【问题标题】:How to aggregate data in data.frame in R如何在 R 中的 data.frame 中聚合数据
【发布时间】:2017-08-15 19:19:27
【问题描述】:

我有一个很大的 data.frame。 data.frame 包含很多值。

例如:

df <- data.frame(Company = c('A', 'A', 'B', 'C', 'A', 'B', 'B', 'C', 'C'), 
                 Name = c("Wayne", "Duane", "William", "Rafael", "John", "Eric", "James", "Pablo", "Tammy"), 
                 Age = c(26, 27, 28, 32, 28, 24, 34, 30, 25), 
                 Wages = c(50000, 70000, 70000, 60000, 50000, 70000, 65000, 50000, 50000), 
                 Education.University = c(1, 1, 1, 0, 0, 1, 1, 0, 1), 
                 Productivity = c(100, 120, 120, 95, 88, 115, 100, 90, 120))

如何汇总我的data.frame?我想分析每家公司的价值观。它必须看起来像:

年龄 -> 公司所有员工的平均年龄

工资 -> 公司所有员工的平均工资

Education.University -> 公司所有员工的因素总和(1 或 0)

生产力 -> 公司所有员工的平均生产力

【问题讨论】:

标签: r dataframe aggregate


【解决方案1】:

基础R

cbind(aggregate(.~Company, df[,-c(2, 5)], mean),
      aggregate(Education.University~Company, df, sum)[-1])
#  Company      Age    Wages Productivity Education.University
#1       A 27.00000 56666.67     102.6667                    2
#2       B 28.66667 68333.33     111.6667                    3
#3       C 29.00000 53333.33     101.6667                    1

这里是较长的版本,可能更容易理解

merge(x = aggregate(x = list(Age_av = df$Age,
                             Wages_av = df$Wages,
                             Productivity_av = df$Productivity),
                by = list(Company = df$Company),
                FUN = mean),
      y = aggregate(x = list(Education.University_sum = df$Education.University),
                by = list(Company = df$Company),
                FUN = sum),
      by = "Company")
#  Company   Age_av Wages_av Productivity_av Education.University_sum
#1       A 27.00000 56666.67        102.6667                        2
#2       B 28.66667 68333.33        111.6667                        3
#3       C 29.00000 53333.33        101.6667                        1

【讨论】:

    【解决方案2】:

    一个选项是使用data.table

    library(data.table)
    setDT(df)[, c(lapply(.SD[, c(2:3, 5), with = FALSE], mean), 
        .(Education.University = sum(Education.University))), by = Company]
    #   Company      Age    Wages Productivity Education.University
    #1:       A 27.00000 56666.67     102.6667                    2
    #2:       B 28.66667 68333.33     111.6667                    3
    #3:       C 29.00000 53333.33     101.6667                    1
    

    或dplyr

    library(dplyr)
    df %>%
       group_by(Company) %>% 
       mutate(Education.University = sum(Education.University)) %>%
       summarise_if(is.numeric, mean)
    # A tibble: 3 x 5
    #  Company      Age    Wages Education.University Productivity
    #   <fctr>    <dbl>    <dbl>                <dbl>        <dbl>
    #1       A 27.00000 56666.67                    2     102.6667
    #2       B 28.66667 68333.33                    3     111.6667
    #3       C 29.00000 53333.33                    1     101.6667
    

    【讨论】:

    • @akrun 谢谢! data.table 有效。 dplyr group_by 中是否有可能有更多值,例如Company 和Name?
    • @Denis 是的,你可以使用group_by(Company, Name)
    【解决方案3】:

    您可以使用 dplyr 库轻松做到这一点。

    library(dplyr)
    df %>% group_by(Company) %>% summarise(Age = mean(Age), Wages = mean(Wages), Education.University = sum(Education.University), Productivity = mean(Productivity))
    

    【讨论】:

      【解决方案4】:

      简洁的data.table 解决方案已经posted 使用列numbers 而不是列names。这被认为是不好的做法 Frequently Asked Questions about data.table, section 1.1:

      如果您的同事稍后出现并阅读您的代码,他们可能不得不四处寻找哪一列是第 5 列。如果您或他们在您的 R 程序中更改了更高的列顺序,您可能会产生错误的结果,而没有如果您忘记更改代码中引用第 5 列的所有位置,则会出现警告或错误。

      所以,我想提出使用列名的替代方法。

      变体 1

      library(data.table)
      setDT(df)[, .(average.Age = mean(Age), 
                    average.Wages = mean(Wages), 
                    sum.Education.University = sum(Education.University),
                    average.Productivity = mean(Productivity)), 
                by = Company]
      
         Company average.Age average.Wages sum.Education.University average.Productivity
      1:       A    27.00000      56666.67                        2             102.6667
      2:       B    28.66667      68333.33                        3             111.6667
      3:       C    29.00000      53333.33                        1             101.6667
      

      在这里,每一列都是单独聚合的。虽然它需要更多的打字,但它有几个好处:

      1. 很容易理解代码 sn-p 的用途。
      2. 可以根据需要修改结果中的列名。
      3. 如果需要,可以控制结果中列的顺序。

      变体 2

      如果有许多列需要相同的操作,data.table 常见问题解答recommends 使用.SDcols。所以,我们可以做

      m_cols <- c("Age", "Wages", "Productivity")
      s_cols <- c("Education.University")
      by_cols <- c("Company") 
      setDT(df)[, c(.SD[, lapply(.SD, mean), .SDcols = m_cols],
                    .SD[, lapply(.SD, sum ), .SDcols = s_cols]),
                by = by_cols]
      
         Company      Age    Wages Productivity Education.University
      1:       A 27.00000 56666.67     102.6667                    2
      2:       B 28.66667 68333.33     111.6667                    3
      3:       C 29.00000 53333.33     101.6667                    1
      

      这类似于 Akrun's answer,但使用列 names 而不是列 numbers。此外,列名存储在一个便于编程的变量中。

      请注意,by_cols 可能包含用于聚合的其他列,例如,

      by_cols <- c("Company", "Name")
      

      如果列顺序很重要,我们可以使用setcolorder():

      result <- setDT(df)[, c(.SD[, lapply(.SD, mean), .SDcols = m_cols],
                              .SD[, lapply(.SD, sum ), .SDcols = s_cols]),
                          by = by_cols]
      setcolorder(result, intersect(names(df), names(result)))
      result
      
         Company      Age    Wages Education.University Productivity
      1:       A 27.00000 56666.67                    2     102.6667
      2:       B 28.66667 68333.33                    3     111.6667
      3:       C 29.00000 53333.33                    1     101.6667
      

      同样,可以修改结果的列名以满足OP的要求:

      setnames(result, m_cols, paste0("average.", m_cols))
      setnames(result, s_cols, paste0("sum.", s_cols))
      result
      
         Company average.Age average.Wages sum.Education.University average.Productivity
      1:       A    27.00000      56666.67                        2             102.6667
      2:       B    28.66667      68333.33                        3             111.6667
      3:       C    29.00000      53333.33                        1             101.6667
      

      请注意,data.table 函数 setcolorder() 和 setnames() 工作就地,即不复制 data.table 对象。这可以节省内存和时间,这在处理大型表时尤为重要。

      【讨论】:

        【解决方案5】:

        只需使用“聚合”功能

        aggregate(x = df[c("Age","Wages","Education.University","Productivity")], by = df[c("Company")], FUN = mean)
        
        #  Company      Age    Wages Education.University Productivity
        #1       A 27.00000 56666.67            0.6666667     102.6667
        #2       B 28.66667 68333.33            1.0000000     111.6667
        #3       C 29.00000 53333.33            0.3333333     101.6667
        

        【讨论】:

        • OP 需要教育大学的总和,其余的需要平均数。
        • @Brutalroot 如果我想一次添加多个统计信息,我可以这样做吗?我想得到 mean、min、max、sd、Iqr、Mscore 和其他一些忽略 NA 并为每个统计数据创建一个新的 df
        • @user3614197 检查此主题。 'stackoverflow.com/questions/12064202/…'
        猜你喜欢
        • 2013-03-23
        • 2021-02-27
        • 1970-01-01
        • 2020-09-03
        • 2016-08-28
        • 2011-07-24
        • 2020-03-28
        • 2014-11-07
        • 1970-01-01
        相关资源
        最近更新 更多