【问题标题】:Aggregation and percentage calculation by groups按组聚合和百分比计算
【发布时间】:2014-12-24 10:03:27
【问题描述】:

我在 R 中有一个按班级划分的学生每周津贴数据集,如下所示:

Year    ID  Class       Allowance
2013    123 Freshman    100
2013    234 Freshman    110
2013    345 Sophomore   150
2013    456 Sophomore   200
2013    567 Junior      250
2014    678 Junior      100
2014    789 Junior      230
2014    890 Freshman    110
2014    891 Freshman    250
2014    892 Sophomore   220

如何按组(年份/班级)汇总结果以获得总和和百分比(按组)?使用ddply 获得总和似乎很容易,只是无法正确获得按组的百分比。

它适用于sum

summary <- ddply(my_data, .(Year, Class), summarize, Sum_Allow=sum(Allowance))

但它不适用于按组部分的百分比:

summary <- ddply(my_data, .(Year, Class), summarize, Sum_Allow=sum(Allowance),
                 Allow_Pct=Allowance/sum(Allowance))

理想的结果应该是这样的:

 Year     Class Sum_Allow Allow_Pct
 2013  Freshman       210       26%
 2013    Junior       250       31%
 2013 Sophomore       350       43%
 2014  Freshman       360       40%
 2014    Junior       330       36%
 2014 Sophomore       220       24%

我尝试了 plyr 包中的 ddply,但请告诉我任何可行的方法。

【问题讨论】:

  • 您正在尝试绑定具有奇数行数的数据帧。分别执行Sum_allowallow_pct 并查看结果。您可以使用 head 或 tail 来获取每个百分比的第一行或最后一行

标签: r plyr aggregation


【解决方案1】:

这是使用data.table 包的可能解决方案(假设您的数据称为df

library(data.table)
setDT(df)[, list(Sum_Allow = sum(Allowance)), keyby = list(Year, Class)][, 
            Allow_Pct := paste0(round(Sum_Allow/sum(Sum_Allow), 2)*100, "%"), by = Year][]

#    Year     Class Sum_Allow Allow_Pct
# 1: 2013  Freshman       210       26%
# 2: 2013    Junior       250       31%
# 3: 2013 Sophomore       350       43%
# 4: 2014  Freshman       360       40%
# 5: 2014    Junior       330       36%
# 6: 2014 Sophomore       220       24%

贡献给@rawr,这是一个可能的基础 R 解决方案

df2 <- aggregate(Allowance ~  Class + Year, df, sum)
transform(df2, Allow_pct = ave(Allowance, Year, FUN = function(x) paste0(round(x/sum(x), 2)*100, "%")))
#       Class Year Allowance Allow_pct
# 1  Freshman 2013       210       26%
# 2    Junior 2013       250       31%
# 3 Sophomore 2013       350       43%
# 4  Freshman 2014       360       40%
# 5    Junior 2014       330       36%
# 6 Sophomore 2014       220       24%

【讨论】:

    【解决方案2】:

    您可以分两步完成此操作

    my_data <- read.table(header = TRUE,
                          text = "Year    ID  Class       Allowance
    2013    123 Freshman    100
    2013    234 Freshman    110
    2013    345 Sophomore   150
    2013    456 Sophomore   200
    2013    567 Junior      250
    2014    678 Junior      100
    2014    789 Junior      230
    2014    890 Freshman    110
    2014    891 Freshman    250
    2014    892 Sophomore   220")
    
    library(plyr)
    (summ <- ddply(my_data, .(Year, Class), summarize, Sum_Allow=sum(Allowance)))
    
    #   Year     Class Sum_Allow
    # 1 2013  Freshman       210
    # 2 2013    Junior       250
    # 3 2013 Sophomore       350
    # 4 2014  Freshman       360
    # 5 2014    Junior       330
    # 6 2014 Sophomore       220
    
    ddply(summ, .(Year), mutate, Allow_pct = Sum_Allow / sum(Sum_Allow) * 100)
    
    #   Year     Class Sum_Allow Allow_pct
    # 1 2013  Freshman       210  25.92593
    # 2 2013    Junior       250  30.86420
    # 3 2013 Sophomore       350  43.20988
    # 4 2014  Freshman       360  39.56044
    # 5 2014    Junior       330  36.26374
    # 6 2014 Sophomore       220  24.17582
    

    我不知道你们其他人是否会发生这种情况,但是当我运行最初的尝试时,R 会崩溃而不是发出警告。或者,如果我拼错了 Allow 而不是 allow,它就会崩溃。我真的很讨厌那个;哈德利请修复

    base r 永远

    【讨论】:

    • 不确定在您的解决方案中base R扮演什么角色
    • @DavidArenburg 如上所述 plyr 的挫败感
    • 哦,我的代码没有任何错误,但plyr 基本上是基本 R 的包装器,我认为那里没有用 C 编写的东西
    • @DavidArenburg 当我在 rstudio 中运行由 OP 编写的代码时,它每次都会崩溃,ddply(my_data, .(Year, Class), summarize, Sum_Allow = sum(Allowance), Allow_Pct = Allowance/sum(Allowance)) 因为 Sum_allow 和 Allow_pct 返回的行数不同,就像我在上面的 cmets 中提到的那样。没有关于绑定问题的警告,只是崩溃
    • 好的,我专门为您贡献了一个基本的 R 解决方案,请参阅我对答案的编辑
    【解决方案3】:

    所以假设你想要的是:

    1. 获取由 Year AND Class 定义的所有组中 Allowance 列的总和,并且
    2. 将该总和除以相关年份的总和

    那么这可以在 dplyr 中解决问题:

    library(dplyr)
    my_data <- read.table(header = TRUE,
                          text = 
    'Year    ID  Class       Allowance
    2013    123 Freshman    100
    2013    234 Freshman    110
    2013    345 Sophomore   150
    2013    456 Sophomore   200
    2013    567 Junior      250
    2014    678 Junior      100
    2014    789 Junior      230
    2014    890 Freshman    110
    2014    891 Freshman    250
    2014    892 Sophomore   220')
    
    summary <- my_data %>%
      group_by(Year) %>%
      summarise(Year_Sum_Allow = sum(Allowance)) %>%
      left_join(x = my_data, y = ., by = 'Year') %>%
      group_by(Year, Class) %>%
      summarise(Sum_Allow = sum(Allowance),
                Allow_Pct = Sum_Allow/first(Year_Sum_Allow))
    
    summary
    
    # Results
    Source: local data frame [6 x 4]
    Groups: Year
    
      Year     Class Sum_Allow Allow_Pct
    1 2013  Freshman       210 0.2592593
    2 2013    Junior       250 0.3086420
    3 2013 Sophomore       350 0.4320988
    4 2014  Freshman       360 0.3956044
    5 2014    Junior       330 0.3626374
    6 2014 Sophomore       220 0.2417582
    

    如果您不熟悉 dplyr,其语法可能看起来很奇怪。我建议看看introduction。这样可以节省大量时间。

    编辑:我应该补充一点,如果您想要在示例输出中使用相当圆润的百分比格式,您可以在最后一行替换 Allow_Pct = paste0(round(Sum_Allow/first(Year_Sum_Allow), 2), '%')

    编辑 2:正如 jbaums 指出的,这可以简化为:

    my_data %>% 
      group_by(Year, Class) %>% 
      summarise(sum_allow=sum(Allowance)) %>% 
      mutate(pct_allow=sum_allow/sum(sum_allow))
    

    【讨论】:

    • 这可以简化为:my_data %&gt;% group_by(Year, Class) %&gt;% summarise(sum_allow=sum(Allowance)) %&gt;% mutate(pct_allow=sum_allow/sum(sum_allow)).
    • @jbaums,我想知道最后一个mutate 怎么知道它应该由year 专门分组,而不是由上面指定的group_by 分组或根本不分组.. .
    • @DavidArenburg,来自dplyr vignette:“当您按多个变量分组时,每个摘要都会剥离一个分组级别。这使得逐步汇总数据集变得容易”。因此,在summarise 之后,分组变量'Class' 被剥离,然后数据按'Year' 'only' 分组。
    • @Henrik - 我自己和your other post 都想引用这一点。 @David - 因此,如果我写 group_by(Class, Year),它就不会以同样的方式工作。
    • @Henrik,这很有趣,也许值得在 data.table 中将其作为功能请求推荐给 Arun 或 Matt
    猜你喜欢
    • 2017-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多