如何在data.table中无需apply生成行向量并添加行标准差列
这俩都是data.table里很常见的行级操作需求,我给你整理了不用apply的高效解法:
1. 不使用apply,从data.table行生成向量
有两种符合data.table向量化风格的方法,完全不用apply这类循环型函数:
- 方法一:用
transpose()生成每行向量的列表transpose()是data.table内置的高效函数,它会把原表的列转成列表,每个列表元素就是原表对应的一行向量。示例代码:
library(data.table) DT <- data.table(a = 1:4, b = c(5,7,9,11), c = c(13,16,19,22), d = c(25,29,33,37)) # 生成所有行的向量列表 row_vec_list <- transpose(DT) # 提取第1行的向量 row1_vector <- row_vec_list[[1]] # 结果为 c(1, 5, 13, 25)
- 方法二:在data.table内新增列存储每行向量
如果需要把每行向量作为新列保留在表中,可以结合.SD和逐行分组处理:
DT[, row_vector := .(transpose(.SD)), by = seq_len(nrow(DT))]
这里by = seq_len(nrow(DT))让我们按每行单独分组,transpose(.SD)把当前行的所有列转成向量,再用.()包裹成列表存入新列,全程没有用到apply。
2. 新增列存储指定三列的行标准差
同样可以用向量化方法或者手动计算,完全避开apply:
方法一:用matrixStats包的rowSds()(推荐,高效)
matrixStats包的rowSds()是专门计算矩阵每行标准差的向量化函数,和data.table适配性极好:
library(data.table) library(matrixStats) # 初始化你的data.table DT <- data.table(a = 1:4, b = c(5,7,9,11), c = c(13,16,19,22), d = c(25,29,33,37)) # 新增abdSD列,计算a、b、d三列的行标准差 DT[, abdSD := rowSds(as.matrix(.SD)), .SDcols = c("a", "b", "d")]
运行后得到的结果和你期望的一致:
a b c d abdSD 1: 1 5 13 25 12.8609 2: 2 7 16 29 14.1845 3: 3 9 19 33 15.4919 4: 4 11 22 37 16.8018
.SDcols用来指定我们要处理的三列,as.matrix(.SD)将这三列转换为矩阵,rowSds()就能快速完成每行的标准差计算。
方法二:不依赖额外包,手动计算
如果不想安装额外包,可以利用data.table的逐行分组,手动实现标准差公式:
DT[, abdSD := { # 取出当前行的a、b、d值 vals <- c(a, b, d) # 计算均值 val_mean <- mean(vals) # 计算标准差 sqrt(mean((vals - val_mean)^2)) }, by = seq_len(nrow(DT))]
这里by = seq_len(nrow(DT))确保我们对每行单独处理,内部的计算都是针对当前行的三个数值,完全没有用到apply函数。
内容的提问来源于stack exchange,提问作者Dan Rosenheck
相关产品推荐
相关产品推荐

