如何对xts对象逐行使用vapply计算均值?哪种apply函数最优?
我有如下xts对象:
x <- structure(c(30440.5, 30441, 30441.5, 30441.5, 30441, 30439.5, 30440.5, 30441, 30441.5, NA, NA, 30439.5, NA, NA, NA, 30441.5, 30441, NA), .indexTZ = "", class = c("xts", "zoo"), .indexCLASS = c("POSIXct", "POSIXt"), tclass = c("POSIXct", "POSIXt"), tzone = "", index = structure(c(1519866931.1185, 1519866931.1255, 1519866931.1255, 1519866931.1905, 1519866931.1905, 1519866931.1915), tzone = "", tclass = c("POSIXct", "POSIXt")), .indexFormat = "%Y-%m-%d %H:%M:%OS", .Dim = c(6L, 3L), .Dimnames = list(NULL, c("x", "y", "z")))
打印后样式如下:
# x y z # 2018-03-01 09:15:31.118 30440.5 30440.5 NA # 2018-03-01 09:15:31.125 30441.0 30441.0 NA # 2018-03-01 09:15:31.125 30441.5 30441.5 NA # 2018-03-01 09:15:31.190 30441.5 NA 30441.5 # 2018-03-01 09:15:31.190 30441.0 NA 30441.0 # 2018-03-01 09:15:31.191 30439.5 30439.5 NA
我想编写vapply代码,用mean(..., na.rm = TRUE)计算每行均值,得到如下单列结果:
w 2018-03-01 09:15:31.118 30440.5 2018-03-01 09:15:31.125 30441.0 2018-03-01 09:15:31.125 30441.5 2018-03-01 09:15:31.190 30441.5 2018-03-01 09:15:31.190 30441.0 2018-03-01 09:15:31.191 30439.5
我尝试多次仍无法实现。此外,很多回答建议我不要使用vapply,改用其他函数,但有资料显示vapply是最快的,请问此处哪种apply函数最优?
一、用vapply实现每行均值计算
要实现这个需求,核心是抓住xts对象本质是带时间索引的矩阵这一点,我们可以逐行遍历计算均值,最后把结果包装回xts对象保留索引:
# 用vapply遍历每行,计算均值并指定返回类型为数值型 row_means <- vapply(seq_len(nrow(x)), function(i) { mean(x[i, ], na.rm = TRUE) }, FUN.VALUE = numeric(1)) # 将计算结果转换为xts对象,保留原时间索引 w <- xts(row_means, index(x)) colnames(w) <- "w"
这段代码的关键点:
seq_len(nrow(x))生成每行的位置索引,供vapply逐个处理FUN.VALUE = numeric(1)明确指定返回值类型,这也是vapply比sapply更高效的核心原因- 最后用原
x的时间索引重新构建xts对象,确保时间信息不丢失
二、关于最优apply函数的讨论
你说的没错,vapply因为提前指定了返回类型,避免了sapply的动态类型检查,性能确实会更优,但针对这个场景,还有更合适的选择:
rowMeans函数(绝对最优选择)
这是R专门为矩阵/数据框设计的行均值计算函数,底层用C实现,速度远快于任何apply系列函数。针对你的xts对象,一行代码就能搞定:w <- xts(rowMeans(x, na.rm = TRUE), index(x)) colnames(w) <- "w"代码简洁,性能拉满,完全没必要用apply系列函数绕弯。
apply函数
如果一定要用apply系列,apply(x, 1, mean, na.rm = TRUE)也能实现,但它返回的是普通向量,需要再转成xts,而且性能不如vapply和rowMeans。vapplyvssapply
正如你了解的,vapply确实比sapply快,但在这个场景下,rowMeans的性能还是碾压vapply——毕竟是专门做行均值优化的底层函数。
总结:如果追求极致性能和简洁代码,rowMeans是毫无争议的最优选择;如果一定要用apply系列,vapply确实是其中最快的,但没必要舍近求远用它替代专用函数。
内容的提问来源于stack exchange,提问作者mynameisJEFF

