Jak zsumować zmienną według grupy?

Powiedzmy, że mam dwie kolumny danych. Pierwszy zawiera kategorie takie jak "pierwszy"," drugi"," trzeci " itp. Drugi ma liczby, które reprezentują liczbę razy widziałem "pierwszy".

Na przykład:

Category     Frequency
First        10
First        15
First        5
Second       2
Third        14
Third        20
Second       3

Chcę posortować dane według kategorii i zsumować częstotliwości:

Category     Frequency
First        30
Second       5
Third        34

Jak mam to zrobić w R?

Author: David Arenburg, 2009-11-02

10 answers

Używając aggregate:

aggregate(x$Frequency, by=list(Category=x$Category), FUN=sum)
  Category  x
1    First 30
2   Second  5
3    Third 34

(embedding @thelatemail comment), aggregate ma też interfejs formuły

aggregate(Frequency ~ Category, x, sum)

Lub jeśli chcesz połączyć wiele kolumn, możesz użyć notacji . (działa również dla jednej kolumny)

aggregate(. ~ Category, x, sum)

Lub tapply:

tapply(x$Frequency, x$Category, FUN=sum)
 First Second  Third 
    30      5     34 

Wykorzystanie tych danych:

x <- data.frame(Category=factor(c("First", "First", "First", "Second",
                                      "Third", "Third", "Second")), 
                    Frequency=c(10,15,5,2,14,20,3))
 274
Author: rcs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-03 23:06:55

Od niedawna możesz również użyć do tego celu pakietu dplyr:

library(dplyr)
x %>% 
  group_by(Category) %>% 
  summarise(Frequency = sum(Frequency))

#Source: local data frame [3 x 2]
#
#  Category Frequency
#1    First        30
#2   Second         5
#3    Third        34

Lub dla wielu kolumn podsumowania (działa również z jedną kolumną):

x %>% 
  group_by(Category) %>% 
  summarise_each(funs(sum))

Aktualizacja dla dplyr >= 0.5: summarise_each został zastąpiony przez summarise_all, summarise_at i summarise_if rodzina funkcji w dplyr.

Lub, jeśli masz wiele kolumn do pogrupowania według, możesz określić wszystkie z nich w group_by oddzielonych przecinkami:

mtcars %>% 
  group_by(cyl, gear) %>%                            # multiple group columns
  summarise(max_hp = max(hp), mean_mpg = mean(mpg))  # multiple summary columns

Aby uzyskać więcej informacji, łącznie z operatorem %>%, Zobacz wprowadzenie do dplyr .

 141
Author: docendo discimus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-02 15:32:13

Odpowiedź udzielona przez rcs działa i jest prosta. Jeśli jednak obsługujesz większe zbiory danych i potrzebujesz zwiększenia wydajności, istnieje szybsza alternatywa: {]}

library(data.table)
data = data.table(Category=c("First","First","First","Second","Third", "Third", "Second"), 
                  Frequency=c(10,15,5,2,14,20,3))
data[, sum(Frequency), by = Category]
#    Category V1
# 1:    First 30
# 2:   Second  5
# 3:    Third 34
system.time(data[, sum(Frequency), by = Category] )
# user    system   elapsed 
# 0.008     0.001     0.009 

Porównajmy to do tego samego, używając danych.ramka i wyżej:

data = data.frame(Category=c("First","First","First","Second","Third", "Third", "Second"),
                  Frequency=c(10,15,5,2,14,20,3))
system.time(aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum))
# user    system   elapsed 
# 0.008     0.000     0.015 

I jeśli chcesz zachować kolumnę to jest składnia:

data[,list(Frequency=sum(Frequency)),by=Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34

Różnica będzie bardziej zauważalna przy większych zestawach danych, jak pokazuje poniższy kod:

data = data.table(Category=rep(c("First", "Second", "Third"), 100000),
                  Frequency=rnorm(100000))
system.time( data[,sum(Frequency),by=Category] )
# user    system   elapsed 
# 0.055     0.004     0.059 
data = data.frame(Category=rep(c("First", "Second", "Third"), 100000), 
                  Frequency=rnorm(100000))
system.time( aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum) )
# user    system   elapsed 
# 0.287     0.010     0.296 

Dla wielu agregacji, ty można łączyć lapply i .SD w następujący sposób

data[, lapply(.SD, sum), by = Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34
 56
Author: asieira,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-09 12:24:08

Jest to nieco związane z tym pytaniem .

Możesz również użyć funkcji by () :

x2 <- by(x$Frequency, x$Category, sum)
do.call(rbind,as.list(x2))

Te inne pakiety (plyr, reshape) mają tę zaletę, że zwracają dane.frame, ale warto się z nią zapoznać by (), ponieważ jest to funkcja bazowa.

 33
Author: Shane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:44
library(plyr)
ddply(tbl, .(Category), summarise, sum = sum(Frequency))
 21
Author: learnr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-02 09:44:34

Kilka lat później, aby dodać kolejne proste rozwiązanie base R, którego nie ma tutaj z jakiegoś powodu - xtabs

xtabs(Frequency ~ Category, df)
# Category
# First Second  Third 
#    30      5     34 

Or if want a data.frame back

as.data.frame(xtabs(Frequency ~ Category, df))
#   Category Freq
# 1    First   30
# 2   Second    5
# 3    Third   34
 18
Author: David Arenburg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-10 13:36:01

Aby dodać trzecią opcję:

require(doBy)
summaryBy(Frequency~Category, data=yourdataframe, FUN=sum)

EDIT: to bardzo stara odpowiedź. Teraz polecam użycie group_by i streszczenia z dplyr, jak w odpowiedzi @docendo.

 15
Author: dalloliogm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-24 15:24:20

Podczas gdy ostatnio stałem się konwerterem na dplyr dla większości tego typu operacji, pakiet sqldf jest nadal naprawdę ładny (i IMHO bardziej czytelny) dla niektórych rzeczy.

Oto przykład jak na to pytanie można odpowiedzieć za pomocą sqldf

x <- data.frame(Category=factor(c("First", "First", "First", "Second",
                                  "Third", "Third", "Second")), 
                Frequency=c(10,15,5,2,14,20,3))

sqldf("select 
          Category
          ,sum(Frequency) as Frequency 
       from x 
       group by 
          Category")

##   Category Frequency
## 1    First        30
## 2   Second         5
## 3    Third        34
 14
Author: joemienko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-17 12:12:56

Jeśli x jest ramką danych z Twoimi danymi, to następujące dane zrobią to, co chcesz:

require(reshape)
recast(x, Category ~ ., fun.aggregate=sum)
 13
Author: Rob Hyndman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-02 09:44:03

Użycie cast zamiast recast (Uwaga 'Frequency' jest teraz 'value')

df  <- data.frame(Category = c("First","First","First","Second","Third","Third","Second")
                  , value = c(10,15,5,2,14,20,3))

install.packages("reshape")

result<-cast(df, Category ~ . ,fun.aggregate=sum)

Aby uzyskać:

Category (all)
First     30
Second    5
Third     34
 1
Author: Grant Shannon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-25 15:43:56