2011-05-29 24 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))