我想使用data.table
为大型数据集实现一个非常简单的任务。
计算每个ID的val1和val2的平均值。
有关详细信息,请参阅附带的假数据。
library(data.table)
DT <- data.table(ID = paste0("ID",rep(1:5,each=2)),
level= rep(c("CTRL","CTRL","ID1","ID2","ID3"),2),
val1 = 1:10,
val2 = rnorm(10))
这里我想计算每个ID,val1和val2的平均值。
另请注意,在每个ID中,都有不同的级别。但是对于每个唯一ID,我只想要一个包含不同级别val1和val2的意思。
--- ID |意思是---
- ID1 | ...
- ID2 | ...
- ID3 | ......
我尝试了以下代码,但它不起作用。
topagents <- DT[, mean = mean(list(val1,val2)),
by = ID]
但它不起作用。
我知道如何在reshape2
中执行此操作,首先是melt
,然后是dcast
。
但是原始数据集相对较大,有20M行和12个字段,进行计算需要相当长的时间。
所以我更喜欢使用data.table
或dplyr
。
答案 0 :(得分:7)
将对mean
的调用封装在列表中,而不是采用列表的平均值,这是您无法做到的:
DT[, j=list(val1=mean(val1), val2=mean(val2)), by=ID]
ID val1 val2
1: ID1 1.5 0.1389794
2: ID2 3.5 0.3392179
3: ID3 5.5 -0.6336174
4: ID4 7.5 0.9941148
5: ID5 9.5 0.1324782
要获得单个值,val1
和val2
值的平均值,请合并这些值并传递给mean
:
DT[, j=list(mean=mean(c(val1,val2))), by=ID]
ID mean
1: ID1 0.8194897
2: ID2 1.9196090
3: ID3 2.4331913
4: ID4 4.2470574
5: ID5 4.8162391
在此处使用j
的单个元素的列表是一种命名结果列的简单方法。
答案 1 :(得分:5)
topagents <- DT[, mean(c(val1,val2)), by = ID]
意思是只能拿一个矢量,它不理解列表。
您的问题是“计算每个ID的val1和val2的平均值。”但根据Mathew的回答,你可能想要“为每个ID计算val1和val2的平均值(复数)。”?
答案 2 :(得分:5)
您提到您的数据维度是包含12列的2000万行,但未提及“ID”的唯一值的数量。我将在这里假设为20,000。
如果你正在寻找你的解决方案:1)快速和2)记忆效率,那么马修(或杰里米)解决方案拼出所有变量都会表现得更好 - 这就是,直到unlist(.SD)
被优化。基本上最好的是@ codoremifa的语法和@Matthew的表现。
setkey
data.table
(如此巨大的维度)之前可以获得的表现收益(聚合之前)(其方面尚未涵盖写作时的答案)。 setkey
,因为join
或fast subset
(基于二进制搜索)是必需的。但是对于像你这样的数据维度(可以说是安全的BIG数据),你可以通过设置密钥来获得A LOT。这是因为,setkey
按键列对数据进行排序,这使得以后聚合的列位于连续的内存位置,因此非常有效。
v1.8.11中有很多增强功能(当前的开发版本,其中setkey
也已经很多更快)。因此,此处显示的基准将随current stable version 1.8.10 on CRAN而变化。如果您没有使用开发版本,那也没关系。希望这会让您相信setkey
的有用性,并为您提供有关下一版本期待的内容的一些内容。
好的,关于尺寸数据的说明:
require(data.table)
set.seed(1L)
uval <- 2e4 # unique values in ID
N <- 20e6
DT <- data.table(ID=sample(uval, N, TRUE)) # for simplicity ID is integer
cols <- paste("V", 1:11, sep="")
set(DT, i=NULL, j=cols, value=as.list(1:11))
dim(DT) # 20e6 by 12
system.time(ans1 <- DT[,
list(val=mean(c(V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11))),
by=ID])
# user system elapsed
# 45.587 0.632 46.251
system.time(setkey(DT, ID)) # (note that this'll be much faster on 1.8.11)
# user system elapsed
# 5.872 0.072 5.948
system.time(ans2 <- DT[,
list(val=mean(c(V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11))),
by=ID])
# user system elapsed
# 2.164 0.236 2.400
setkey(ans1, ID)
identical(ans1, ans2) # [1] TRUE
你可以看到,通过设置键,你需要大约8.4秒,而没有它的那个&gt; 40秒这是很多加速。
答案 3 :(得分:3)
如果我理解正确,你有十二个字段,并希望将硬编码保持在最低限度。我不太确定您的预期输出是什么,但希望它是以下两个结果中的一个 -
colstomean <- setdiff(colnames(DT),c('ID','level'))
选项1,该ID中每个变量值的平均值
DT[, lapply(.SD, mean, na.rm=TRUE),
by=ID,
.SDcols = colstomean
]
输出 -
ID val1 val2
1: ID1 1.5 0.37648090
2: ID2 3.5 -0.55484848
3: ID3 5.5 -0.07326365
4: ID4 7.5 -0.37705525
5: ID5 9.5 -0.08075406
选项2,该ID中所有变量值的平均值
DT[, mean(unlist(.SD), na.rm = TRUE),
by=ID,
.SDcols = colstomean
]
输出
ID V1
1: ID1 0.9382404
2: ID2 1.4725758
3: ID3 2.7133682
4: ID4 3.5614724
5: ID5 4.7096230