2017-04-22 97 views
0

我想计算与具有大数据集的几个组合的NA的平均值和计数值。这可能是最容易解释的一些测试数据。我在Macbook Pro上使用最新版本的R,并使用data.table包(数据很大,> 1M行)。 (注意:在发布这个帖子后,我注意到我意外地使用了sum()而不是mean()作为下面的“m =”变量。我没有编辑它,因为我不想重新运行所有的东西, “T认为它很重要,许多)按R计算平均值和多个组合的组合,data.table

set.seed(4) 
YR = data.table(yr=1962:2015) 
ID = data.table(id=10001:11000) 
ID2 = data.table(id2 = 20001:20050) 
DT <- YR[,as.list(ID), by = yr] # intentional cartesian join 
DT <- DT[,as.list(ID2), by = .(yr, id)] # intentional cartesian join 
rm("YR","ID","ID2") 
# 2.7M obs, now add data 
DT[,`:=` (ratio = rep(sample(10),each=27000)+rnorm(nrow(DT)))] 
DT <- DT[round(ratio %% 5) == 0, ratio:=NA] # make some of the ratios NA 
DT[,`:=` (keep = as.integer(rnorm(nrow(DT)) > 0.7)) ] # add in the indicator variable 
# do it again 
DT[,`:=` (ratio2 = rep(sample(10),each=27000)+rnorm(nrow(DT)))] 
DT <- DT[round(ratio2 %% 4) == 0, ratio2:=NA] # make some of the ratios NA 
DT[,`:=` (keep2 = as.integer(rnorm(nrow(DT)) > 0.7)) ] # add in the indicator variable 

所以,我有什么是识别信息(年,ID,ID2),我想总结一下数据:keep1 | 2比1 | 2。特别是通过yr-id,我想使用keep和keep2(因此压缩id2)来计算平均比率和ratio2。我想通过keep/keep2计算比率和ratio2或者通过保持*比率,keep2 *比率,keep * ratio2和keep2 * ratio2的矩阵相乘来进行子集化。

首先,我做这一点,得到正确的答案,但方式是缓慢:

system.time(test1 <- DT[,.SD[keep == 1,.(m = sum(ratio,na.rm = TRUE), 
           nmiss = sum(is.na(ratio))) 
         ],by=.(yr,id)]) 
    user system elapsed 
23.083 0.191 23.319 

该作品一样好于大约在同一时间。我想这可能是快于内.SD子集的主要数据第一,而不是:

system.time(test2 <- DT[keep == 1,.SD[,.(m = sum(ratio,na.rm = TRUE), 
           nmiss = sum(is.na(ratio))) 
         ],by=.(yr,id)]) 
    user system elapsed 
23.723 0.208 23.963 

无论使用哪种方法的问题是,我需要为每个keep变量做单独计算。因此,我想是这样的:

system.time(test3 <- DT[,.SD[,.(m = sum(ratio*keep,na.rm = TRUE), 
           nmiss = sum(is.na(ratio*keep))) 
         ],by=.(yr,id)]) 
    user system elapsed 
25.997 0.191 26.217 

这让我把所有的公式在一起,但1是比较慢和2(我可以在ratio*keep2ratio2*keepratio2*keep2添加)它没有得到正确数量的NAS(见nmiss列):

> summary(test1) 
     yr    id    m    nmiss  
Min. :1962 Min. :10001 Min. : -2.154 Min. :0.000 
1st Qu.:1975 1st Qu.:10251 1st Qu.: 30.925 1st Qu.:0.000 
Median :1988 Median :10500 Median : 53.828 Median :1.000 
Mean :1988 Mean :10500 Mean : 59.653 Mean :1.207 
3rd Qu.:2002 3rd Qu.:10750 3rd Qu.: 85.550 3rd Qu.:2.000 
Max. :2015 Max. :11000 Max. :211.552 Max. :9.000 
> summary(test2) 
     yr    id    m    nmiss  
Min. :1962 Min. :10001 Min. : -2.154 Min. :0.000 
1st Qu.:1975 1st Qu.:10251 1st Qu.: 30.925 1st Qu.:0.000 
Median :1988 Median :10500 Median : 53.828 Median :1.000 
Mean :1988 Mean :10500 Mean : 59.653 Mean :1.207 
3rd Qu.:2002 3rd Qu.:10750 3rd Qu.: 85.550 3rd Qu.:2.000 
Max. :2015 Max. :11000 Max. :211.552 Max. :9.000 
> summary(test3) 
     yr    id    m    nmiss  
Min. :1962 Min. :10001 Min. : -2.154 Min. : 0.00 
1st Qu.:1975 1st Qu.:10251 1st Qu.: 30.925 1st Qu.: 2.00 
Median :1988 Median :10500 Median : 53.828 Median : 4.00 
Mean :1988 Mean :10500 Mean : 59.653 Mean : 4.99 
3rd Qu.:2002 3rd Qu.:10750 3rd Qu.: 85.550 3rd Qu.: 8.00 
Max. :2015 Max. :11000 Max. :211.552 Max. :20.00 

什么是YR-ID让我总结信息的4个组合的最快方法?现在 ,我使用选项1或2重复两次(一次为守,再次keep2)

回答

1

您可以直接j做总结中表达:

# solution A: summarize in `.SD`: 
system.time({ 
    test2 <- DT[keep == 1, 
       .SD[, .(m = sum(ratio, na.rm = TRUE), 
         nmiss = sum(is.na(ratio)))], 
       by = .(yr, id), verbose = T] 
}) 
# user system elapsed 
# 22.359 0.439 22.561 

# solution B: summarize directly in j: 
system.time({ 
    test2 <- DT[keep == 1, .(m = sum(ratio, na.rm = T), 
          nmiss = sum(is.na(ratio))), 
       by = .(yr, id), verbose = T] 
}) 
# user system elapsed 
# 0.118 0.077 0.195 

verbose = T被添加到显示两种方法之间的区别:

为溶液A:

lapply优化是上,J不变” .SD [,列表(M =总和(大鼠IO, na.rm = TRUE),nmiss =总和(is.na(比)))]”苹果牛上,左Ĵ 不变

旧意味着优化上,左Ĵ不变。

使每个组和运行Ĵ(苹果牛FALSE)... j的结果是

命名列表。对于每个组创建相同的名称并且重新创建相同的名称效率非常低。

当j = list(...)时,检测到任何名称, 删除并在分组完成后放回,以提高效率。 例如,使用j = transform()可以防止加速(将 更改为:=)。此消息将来可能会升级为警告。

收集不连续的群体了0.058s为54000组
的eval(J)了22.487s为54000个呼叫 22.521秒

对于解决方案B:

...

从位置查找组大小(可以避免以节省RAM) ... 0秒lapply优化开启,j不变为'list(sum(ratio, na.rm = T),和(is.na(比率)))”

苹果牛上,左Ĵ不变

旧意味着优化上,左Ĵ不变。使每个组与 运行Ĵ(苹果牛FALSE)...收集不连续的群体采取 0.027s为54000组的eval(J)花了0.079s为54000个呼叫 0.168秒

的主要区别在于汇总在B被视为命名列表,这是非常缓慢的时候有很多组(这个数据54k组!)。对于此类型的类似基准,请参阅this one

对于第二部分(您的test3): 我们没有首先通过keep = 1过滤列。所以那些NA s其中keep !=也计入nmiss。因此,NA s的计数是不同的。

+0

辉煌。我仍然在这里了解细节,甚至不知道详细的选项。 –

+0

第二部分:第二种方法(测试3)不起作用(我认为),因为比率*保持即使在保持= 0时也给NA。有没有办法做一些像sum(is.na(ratios [keep] ))与子集比率,然后评估is.na()函数?我宁愿使用第二种方法,因为在真实数据中,我有7个版本的“保留”,因此迭代7次,然后必须重新合并这7个数据集。在步骤中完成这一切会更好。 –

+0

@JesseBlocher,看看为什么'NA'不同的编辑。我还没有想出一种方法来做到这一点比多重保持和比率对的循环更好。 – mt1022