【问题标题】:How to sum one column based on key of two other columns如何根据其他两列的键对一列求和
【发布时间】:2014-12-16 19:27:25
【问题描述】:

我有一个包含三列的 data.frame:

To     Amount   Type
Smith  $1       A
John   $5       B
Jeff   $8       A
Smith  $4       C
...    ...      ...

而且我需要将它转换成一个数据框,表明每个人每种类型收到了多少钱。

Name  TotalAmtOfTypeA  TotalAmtOfTypeB  TotalAmtOfTypeC ...
Smith $1               $0               $4
John  $0               $5               $0
Jeff  $8               $0               $0
...

原始 data.frame 的长度刚刚超过 300 万行,因此解决方案越高效或并行化越好。解决方案是否涉及aggregate?或者我应该看看plyr?任何指导将不胜感激!

【问题讨论】:

  • 此解决方案涉及“重塑”数据框。有一个基本的 R reshape 函数,但是如果你想学习 dplyr 系列工具,使用的包是 tidyr(它是 dplyr 的补充)。看看函数spread()

标签: r sum dataframe


【解决方案1】:

这里有两个选项:

library(tidyr)
spread(df, Type, Amount)
#     To ordered.A ordered.B ordered.C
#1  Jeff        $8      <NA>      <NA>
#2  John      <NA>        $5      <NA>
#3 Smith        $1      <NA>        $4

或者

library(reshape2)
dcast(df, To ~ Type, value.var = "Amount")
#     To    A    B    C
#1  Jeff   $8 <NA> <NA>
#2  John <NA>   $5 <NA>
#3 Smith   $1 <NA>   $4

或者,如果您将列类从因子更改为字符,您可以这样做:

df$Amount <- as.character(df$Amount)
dcast(df, To ~ Type, value.var = "Amount", fill = "$0")
#     To  A  B  C
#1  Jeff $8 $0 $0
#2  John $0 $5 $0
#3 Smith $1 $0 $4

同样

spread(df, Type, Amount, fill = "$0")
#     To  A  B  C
#1  Jeff $8 $0 $0
#2  John $0 $5 $0
#3 Smith $1 $0 $4

注意:如果您将“金额”列为因素并尝试使用fill = "$0",您将收到如下错误消息:

警告消息:在 [&lt;-.factor(*tmp*, is.na(ordered), value = 0) 中: 无效因子水平,NA生成


如果您想去掉“金额”列中的那些“$”,以便实际使用这些数字进行进一步处理,您可以在 dplyr / tidyr 链中执行以下操作:

library(dplyr)
library(tidyr)
df %>%
  mutate(Amount = as.numeric(gsub("\\$", "", Amount))) %>%
  spread(Type, Amount, fill = 0)

#     To A B C
#1  Jeff 8 0 0
#2  John 0 5 0
#3 Smith 1 0 4

【讨论】:

    【解决方案2】:

    这是一个data.table 解决方案,它应该会运行得相当快:

    数据

    library(data.table)
    n <- 1e6
    dat <- data.table(Name = LETTERS[sample(26, n, TRUE)],
                      Amount = rpois(n, 100),
                      Type = letters[sample(26, n, TRUE)])
    

    代码

    setkey(dat, Name, Type)
    dat.agg <- dat[, .(Sum = sum(Amount)), by =.(Name, Type)]
    dat.agg[, as.list(setattr(Sum, 'names', Type)), by = .(Name)]
    

    说明

    第一个 [.data.table 聚合 data.table 以获得所有 Name/Type 组合的总和。第二个[.data.table 以您想要的方式格式化data.tablesetattr 用于有一个很好的输出(根据Type 的级别对列进行调整。

    【讨论】:

    • 这似乎完全在正确的轨道上,但是根据我的真实数据,我得到了错误:Error in `[.data.table`(pacdons2.agg, , as.list(setattr(Sum, "names", : j doesn't evaluate to the same number of columns for each group
    猜你喜欢
    • 2021-01-26
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    • 2020-05-30
    • 2014-05-07
    • 2021-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多