R &引用;“循环通过”;用于计算条件平均值的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

我想“循环”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), 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
    是可以的,可能更有效。