【问题标题】:Sum duplicates then remove all but first occurrence对重复项求和,然后删除除第一次出现之外的所有内容
【发布时间】:2013-02-08 01:00:55
【问题描述】:

我有一个数据框(约 5000 行,6 列),其中包含 id 变量的一些重复值。我有另一个连续变量x,我想为每个重复的id 求和其值。观察是时间相关的,有yearmonth 变量,我想保留每个重复id 的时间顺序第一次观察,并将随后的欺骗添加到第一次观察中。

我已包含类似于我所拥有的虚拟数据:dat1。我还包含了一个数据集,显示了我想要的结果的结构:outcome

我尝试了两种策略,但都不能满足我的需求(见下文)。第一个策略为我提供了 x 的正确值,但我丢失了年份和月份列 - 我需要为所有第一个重复的 id 值保留这些值。第二种策略没有正确总结 x 的值。

任何关于如何获得我想要的结果的建议将不胜感激。

# dummy data set
set.seed(179)
dat1 <- data.frame(id = c(1234, 1321, 4321, 7423, 4321, 8503, 2961, 1234, 8564, 1234),
                   year = rep(c("2006", "2007"), each = 5),
                   month = rep(c("December", "January"), each = 5),
                   x = round(rnorm(10, 10, 3), 2))

# desired outcome
outcome <- data.frame(id = c(1234, 1321, 4321, 7423, 8503, 2961, 8564),
                      year = c(rep("2006", 4), rep("2007", 3)),
                      month = c(rep("December", 4), rep("January", 3)),
                      x = c(36.42, 11.55, 17.31, 5.97, 12.48, 10.22, 11.41))

# strategy 1:
library(plyr)
dat2 <- ddply(dat1, .(id), summarise, x = sum(x))

# strategy 2:
# partition into two data frames - one with unique cases, one with dupes
dat1_unique <- dat1[!duplicated(dat1$id), ]
dat1_dupes <- dat1[duplicated(dat1$id), ]

# merge these data frames while summing the x variable for duplicated ids
# with plyr
dat3 <- ddply(merge(dat1_unique, dat1_dupes, all.x = TRUE),
              .(id), summarise, x = sum(x))
# in base R
dat4 <- aggregate(x ~ id, data = merge(dat1_unique, dat1_dupes,
                  all.x = TRUE), FUN = sum)

【问题讨论】:

    标签: r plyr


    【解决方案1】:

    我得到了不同的金额,但它是 b/c 我忘记了种子:

    > dat1$x <- ave(dat1$x, dat1$id, FUN=sum)
    > dat1[!duplicated(dat1$id), ]
        id year    month     x
    1 1234 2006 December 25.18
    2 1321 2006 December 15.06
    3 4321 2006 December 15.50
    4 7423 2006 December  7.16
    6 8503 2007  January 13.23
    7 2961 2007  January  7.38
    9 8564 2007  January  7.21
    

    (为了更安全,最好在副本上工作。您可能需要添加订购步骤。)

    【讨论】:

    • 哇,太棒了!我没有捏造数学 - 我想你可能没有复制我放在代码顶部的种子编号。当我使用该种子时,我使用您的代码获得了我在 outcome 数据集中给出的值。非常感谢这么整洁的两个班轮!
    • 哎呀。对不起。我可能确实错过了设置的随机种子,因为它是一个很小的 ​​data.frame。
    【解决方案2】:

    您可以使用 data.table 来执行此操作(比 plyr 更快,内存效率更高)

    使用mult ='first' 带来一点自我加入的乐趣。按 id 年和月键入将按 id、年和月排序。

    library(data.table)
    DT <- data.table(dat1, key = c('id','year','month'))
    
    
    # setnames is required as there are two x columns that get renamed x, x.1
    DT1 <- setnames(DT[DT[,list(x=sum(x)),by=id],mult='first'][,x:=NULL],'x.1','x')
    

    或者更简单的方法:

    DT = as.data.table(dat1)
    
    DT[,x:=sum(x),by=id][!duplicated(id)]
    
         id year    month     x
    1: 1234 2006 December 36.42
    2: 1321 2006 December 11.55
    3: 4321 2006 December 17.31
    4: 7423 2006 December  5.97
    5: 8503 2007  January 12.48
    6: 2961 2007  January 10.22
    7: 8564 2007  January 11.41
    

    【讨论】:

    • 非常感谢您的解决方案!上面的data.table 解决方案完美运行,但语法看起来很可怕(对我来说 - 不熟悉data.table)。我注意到您在编辑之前的原始答案中有plyr 解决方案。您的plyr 代码给出了以下错误:Error: length(rows) == 1 is not TRUE。如果您有时间,您介意提供一个有效的plyr 示例吗?我觉得语法对我来说可能更容易理解,data.table 的性能提升对于 5k 行数据来说微不足道(我以后不需要扩展它)。
    • @Chris,我的plyr 解决方案不正确(这就是我删除它的原因)。如果您可以确保数据按年(正确)排序,然后按月排序。那么ddply(dat1, .(id), summarise, x = sum(x),month = month[1],year = year[1]) 就可以了。
    猜你喜欢
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 2021-01-28
    • 1970-01-01
    • 2012-02-24
    • 2022-11-22
    • 2012-12-03
    • 1970-01-01
    相关资源
    最近更新 更多