在R中的数据表的by =调用内循环编号变量

时间:2014-05-09 10:02:24

标签: r data.table

它很可能是愚蠢的,但我找不到以下问题的(非穷举)解决方法:

我们设置:

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]]
}

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

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

3 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:1)

尝试将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

答案 2 :(得分:1)

怎么样:

> 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