使用dlply与unsplit

时间:2014-05-09 20:50:05

标签: r plyr

我想将列附加到具有累积函数结果的数据框。我可以使用unsplit / split完成此操作,就像这样

> set.seed(3)
> d <- data.frame(type=sample(c('a','b'),10,replace=TRUE), val=rnorm(10))
> d
   type         val
1     a  0.03012394
2     b  0.08541773
3     a  1.11661021
4     a -1.21885742
5     b  1.26736872
6     b -0.74478160
7     a -1.13121857
8     a -0.71635849
9     b  0.25265237
10    b  0.15204571

所以我使用split / lapply / unsplit来获得我想要的结果

> d$sum <- unsplit(lapply(split(d,d$type), function(x) { cumsum(x$val)}), d$type)
> d
   type         val         sum
1     a  0.03012394  0.03012394
2     b  0.08541773  0.08541773
3     a  1.11661021  1.14673416
4     a -1.21885742 -0.07212326
5     b  1.26736872  1.35278645
6     b -0.74478160  0.60800486
7     a -1.13121857 -1.20334183
8     a -0.71635849 -1.91970032
9     b  0.25265237  0.86065723
10    b  0.15204571  1.01270293

这是理想的结果。但在这种情况下,我真的想使用plyr的简化语法。所以我试过

> d$sum2 <- unsplit(dlply(d, .(type), summarise, cumsum(val)), d$type)
Error in `row.names<-.data.frame`(`*tmp*`, value = value) : 
  duplicate 'row.names' are not allowed
In addition: Warning message:
non-unique values when setting 'row.names': '1', '2', '3', '4', '5' 

dlplylapply / split的输出几乎相同,只是dlply有一些额外的垃圾,我认为unsplit会忽略,dlply输出已重新索引row.names。我认为后者就是投诉。

另请注意,我知道我可以使用ddply / transform

来解决此问题
> ddply(d, .(type), transform, sum2=cumsum(val))                                
   type         val         sum        sum2
1     a  0.03012394  0.03012394  0.03012394
2     a  1.11661021  1.14673416  1.14673416
3     a -1.21885742 -0.07212326 -0.07212326
4     a -1.13121857 -1.20334183 -1.20334183
5     a -0.71635849 -1.91970032 -1.91970032
6     b  0.08541773  0.08541773  0.08541773
7     b  1.26736872  1.35278645  1.35278645
8     b -0.74478160  0.60800486  0.60800486
9     b  0.25265237  0.86065723  0.86065723
10    b  0.15204571  1.01270293  1.01270293

这在我的情况下不起作用,因为正如您所看到的,这会产生重新排列行不正常的副作用。如果ddply有一些不会重新排列行的参数,那么这对我的目的来说是完美的。

2 个答案:

答案 0 :(得分:3)

也许您可以试试dplyr?与ddply相反,它保留原始顺序。

library(dplyr)
d %.%
  group_by(type) %.%
  mutate(sum = cumsum(val))
# Source: local data frame [10 x 3]
# Groups: type
# 
#    type         val         sum
# 1     a  0.03012394  0.03012394
# 2     b  0.08541773  0.08541773
# 3     a  1.11661021  1.14673416
# 4     a -1.21885742 -0.07212326
# 5     b  1.26736872  1.35278645
# 6     b -0.74478160  0.60800486
# 7     a -1.13121857 -1.20334183
# 8     a -0.71635849 -1.91970032
# 9     b  0.25265237  0.86065723
# 10    b  0.15204571  1.01270293

答案 1 :(得分:1)

为什么不使用ave

d$sum <-   # absolutely terrible name for a variable
  ave( d$val, d$type, FUN=cumsum) 

lapply( split(d, d$type) , func) - 方法对于一次只对一个向量进行操作的函数来说是过度的。