2017-04-22 111 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