2011-05-29 21 views
1

R中的常見用例(至少對我而言)是在數據框中標識具有某些取決於某些子集中的值的特徵的觀察值的其他觀察。R中針對「自然」過程問題的有效函數編程(使用mapply)

爲了使這更沈志南,假設我有一批工人(由WorkerId索引)是 具有相應的「迭代」:

raw <- data.frame(WorkerId=c(1,1,1,1,2,2,2,2,3,3,3,3), 
       Iteration = c(1,2,3,4,1,2,3,4,1,2,3,4)) 

,我想最終子集的數據幀排除「最後」迭代(通過爲每個工作者創建一個「刪除」布爾值)。我可以寫一個函數來做到這一點:

raw$remove <- mapply(function(wid,iter){ 
           iter==max(raw$Iteration[raw$WorkerId==wid])}, 
       raw$WorkerId, raw$Iteration) 

> raw$remove 
    [1] FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE FALSE FALSE FALSE TRUE 

但得到的數據幀變大很慢(大概是因爲我不必要計算最大爲每個觀察)。

我的問題是在函數式編程風格中做到這一點的更高效(和慣用)的方式是什麼。它是首先創建一個WorkerId到最大值字典,然後將其用作另一個對每個觀察操作的函數的參數?

+0

你的例子是由另一個R-覆蓋問題:[爲指定字段提取具有MAX值的數據幀行的索引](http://stackoverflow.com/q/60 168747分之25051)。 – Marek 2011-05-29 23:08:36

回答

3

「最自然的方式」國際海事組織是分裂lapply-rbind方法。你首先將split()分成一組列表,然後lapply()處理規則(在這種情況下刪除最後一行),然後將它們重新綁定到一起。這一切都可以作爲嵌套函數調用進行操作。內部的兩個步驟都在這裏示出並最終一行程序呈現在底部:

> lapply(split(raw, raw$WorkerId), function(x) x[-NROW(x),]) 
$`1` 
    WorkerId Iteration 
1  1   1 
2  1   2 
3  1   3 

$`2` 
    WorkerId Iteration 
5  2   1 
6  2   2 
7  2   3 

$`3` 
    WorkerId Iteration 
9   3   1 
10  3   2 
11  3   3 

do.call(rbind, lapply(split(raw, raw$WorkerId), function(x) x[-NROW(x),])) 

哈德利韋翰已經開發了廣泛的工具集,所述plyr包,即擴展這一策略,以更廣泛的各種任務的。

+1

更好地分割索引和子集? 'splt < - split(seq_len(nrow(raw)),raw $ WorkerId); idx < - unlist(lapply(splt,function(x)x [-length(x)]),use.names = FALSE);原始[idx,]' – 2011-05-29 13:31:16

+0

馬丁,當你這麼說的時候,我不是一個可以爭論的人。我假設你認爲這是提高效率的原因,因爲它不適用於完整的數據框? – 2011-05-29 13:47:40

+0

是的,只需處理所需的數據。數據幀上的「split」和「rbind」相對於矢量和子集上的「split」而言將是昂貴的。我喜歡你的答案如何說明一種有用的模式。 – 2011-05-29 13:53:55

2

這種情況是爲使用plyr包而量身定製的。

ddply(raw, .(WorkerId), function(df) df[-NROW(df),]) 

它產生的輸出

WorkerId Iteration 
1  1   1 
2  1   2 
3  1   3 
4  2   1 
5  2   2 
6  2   3 
7  3   1 
8  3   2 
9  3   3 
3

對於特定問題所造成!rev(duplicated(rev(raw$WorkerId)))或更好,以下查爾斯的建議,!duplicated(raw$WorkerId, fromLast=TRUE)

+0

另請參閱'fromLast'參數以避免兩次顛倒。 – Charles 2011-05-30 14:49:31

+0

輝煌。我偷了它[更新我的答案](http://stackoverflow.com/questions/6025051/extracting-indices-for-data-frame-rows-that-have-max-value-for-named-field/ 6037559#6037559)。 – Marek 2011-05-31 08:22:18

1
remove <- with(raw, as.logical(ave(Iteration, WorkerId, FUN=function(x) c(rep(TRUE, length(x)-1), FALSE))))) 
2
subset(raw, Iteration != ave(Iteration, WorkerId, FUN=max))