R &引用;“循环通过”;用于计算条件平均值的data.table
我想“循环”data.table的行,并计算每行的平均值。应根据以下机制计算平均值:R &引用;“循环通过”;用于计算条件平均值的data.table,r,data.table,R,Data.table,我想“循环”data.table的行,并计算每行的平均值。应根据以下机制计算平均值: 在第一行(ID(i))中查找标识符ID 在第一行(T2(i))中查找T2的值 计算所有行j中Data1值的平均值,这些值满足以下两个标准:ID(j)=ID(i)和T1(j)=T2(i) 在第一行的Data2列中输入计算的平均值 DF = data.frame(ID=rep(c("a","b"),each=6), T1=rep(1:2,each=3), T2=c(1,2,3), Da
j
中Data1
值的平均值,这些值满足以下两个标准:ID(j)=ID(i)
和T1(j)=T2(i)
DF = data.frame(ID=rep(c("a","b"),each=6),
T1=rep(1:2,each=3), T2=c(1,2,3), Data1=c(1:12))
DT = data.table(DF)
DT[ , Data2:=NA_real_]
ID T1 T2 Data1 Data2
[1,] a 1 1 1 NA
[2,] a 1 2 2 NA
[3,] a 1 3 3 NA
[4,] a 2 1 4 NA
[5,] a 2 2 5 NA
[6,] a 2 3 6 NA
[7,] b 1 1 7 NA
[8,] b 1 2 8 NA
[9,] b 1 3 9 NA
[10,] b 2 1 10 NA
[11,] b 2 2 11 NA
[12,] b 2 3 12 NA
ID T1 T2 Data1 Data2
[1,] a 1 1 1 2
[2,] a 1 2 2 5
[3,] a 1 3 3 NA
[4,] a 2 1 4 2
[5,] a 2 2 5 5
[6,] a 2 3 6 NA
[7,] b 1 1 7 8
[8,] b 1 2 8 11
[9,] b 1 3 9 NA
[10,] b 2 1 10 8
[11,] b 2 2 11 11
[12,] b 2 3 12 NA
我认为这样做的一种方法是通过行循环,但我认为这是低效的。我已经看过
apply()
函数,但我确信它是否能解决我的问题。我也可以使用data.frame
而不是data.table
,如果这能使它更高效或更简单的话。真正的数据集包含大约100万行。迭代行的另一种更快的方法是采用矢量化的解决方案
R> d <- data.frame(ID=rep(c("a","b"),each=6), T1=rep(1:2,each=3), T2=c(1,2,3), Data1=c(1:12))
R> d
ID T1 T2 Data1
1 a 1 1 1
2 a 1 2 2
3 a 1 3 3
4 a 2 1 4
5 a 2 2 5
6 a 2 3 6
7 b 1 1 7
8 b 1 2 8
9 b 1 3 9
10 b 2 1 10
11 b 2 2 11
12 b 2 3 12
R> rowfunction <- function(i) with(d, mean(Data1[which(T1==T2[i] & ID==ID[i])]))
R> d$Data2 <- sapply(1:nrow(d), rowfunction)
R> d
ID T1 T2 Data1 Data2
1 a 1 1 1 2
2 a 1 2 2 5
3 a 1 3 3 NaN
4 a 2 1 4 2
5 a 2 2 5 5
6 a 2 3 6 NaN
7 b 1 1 7 8
8 b 1 2 8 11
9 b 1 3 9 NaN
10 b 2 1 10 8
11 b 2 2 11 11
12 b 2 3 12 NaN
R>d
ID T1 T2数据1
一一
2 a 12 2
3 a 1 3 3
4 a 2 1 4
5 a 2 5
6 a 2 3 6
7b117
8b128
9b139
10B2110
11B211
12 b 2 3 12
R> rowd函数$data2d
ID T1 T2数据1数据2
1A 11 2
2 a 1 2 5
3a13nan
4 a 2 1 4 2
5 a 2 5 5
6A236NAN
7b1178
8b12811
9B139NAN
10B21108
11B21111
12 b 2 3 12南
此外,我更愿意在将数据放入R之前对其进行预处理。也就是说,如果您从SQL server检索数据,让服务器计算平均值可能是更好的选择,因为它很可能在这方面做得更好
R实际上并不擅长数字运算,原因有几个。但在对已经预处理的数据进行统计时,它非常出色。使用tapply和最近的另一篇文章:
DF = data.frame(ID=rep(c("a","b"),each=6), T1=rep(1:2,each=3), T2=c(1,2,3), Data1=c(1:12))
编辑:事实上,大多数原始功能是多余的,并打算用于其他用途。在此,简化:
ansMat <- tapply(DF$Data1, DF[, c("ID", "T1")], mean)
i <- cbind(match(DF$ID, rownames(ansMat)), match(DF$T2, colnames(ansMat)))
DF<-cbind(DF,Data2 = ansMat[i])
# ansMat<-tapply(seq_len(nrow(DF)), DF[, c("ID", "T1")], function(x) {
# curSub <- DF[x, ]
# myIndex <- which(DF$T2 == curSub$T1 & DF$ID == curSub$ID)
# meanData1 <- mean(curSub$Data1)
# return(meanData1 = meanData1)
# })
ansMat经验法则是先聚合,然后加入
agg = DT[,mean(Data1),by=list(ID,T1)]
setkey(agg,ID,T1)
DT[,Data2:={JT=J(ID,T2);agg[JT,V1][[3]]}]
ID T1 T2 Data1 Data2
[1,] a 1 1 1 2
[2,] a 1 2 2 5
[3,] a 1 3 3 NA
[4,] a 2 1 4 2
[5,] a 2 2 5 5
[6,] a 2 3 6 NA
[7,] b 1 1 7 8
[8,] b 1 2 8 11
[9,] b 1 3 9 NA
[10,] b 2 1 10 8
[11,] b 2 2 11 11
[12,] b 2 3 12 NA
正如你所看到的,在这种情况下有点难看(但会很快)。计划添加drop
,这将避免[[3]]
位,也许我们可以提供一种方法来告诉[.data.table
以评估调用范围中的i
(即无自连接)这将避免此处所需的JT=
位,因为ID
同时位于agg
和DT
中
keyby
已添加到R-Forge上的v1.8.0中,因此也无需使用setkey
。您编写的规范似乎难以操作,但您的示例表明,在每个ID组中,您需要一些值组的平均值,其中T2在T1的值范围内。但即使如此,也可以解释为当试图找出为什么第二行中的数据2应该是5时,on会崩溃。这是因为平均值是在Data1
列上进行的。Data2[2]
等于5,因为5是的平均值(4,5,6)
。谢谢你,Matthew。这速度太快了。在创建agg
中的V1
列时,是否有可能给它一个自定义名称,以避免对列名的混淆?请尝试DT[,list(myname=mean(Data1)),by=list(ID,T1)]
。关于本例的进一步加速,请参见第3点。我将第三行替换为DT[,Data2:={agg[J(ID,T2)][[3]]}]
,并得到了相同的结果。也就是说,我确实避免了JT=
位(以及,V1
).这些都是我的错误做法吗?@Josh Hi.我试过那一行,但结果似乎不一样。J()
中的ID
来自agg
,循环使用以匹配T2
的长度(来自DT
,因为T2
不在agg
)因此它混合了a
和b
。但是在这种情况下,避免V1
是可以的,可能更有效。