【问题标题】:Looping over numbered variables within a by= call of a data table in R在 R 中的数据表的 by= 调用中循环编号变量
【发布时间】:2014-05-20 21:38:15
【问题描述】:

这很可能很愚蠢,但我找不到以下问题的(非详尽的)解决方法:

让我们设置:

data<-data.table(id=c("a","a","a","b","b"),
                 x1=1:5,
                 x2=6:10,
                 x3=11:15)

例如,我想要根据“id”分组的每个列变量的平均值,然后将它们作为变量附加到数据集。这么少,当然,我们可以使用语法:

means1<-data[,mean(x1),by=id]

同样对于 x2, x3, 得到:

   id x1 x2 x3  V1 V1.1 V1.2
1:  a  1  6 11 2.0  7.0 12.0
2:  a  2  7 12 2.0  7.0 12.0
3:  a  3  8 13 2.0  7.0 12.0
4:  b  4  9 14 4.5  9.5 14.5
5:  b  5 10 15 4.5  9.5 14.5

但是,对于更大的集合,我们很想循环。这是我首先尝试的:

for(nn in 1:3){
   data<-data[data[,mean(paste("x",nn,sep="")),by=id]]
}

但这失败了,我猜是因为即使通常允许字符串标识列名,mean 函数也会尝试在外部运算符之前进行操作:

Warning messages:
1: In `[.data.table`(data, , mean(paste("x", nn, sep = "")), by = id) :
  argument is not numeric or logical: returning NA

所以,下一次尝试:

for(nn in 1:3){
   data<-data[data[,mean(data[[paste("x",nn,sep="")]]),by=id]]
}

但是,这也失败了,同样因为均值先运行。 (更不用说语法对于任何习惯在 STATA 中做类似事情的人来说都是令人畏惧的)所以我们最终得到每个 x 的整体平均值被分配给每个 id 值:

   id x1 x2 x3 V1 V1.1 V1.2
1:  a  1  6 11  3    8   13
2:  a  2  7 12  3    8   13
3:  a  3  8 13  3    8   13
4:  b  4  9 14  3    8   13
5:  b  5 10 15  3    8   13

那么,我们如何循环执行这个简单的任务呢?

这样的语法在类似的调用中对我有用,例如:

for(nn in 1:3){
   data[,paste("x_greater_than_4_",nn,sep=""):=(data[[paste("x",nn,sep="")]]>4)]
}

产生我所期望的:

   id x1 x2 x3 x_greater_than_4_1 x_greater_than_4_2 x_greater_than_4_3
1:  a  1  6 11              FALSE               TRUE               TRUE
2:  a  2  7 12              FALSE               TRUE               TRUE
3:  a  3  8 13              FALSE               TRUE               TRUE
4:  b  4  9 14              FALSE               TRUE               TRUE
5:  b  5 10 15               TRUE               TRUE               TRUE

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    我首先使用setkey 设置一个键,然后在j 表达式中使用lapply 并自加入结果。您可以在lapply 和关联的.SDcols 中使用.SD 按数字位置指定列。像这样:

    setkey( data , id )
    data[ data[ , lapply( .SD , mean ) , keyby = id , .SDcols = 2:4 ] ]
    #   id x1 x2 x3 x1.1 x2.1 x3.1
    #1:  a  1  6 11  2.0  7.0 12.0
    #2:  a  2  7 12  2.0  7.0 12.0
    #3:  a  3  8 13  2.0  7.0 12.0
    #4:  b  4  9 14  4.5  9.5 14.5
    #5:  b  5 10 15  4.5  9.5 14.5
    
    # If you just want the group means use this:
    data[ ,  lapply( .SD , mean ), by = id , .SDcols = 2:4 ]
    

    或者,您可以将:=by 一起使用,如下所示,这也将避免加入:

    sd_cols = c("x1", "x2", "x3")
    data[, c(paste0("v", 1:3)) := lapply(.SD, mean), by=id, .SDcols=sd_cols]
    
    #    id x1 x2 x3  v1  v2   v3
    # 1:  a  1  6 11 2.0 7.0 12.0
    # 2:  a  2  7 12 2.0 7.0 12.0
    # 3:  a  3  8 13 2.0 7.0 12.0
    # 4:  b  4  9 14 4.5 9.5 14.5
    # 5:  b  5 10 15 4.5 9.5 14.5
    

    【讨论】:

    • 你能编辑这个以包含一个循环吗?我会按照这些思路做一些事情(鉴于这已应用了 30 多次,并且担心变量所在的列号没有意义): x
    • 或者甚至更好(假设我在循环中做了其他事情): for(i in 1:3){ x
    【解决方案2】:

    尝试用aggregate配合公式接口得到分组均值,然后merge变成原始数据:

    merge(data,aggregate(.~id,data=data,mean),by="id",suffixes=c("",".mean"))
       id x1 x2 x3 x1.mean x2.mean x3.mean
    1:  a  1  6 11     2.0     7.0    12.0
    2:  a  2  7 12     2.0     7.0    12.0
    3:  a  3  8 13     2.0     7.0    12.0
    4:  b  4  9 14     4.5     9.5    14.5
    5:  b  5 10 15     4.5     9.5    14.5
    

    【讨论】:

      【解决方案3】:

      怎么样:

      > data[, x1Mean := mean(x1), by=id] # this command updates the data table
      > data
         id x1 x2 x3 x1Mean
      1:  a  1  6 11    2.0
      2:  a  2  7 12    2.0
      3:  a  3  8 13    2.0
      4:  b  4  9 14    4.5
      5:  b  5 10 15    4.5
      

      【讨论】:

      • 你是对的。如果您想为多个列执行此操作,请查看 Simon's answer 下的第二个解决方案。
      • @Arun 实际上我想为多个列执行“data[, J = list(x1Mean := mean(x1),x2Mean := mean(x2)),By = id]”,但是这行不通。
      • 图森,要么:DT[ c("a", "b", "c") := list(mean(x1), mean(x2), mean(x3)), by=.] 要么 DT[, `:=`(a=mean(x1), b=mean(x2), c=mean(x3)), by=.](除了上面的 lapply 方法)。在data.table 标签下搜索 SO 应该会得到一些不错的答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-26
      • 2015-11-10
      • 2020-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多