假设我想在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))
DT
a b c d
1: 1 5 13 25
2: 2 7 16 29
3: 3 9 19 33
4: 4 11 22 37
我想添加一个包含每行a,b和d标准差的列,如下所示:
a b c d abdSD
1: 1 5 13 23 12.86
2: 2 7 16 27 14.36
3: 3 9 19 31 15.87
4: 4 11 22 35 17.39
我当然可以写一个for循环或使用apply函数来计算它。不幸的是,我真正想做的事情需要应用于数百万行,不像计算标准偏差那么简单,需要在几分之一秒内完成,所以我真的需要一个矢量化解决方案。我想写点像
DT[, abdSD := sd(c(a, b, d))]
但不幸的是,这没有给出正确的答案。是否有任何data.table语法可以在同一行中创建不同值的向量,并使该向量可以访问填充该行中新单元格的函数?任何帮助将不胜感激。 @Arun
答案 0 :(得分:2)
根据数据的大小,您可能希望将数据转换为长格式,然后按如下方式计算结果:
complexFunc <- function(x) sd(x)
cols <- c("a", "b", "d")
rowres <- melt(DT[, rn:=.I], id.vars="rn", variable.factor=FALSE)[,
list(abdRes=complexFunc(value[variable %chin% cols])), by=.(rn)]
DT[rowres, on=.(rn)]
或者如果您的复杂函数有3个参数,您可以执行类似
的操作DT[, abdSD := mapply(complexFunc, a, b, d)]
答案 1 :(得分:1)
正如@Frank所提到的,我可以通过执行by=1:nrow(DT)
DT[, abdSD:=sd(c(a,b,d)),by=1:nrow(DT)]
输出:
a b c d abdSD
1: 1 5 13 25 12.85820
2: 2 7 16 29 14.36431
3: 3 9 19 33 15.87451
4: 4 11 22 37 17.38774
如果你添加一个row_name列,那将非常容易
DT$row_id<-row.names(DT)
只需= row_id,就可以得到你想要的结果
DT[, abdSD:=sd(c(a,b,d)),by=row_id]
结果会有:
a b c d row_id abdSD
1: 1 5 13 25 1 12.85820
2: 2 7 16 29 2 14.36431
3: 3 9 19 33 3 15.87451
4: 4 11 22 37 4 17.38774
如果您想删除row_id,只需添加[,row_id:=NULL]
DT[, abdSD:=sd(c(a,b,d)),by=row_id][,row_id:=NULL]
此行将获得您想要的一切
a b c d abdSD
1: 1 5 13 25 12.85820
2: 2 7 16 29 14.36431
3: 3 9 19 33 15.87451
4: 4 11 22 37 17.38774
你必须按行进行。
data.frame在默认情况下按行执行,data.table在默认情况下按列执行。这有点棘手
希望这有帮助
答案 2 :(得分:0)
我认为你应该试试matrixStats
包
library(matrixStats)
#sample data
dt <- data.table(a = 1:4, b = c(5, 7, 9, 11), c = c(13, 16, 19, 22), d = c(25, 29, 33, 37))
dt[, `:=`(abdSD = rowSds(as.matrix(.SD), na.rm=T)), .SDcols=c('a','b','d')]
dt
输出为:
a b c d abdSD
1: 1 5 13 25 12.85820
2: 2 7 16 29 14.36431
3: 3 9 19 33 15.87451
4: 4 11 22 37 17.38774
答案 3 :(得分:0)
不是答案,只是试图展示使用apply
与上面提供的解决方案之间的区别:
我已将样本数据炸成40,000行以显示稳定的时差:
library(matrixStats)
#sample data
dt <- data.table(a = 1:40000, b = rep(c(5, 7, 9, 11),10000), c = rep(c(13, 16, 19, 22),10000), d = rep(c(25, 29, 33, 37),10000))
df <- data.frame(a = 1:40000, b = rep(c(5, 7, 9, 11),10000), c = rep(c(13, 16, 19, 22),10000), d = rep(c(25, 29, 33, 37),10000))
t0 = Sys.time()
dt[, `:=`(abdSD = rowSds(as.matrix(.SD), na.rm=T)), .SDcols=c('a','b','d')]
print(paste("Time taken for data table operation = ",Sys.time() - t0))
# [1] "Time taken for data table operation = 0.117115020751953"
t0 = Sys.time()
df$abdSD <- apply(df[,c("a","b","d")],1, function(x){sd(x)})
print(paste("Time taken for apply opertaion = ",Sys.time() - t0))
# [1] "Time taken for apply opertaion = 2.93488311767578"
使用DT
和matrixStats
明显赢得比赛
答案 4 :(得分:0)
对于这种情况,sd
不易渲染:
vecSD = function(x) {
n = ncol(x)
sqrt((n/(n-1)) * (Reduce(`+`, x*x)/n - (Reduce(`+`, x)/n)^2))
}
DT[, vecSD(.SD), .SDcols = c('a', 'b', 'd')]
#[1] 12.85820 14.36431 15.87451 17.38774