Aggregazione / riepilogo di più variabili per gruppo (ad es. Somma, media)


154

Da un frame di dati, c'è un modo semplice per aggregare ( sum, mean, maxet c) più variabili contemporaneamente?

Di seguito sono riportati alcuni dati di esempio:

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)

Vorrei aggregare simultaneamente le variabili x1e x2dal df2frame di dati per anno e mese. Il codice seguente aggrega la x1variabile, ma è anche possibile aggregare contemporaneamente la x2variabile?

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

Ogni suggerimento sarà molto apprezzato.

Risposte:


45

Da dove viene questa year()funzione?

È inoltre possibile utilizzare il reshape2pacchetto per questa attività:

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

8
La recastfunzione (anche da reshape2) integra la funzione melte dcastin una sola volta per attività come questa:recast(df1, year + month ~ variable, sum, id.var = c("date", "year", "month"))
Jaap

184

Sì, nel tuo formula, è possibile cbindaggregare le variabili numeriche:

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

Vedi ?aggregate, l' formulaargomento e gli esempi.


3
È possibile che cbind usi variabili dinamiche?
pdb,

14
Vale la pena notare che quando una qualsiasi delle variabili presenti nel cbind ha un NA, la riga verrà eliminata per ogni variabile nel cbind. Questo non è il comportamento che mi aspettavo.
pdb,

1
cosa succede se invece di x1 e x2 voglio usare tutte le restanti variabili (tranne l'anno, il mese)
Clock Slave

7
@ClockSlave, quindi è sufficiente utilizzare .l'LHS. aggregate(. ~ year + month, df1, sum, na.rm = TRUE). In questo esempio, sumper "data" non ha senso però ....
A5C1D2H2I1M1N2O1R2T1

5
E se non volessi due variabili ma due funzioni ?. Ad esempio media e sd.
skan

51

Utilizzo del data.tablepacchetto, che è veloce (utile per set di dati più grandi)

https://github.com/Rdatatable/data.table/wiki

library(data.table)
df2 <- setDT(df1)[, lapply(.SD, sum), by=.(year, month), .SDcols=c("x1","x2")]
setDF(df2) # convert back to dataframe

Utilizzando il pacchetto plyr

require(plyr)
df2 <- ddply(df1, c("year", "month"), function(x) colSums(x[c("x1", "x2")]))

Utilizzando summarize () dal pacchetto Hmisc (le intestazioni di colonna sono disordinate nel mio esempio però)

# need to detach plyr because plyr and Hmisc both have a summarize()
detach(package:plyr)
require(Hmisc)
df2 <- with(df1, summarize( cbind(x1, x2), by=llist(year, month), FUN=colSums))

perché non fare questo per l'opzione data.table: dt[, .(x1.sum = sum(x1), x2.sum = sum(x2), by = c(year, month)?
Bulat,

48

Con il dplyrpacchetto, è possibile utilizzare summarise_all, summarise_ato summarise_iffunzioni di aggregare più variabili contemporaneamente. Per il set di dati di esempio puoi farlo come segue:

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)

Il risultato di queste ultime due opzioni:

    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

Nota: summarise_eachè deprecato a favore di summarise_all, summarise_ate summarise_if.


Come menzionato nel mio commento sopra , puoi anche usare la recastfunzione dal reshape2pacchetto:

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

che ti darà lo stesso risultato.


8

È interessante notare che aggregateil data.framemetodo di base R non è mostrato qui, al di sopra dell'interfaccia della formula viene utilizzata, quindi per completezza:

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

Uso più generico del metodo data.frame aggregato:

Dal momento che stiamo fornendo un

  • data.framecome xe
  • a list( data.frameè anche a list) comeby , questo è molto utile se dobbiamo usarlo in modo dinamico, ad esempio usare altre colonne per aggregare e aggregare è molto semplice
  • anche con funzioni di aggregazione personalizzate

Ad esempio in questo modo:

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)

1

Con la develversione di dplyr(versione - ‘0.8.99.9000’), possiamo anche usare summariseper applicare la funzione su più colonne conacross

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

1

Per un approccio più flessibile e più rapido all'aggregazione dei dati, controlla la collapfunzione nel pacchetto di compressione R disponibile su CRAN:

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

Nota : è possibile utilizzare funzioni di base come mean, maxecc. Con collap, ma fmean, fmaxecc. Sono offerte funzioni raggruppate basate su C ++ offerte nel pacchetto di compressione che sono significativamente più veloci (ovvero le prestazioni su aggregazioni di dati di grandi dimensioni sono le stesse di data.table fornendo una maggiore flessibilità, e queste funzioni raggruppate rapidamente possono essere utilizzate anche senza collap).

Nota 2 : collapsupporta anche l'aggregazione flessibile di dati multitipo, che puoi ovviamente fare usando l' customargomento, ma puoi anche applicare le funzioni alle colonne numeriche e non numeriche in modo semi-automatico:

# 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

0

In ritardo alla festa, ma recentemente ha trovato un altro modo per ottenere le statistiche di riepilogo.

library(psych) describe(data)

Produrrà: media, min, max, deviazione standard, n, errore standard, curtosi, asimmetria, mediana e intervallo per ogni variabile.


La domanda è di fare aggregazioni per gruppo , ma describenon fa nulla per gruppo ...
Gregor Thomas,

describe.by(column, group = grouped_column)raggrupperà i valori
britt

4
Bene, allora inseriscilo nella risposta! Non nasconderlo in un commento!
Gregor Thomas,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.