我有两个用于显示数字的函数:
comprss <- function(x) {
div <- findInterval(abs(x),
c(0, 1e3, 1e6, 1e9, 1e12) ) # buckets of thousands
digits <- 2
if (!is.null(x) && !is.na(x) && abs(x)<1) {
x[abs(x) < 1e-07] <- 0 #very low values at 0 for display purposes
x <- signif(x, digits)
} else {
paste0(signif(x/10^(3*(div-1)), 3),
c("","k","M","B","T")[div],sep="")
}
}
和
reformat <- function(x, digits) {
abs_x <- abs(x)
x <- ifelse(abs_x < 0.0000001, 0, x) # Very low values set to 0 for display purposes
x <- ifelse(abs_x >= 10^digits,
stringr::str_extract(as.character(formattable::comma(x)), "^[^\\.]+"),
signif(x, digits))
return(x)
}
comprss
用于重写带有压缩后缀的数字(k 代表千,M 代表百万...)
reformat
用于用适当的逗号书写数字。
我有三个相同长度的向量
x
,unit
和digits
:
x <- c(1, 12, 871, 1873, 87128, 0.125, 1.1652, 321.276, 17627.17012, 1, 12, 871, 1873, 87128, 0.125, 1.1652, 321.276, 17627.17012, 1, 12, 871, 1873, 87128, 0.125, 1.1652, 321.276, 17627.17012)
unit <- c("€", "€", "€", "€", "€", "€", "€", "€", "€", "%", "%", "%", "%", "%", "%", "%", "%", "%", "pts", "pts", "pts", "pts", "pts", "pts", "pts", "pts", "pts")
digits <- c(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3)
我想将
comprss
应用于单位为 x
中的 not 的 c("pts","%")
的值,并重新格式化为单位为 x
中的 c("pts","%")
的值。
我的问题是这两个函数都接受
"numerical"
对象作为参数,并返回 "character"
对象。如果我将一个函数应用于某些值,它会将向量转换为字符向量,因此我无法应用另一个函数。
我创建了这个中间函数来解决我的问题:
custom_function <- function(x, unit, digits) {
if (!(unit %in% c("%","pts"))) {
x <- comprss(x)
} else {
x <- reformat(x,digits)
}
}
x <- mapply(custom_function, x, unit, digits)
它确实有效,但我重复这个操作很多次并且对巨大的数据向量,并且
mapply
非常慢。
我怎样才能以更优化的方式做到这一点?我的意思是使用更少的内存和更少的时间(我需要保持值的顺序)。
我已经问过同一个表的3列的问题,但现在不再是这样了。
您可以预先实例化一个空字符串向量,然后进行简单的索引:
out <- character(length(x)) # empty strings
out[!unit %in% c("pts", "%")] <- sapply(x[!unit %in% c("pts", "%")], comprss)
out[unit %in% c("pts", "%")] <- sapply(x[unit %in% c("pts", "%")], reformat, digits=3)