【问题标题】:Conditional row summing inside of group组内条件行求和
【发布时间】:2017-01-14 16:32:47
【问题描述】:

我在 df 中对行求和时遇到了一些问题,我想对每个组内的 BAD 和 UGLY 行求和(如果它们存在)!

group = c(seq(1,1.4,0.2),rep(seq(1.6,2,0.2),c(3,3,2)))
clas=c(rep("BAD",3),rep(c("BAD","GOOD","UGLY"),2),rep(c("BAD","GOOD"),1))
n=c(rep(1000,3),96,180,715,190,184,26,124,874)
df <- data.frame(group,clas,n)

> df
#   group clas    n
#1    1.0  BAD 1000
#2    1.2  BAD 1000
#3    1.4  BAD 1000
#4    1.6  BAD   96
#5    1.6 GOOD  180
#6    1.6 UGLY  715
#7    1.8  BAD  190
#8    1.8 GOOD  184
#9    1.8 UGLY   26
#10   2.0  BAD  124
#11   2.0 GOOD  874

我试过这个,但由于我的逻辑不好,它当然没用!

library(dplyr)
df %>%
group_by(group) %>% 
mutate(sum = ifelse(all(clas=="BAD"),n,ifelse(with(clas=="BAD"&clas=="UGLY"),n["BAD"]+n["UGLY"],"NA")))

错误:“逻辑”类型的“环境”参数无效

如果代码可以修复,预期的输出,

> df
    #   group clas    n  sum
    #1    1.0  BAD 1000   1000
    #2    1.2  BAD 1000   1000
    #3    1.4  BAD 1000   1000
    #4    1.6  BAD   96    811
    #5    1.6 GOOD  180    811
    #6    1.6 UGLY  715    811
    #7    1.8  BAD  190    216
    #8    1.8 GOOD  184    216 
    #9    1.8 UGLY   26    216
    #10   2.0  BAD  124    124
    #11   2.0 GOOD  874    124

谢谢!

【问题讨论】:

  • df %&gt;% group_by(group) %&gt;% mutate(sum = sum(n)- sum(n[clas=="GOOD"])) 或 sum(n[clas=="BAD"|clas=="UGLY"])
  • @zx8754 不。没必要!

标签: r dplyr


【解决方案1】:

使用base R aggregate 和merge 的另一个选项。

我们可以 aggregate n 超过 group 忽略 clas GOOD 然后 merge 它们通过 group 到原始数据帧以获得预期的行数。

merge(df, aggregate(n~group, df[!df$clas == "GOOD", ], sum), by = "group", 
                                                   suffixes = c("", "Sum"))


#   group clas    n Sum
#1    1.0  BAD 1000 1000
#2    1.2  BAD 1000 1000
#3    1.4  BAD 1000 1000
#4    1.6  BAD   96  811
#5    1.6 GOOD  180  811
#6    1.6 UGLY  715  811
#7    1.8  BAD  190  216
#8    1.8 GOOD  184  216
#9    1.8 UGLY   26  216
#10   2.0  BAD  124  124
#11   2.0 GOOD  874  124

【讨论】:

    【解决方案2】:

    我们可以使用data.table。将 'data.frame' 转换为 'data.table' (setDT(df)),按 'group' 分组,使用%in%,子集获取基于 'clas' 中的 'BAD'、'UGLY' 元素的逻辑索引'n' 与此索引,获取 sum 并将 (:=) 分配给新列 'Sum'。

    library(data.table)
    setDT(df)[,  Sum := sum(n[as.character(clas) %chin% c("BAD", "UGLY")]), by = group]
    df
    #   group clas    n  Sum
    #1:   1.0  BAD 1000 1000
    #2:   1.2  BAD 1000 1000
    #3:   1.4  BAD 1000 1000
    #4:   1.6  BAD   96  811
    #5:   1.6 GOOD  180  811
    #6:   1.6 UGLY  715  811
    #7:   1.8  BAD  190  216
    #8:   1.8 GOOD  184  216
    #9:   1.8 UGLY   26  216
    #10:   2.0  BAD  124  124
    #11:   2.0 GOOD  874  124
    

    基准测试

    在 1e6 数据集上,基准是

    set.seed(24)
    df1 <- data.frame(group = sample(1:1000, 1e6, replace=TRUE), 
             clas = sample(c("BAD", "GOOD", "UGLY"), 1e6, replace=TRUE),
             n = sample(100:1000, 1e6, replace=TRUE))
    
    
    df2 <- copy(df1)
    
    system.time(setDT(df1)[,  Sum := sum(n[as.character(clas) %chin% c("BAD", "UGLY")]), by = group])
    #    user  system elapsed 
    #   0.04    0.02    0.06 
    
    
    system.time(merge(df2, aggregate(n~group, df2[!df2$clas == "GOOD", ], sum), by = "group", 
                                                    suffixes = c("", "Sum")))
    #   user  system elapsed 
    #   5.00    0.16    5.17 
    

    如果我们将行数从 1e6 增加到 1e7

    system.time(setDT(df1)[,  Sum := sum(n[as.character(clas) %chin% c("BAD", "UGLY")]), by = group])
    #   user  system elapsed 
    #   0.65    0.00    0.66 
    system.time(merge(df2, aggregate(n~group, df2[!df2$clas == "GOOD", ], sum), by = "group", 
                                                    suffixes = c("", "Sum")))
    #   user  system elapsed 
    #  58.00    1.58   59.78 
    

    【讨论】:

    • 也非常感谢data.table 方法。我只是想知道data.table 比dplyr 好吗?
    • @Alexander The assign (:=) 就地执行它,所以它应该更有效率。
    • 我明白了,但我仍然觉得 data.table 很难理解。也许到时候我会习惯的;)
    • 也许我可以使用dplyr 和data.table 的组合。因为我总是从使用dplyr 清理数据开始,并对数据进行这种操作。我希望更多地了解这两者。你有博客之类的吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2018-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多