每组汇总/总结多个变量(例如,总和,平均值)

从一个数据框架,有一个简单的方法来聚合(summeanmax等 c)多个变量同时?

下面是一些样本数据:

library(lubridate)
days = 365*2
date = seq(as.Date("2000-01-01"), length = days, by = "day")
year = year(date)
month = month(date)
x1 = cumsum(rnorm(days, 0.05))
x2 = cumsum(rnorm(days, 0.05))
df1 = data.frame(date, year, month, x1, x2)

我想同时聚合的 x1x2变量从 df2数据框架按年和按月。下面的代码聚合了 x1变量,但是是否也可以同时聚合 x2变量?

### aggregate variables by year month
df2=aggregate(x1 ~ year+month, data=df1, sum, na.rm=TRUE)
head(df2)
220092 次浏览

是的,在你的 formula,你可以 cbind的数字变量被聚合:

aggregate(cbind(x1, x2) ~ year + month, data = df1, sum, na.rm = TRUE)
year month         x1          x2
1  2000     1   7.862002   -7.469298
2  2001     1 276.758209  474.384252
3  2000     2  13.122369 -128.122613
...
23 2000    12  63.436507  449.794454
24 2001    12 999.472226  922.726589

参见 ?aggregateformula参数和示例。

这个 year()函数来自哪里?

您还可以使用 reshape2包完成这项任务:

require(reshape2)
df_melt <- melt(df1, id = c("date", "year", "month"))
dcast(df_melt, year + month ~ variable, sum)
#  year month         x1           x2
1  2000     1  -80.83405 -224.9540159
2  2000     2 -223.76331 -288.2418017
3  2000     3 -188.83930 -481.5601913
4  2000     4 -197.47797 -473.7137420
5  2000     5 -259.07928 -372.4563522

使用 dplyr包,可以使用 summarise_allsummarise_atsummarise_if函数同时聚合多个变量。对于示例数据集,您可以执行以下操作:

library(dplyr)
# summarising all non-grouping variables
df2 <- df1 %>% group_by(year, month) %>% summarise_all(sum)


# summarising a specific set of non-grouping variables
df2 <- df1 %>% group_by(year, month) %>% summarise_at(vars(x1, x2), sum)
df2 <- df1 %>% group_by(year, month) %>% summarise_at(vars(-date), sum)


# summarising a specific set of non-grouping variables using select_helpers
# see ?select_helpers for more options
df2 <- df1 %>% group_by(year, month) %>% summarise_at(vars(starts_with('x')), sum)
df2 <- df1 %>% group_by(year, month) %>% summarise_at(vars(matches('.*[0-9]')), sum)


# summarising a specific set of non-grouping variables based on condition (class)
df2 <- df1 %>% group_by(year, month) %>% summarise_if(is.numeric, sum)

后两种选择的结果是:

    year month        x1         x2
<dbl> <dbl>     <dbl>      <dbl>
1   2000     1 -73.58134  -92.78595
2   2000     2 -57.81334 -152.36983
3   2000     3 122.68758  153.55243
4   2000     4 450.24980  285.56374
5   2000     5 678.37867  384.42888
6   2000     6 792.68696  530.28694
7   2000     7 908.58795  452.31222
8   2000     8 710.69928  719.35225
9   2000     9 725.06079  914.93687
10  2000    10 770.60304  863.39337
# ... with 14 more rows

注意: 不推荐使用 summarise_each,推荐使用 summarise_allsummarise_atsummarise_if


正如在 我上面的评论中提到的,您也可以使用 reshape2-package 中的 recast函数:

library(reshape2)
recast(df1, year + month ~ variable, sum, id.var = c("date", "year", "month"))

也会得到同样的结果。

晚会迟到了,但最近找到了另一种方法来获得总结统计数据。

图书馆(精神科) 说明(数据)

将输出: 每个变量的平均值,最小值,最大值,标准差,n,标准误差,峰度,偏度,中值和范围。

有趣的是,这里没有展示 R aggregatedata.frame方法,使用的是 以上公式接口,因此为了完整性:

aggregate(
x = df1[c("x1", "x2")],
by = df1[c("year", "month")],
FUN = sum, na.rm = TRUE
)

更一般地使用聚合的 data.frame 方法:

由于我们提供了一个

  • 作为 x
  • A list(data.frame也是 list)作为 by,这是非常有用的,如果我们需要使用它在一个动态的方式,例如使用其他列聚合和聚合是非常简单的
  • 还有定制的聚合函数

例如:

colsToAggregate <- c("x1")
aggregateBy <- c("year", "month")
dummyaggfun <- function(v, na.rm = TRUE) {
c(sum = sum(v, na.rm = na.rm), mean = mean(v, na.rm = na.rm))
}


aggregate(df1[colsToAggregate], by = df1[aggregateBy], FUN = dummyaggfun)

使用 dplyr version > = 1.0.0,我们还可以使用 summariseacross的多个列应用函数

library(dplyr)
df1 %>%
group_by(year, month) %>%
summarise(across(starts_with('x'), sum))
# A tibble: 24 x 4
# Groups:   year [2]
#    year month     x1     x2
#   <dbl> <dbl>  <dbl>  <dbl>
# 1  2000     1   11.7  52.9
# 2  2000     2  -74.1 126.
# 3  2000     3 -132.  149.
# 4  2000     4 -130.    4.12
# 5  2000     5  -91.6 -55.9
# 6  2000     6  179.   73.7
# 7  2000     7   95.0 409.
# 8  2000     8  255.  283.
# 9  2000     9  489.  331.
#10  2000    10  719.  305.
# … with 14 more rows

要获得更灵活、更快捷的数据汇总方法,请查阅 CRAN 上提供的 崩溃 R 软件包中的 collap功能:

library(collapse)
# Simple aggregation with one function
head(collap(df1, x1 + x2 ~ year + month, fmean))


year month        x1        x2
1 2000     1 -1.217984  4.008534
2 2000     2 -1.117777 11.460301
3 2000     3  5.552706  8.621904
4 2000     4  4.238889 22.382953
5 2000     5  3.124566 39.982799
6 2000     6 -1.415203 48.252283


# Customized: Aggregate columns with different functions
head(collap(df1, x1 + x2 ~ year + month,
custom = list(fmean = c("x1", "x2"), fmedian = "x2")))


year month  fmean.x1  fmean.x2 fmedian.x2
1 2000     1 -1.217984  4.008534   3.266968
2 2000     2 -1.117777 11.460301  11.563387
3 2000     3  5.552706  8.621904   8.506329
4 2000     4  4.238889 22.382953  20.796205
5 2000     5  3.124566 39.982799  39.919145
6 2000     6 -1.415203 48.252283  48.653926


# You can also apply multiple functions to all columns
head(collap(df1, x1 + x2 ~ year + month, list(fmean, fmin, fmax)))


year month  fmean.x1    fmin.x1  fmax.x1  fmean.x2   fmin.x2  fmax.x2
1 2000     1 -1.217984 -4.2460775 1.245649  4.008534 -1.720181 10.47825
2 2000     2 -1.117777 -5.0081858 3.330872 11.460301  9.111287 13.86184
3 2000     3  5.552706  0.1193369 9.464760  8.621904  6.807443 11.54485
4 2000     4  4.238889  0.8723805 8.627637 22.382953 11.515753 31.66365
5 2000     5  3.124566 -1.5985090 7.341478 39.982799 31.957653 46.13732
6 2000     6 -1.415203 -4.6072295 2.655084 48.252283 42.809211 52.31309


# When you do that, you can also return the data in a long format
head(collap(df1, x1 + x2 ~ year + month, list(fmean, fmin, fmax), return = "long"))


Function year month        x1        x2
1    fmean 2000     1 -1.217984  4.008534
2    fmean 2000     2 -1.117777 11.460301
3    fmean 2000     3  5.552706  8.621904
4    fmean 2000     4  4.238889 22.382953
5    fmean 2000     5  3.124566 39.982799
6    fmean 2000     6 -1.415203 48.252283


注意 : 你可以在 collap中使用像 mean, max这样的基本函数,但是 fmean, fmax等是 崩溃包中提供的基于 C + + 的分组函数,速度要快得多(即大数据聚合的性能与 Data.table相同,同时提供了更大的灵活性,这些快速分组函数也可以在没有 collap的情况下使用)。

注2 : collap还支持灵活的多类型数据聚合,这当然可以使用 custom参数来实现,但是您也可以以半自动的方式将函数应用于数值和非数值列:

# wlddev is a data set of World Bank Indicators provided in the collapse package
head(wlddev)


country iso3c       date year decade     region     income  OECD PCGDP LIFEEX GINI       ODA
1 Afghanistan   AFG 1961-01-01 1960   1960 South Asia Low income FALSE    NA 32.292   NA 114440000
2 Afghanistan   AFG 1962-01-01 1961   1960 South Asia Low income FALSE    NA 32.742   NA 233350000
3 Afghanistan   AFG 1963-01-01 1962   1960 South Asia Low income FALSE    NA 33.185   NA 114880000
4 Afghanistan   AFG 1964-01-01 1963   1960 South Asia Low income FALSE    NA 33.624   NA 236450000
5 Afghanistan   AFG 1965-01-01 1964   1960 South Asia Low income FALSE    NA 34.060   NA 302480000
6 Afghanistan   AFG 1966-01-01 1965   1960 South Asia Low income FALSE    NA 34.495   NA 370250000


# This aggregates the data, applying the mean to numeric and the statistical mode to categorical columns
head(collap(wlddev, ~ iso3c + decade, FUN = fmean, catFUN = fmode))


country iso3c       date   year decade                     region      income  OECD    PCGDP   LIFEEX GINI      ODA
1   Aruba   ABW 1961-01-01 1962.5   1960 Latin America & Caribbean  High income FALSE       NA 66.58583   NA       NA
2   Aruba   ABW 1967-01-01 1970.0   1970 Latin America & Caribbean  High income FALSE       NA 69.14178   NA       NA
3   Aruba   ABW 1976-01-01 1980.0   1980 Latin America & Caribbean  High income FALSE       NA 72.17600   NA 33630000
4   Aruba   ABW 1987-01-01 1990.0   1990 Latin America & Caribbean  High income FALSE 23677.09 73.45356   NA 41563333
5   Aruba   ABW 1996-01-01 2000.0   2000 Latin America & Caribbean  High income FALSE 26766.93 73.85773   NA 19857000
6   Aruba   ABW 2007-01-01 2010.0   2010 Latin America & Caribbean  High income FALSE 25238.80 75.01078   NA       NA


# Note that by default (argument keep.col.order = TRUE) the column order is also preserved

下面是另一种汇总多列的方法,在函数需要进一步参数时尤其有用。您可以通过 everything()any_of(c("a", "b"))等列的子集选择所有列。

library(dplyr)
# toy data
df <- tibble(a = sample(c(NA, 5:7), 30, replace = TRUE),
b = sample(c(NA, 1:5), 30, replace = TRUE),
c = sample(1:5, 30, replace = TRUE),
grp = sample(1:3, 30, replace = TRUE))
df
#> # A tibble: 30 × 4
#>        a     b     c   grp
#>    <int> <int> <int> <int>
#>  1     7     1     3     1
#>  2     7     4     4     2
#>  3     5     1     3     3
#>  4     7    NA     3     2
#>  5     7     2     5     2
#>  6     7     4     4     2
#>  7     7    NA     3     3
#>  8    NA     5     4     1
#>  9     5     1     1     2
#> 10    NA     3     1     2
#> # … with 20 more rows
df %>%
group_by(grp) %>%
summarise(across(everything(),
list(mean = ~mean(., na.rm = TRUE),
q75 = ~quantile(., probs = .75, na.rm = TRUE))))
#> # A tibble: 3 × 7
#>     grp a_mean a_q75 b_mean b_q75 c_mean c_q75
#>   <int>  <dbl> <dbl>  <dbl> <dbl>  <dbl> <dbl>
#> 1     1   6.6      7   2.88  4.25   3        4
#> 2     2   6.33     7   2.62  3.25   2.9      4
#> 3     3   5.78     6   3.33  4      3.09     4

更新后的 dplyr解决方案: 由于 dplyr 1.1.0(在 dev 版本中是2022-11-19,但是在 将于2023年1月在 CRAN 上发布中) ,您可以使用 summarise中的 .by来执行内联临时分组(在计算之后自动执行 ungroup)。

使用 across(可从 dplyr 1.0.0获得)允许同时对多个列应用相同的函数。

#devtools::install_github('tidyverse/dplyr')
library(dplyr)
df1 %>%
summarise(across(starts_with('x'), sum), .by = c(year, month))


# A tibble: 24 x 4
#    year month     x1     x2
#   <dbl> <dbl>  <dbl>  <dbl>
# 1  2000     1   11.7  52.9
# 2  2000     2  -74.1 126.
# 3  2000     3 -132.  149.
# 4  2000     4 -130.    4.12
# 5  2000     5  -91.6 -55.9
# 6  2000     6  179.   73.7
# 7  2000     7   95.0 409.
# 8  2000     8  255.  283.
# 9  2000     9  489.  331.
#10  2000    10  719.  305.
# … with 14 more rows