如何在R中的data.frame中聚合数据

时间:2017-08-15 19:19:27

标签: r dataframe aggregate

我有一个大型的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?我想分析每家公司的价值观。它必须看起来像:

enter image description here

年龄 - &gt;公司所有员工的平均年龄

工资 - &gt;公司所有员工的平均工资

Education.University - &gt;公司所有员工的因子(1或0)之和

生产力 - &gt;公司所有员工的平均生产率

5 个答案:

答案 0 :(得分:4)

基础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

答案 1 :(得分:3)

一种选择是使用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

答案 2 :(得分:3)

您可以使用 dplyr 库轻松完成此操作。

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

答案 3 :(得分:2)

简明data.table解决方案已posted使用列数字而不是列名称。根据这被认为是不良做法 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. 很容易理解代码片段的用途。
  2. 可以根据需要修改结果中的列名称。
  3. 如果需要,可以控制结果中列的顺序。
  4. 变式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类似,但使用列名称而不是列数字。此外,列名存储在一个易于编程的变量中。

    请注意,by_cols可能包含其他要聚合的列,.e.g,

    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对象。这样可以节省内存和时间,这在处理大型表时尤其重要。

答案 4 :(得分:2)

只需使用“聚合”功能

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