web-dev-qa-db-de.com

So summieren Sie eine Variable nach Gruppe

Angenommen, ich habe zwei Datenspalten. Die erste enthält Kategorien wie "Erste", "Zweite", "Dritte" usw. Die zweite enthält Zahlen, die angeben, wie oft ich "Erste" gesehen habe.

Zum Beispiel:

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

Ich möchte die Daten nach Kategorie sortieren und die Häufigkeiten summieren:

Category     Frequency
First        30
Second       5
Third        34

Wie würde ich das in R machen?

307
user5243421

aggregate verwenden:

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

Im obigen Beispiel können in list mehrere Dimensionen angegeben werden. Mehrere aggregierte Metriken desselben Datentyps können über cbind eingebunden werden:

aggregate(cbind(x$Frequency, x$Metric2, x$Metric3) ...

(@thelatemail Kommentar einbetten), aggregate hat auch eine Formel-Schnittstelle

aggregate(Frequency ~ Category, x, sum)

Wenn Sie mehrere Spalten zusammenfassen möchten, können Sie auch die . -Notation verwenden (funktioniert auch für eine Spalte).

aggregate(. ~ Category, x, sum)

oder tapply:

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

Verwendung dieser Daten:

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

In jüngerer Zeit können Sie auch das Paket dplyr für diesen Zweck verwenden:

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

Oder für mehrere Zusammenfassungsspalten (funktioniert auch mit einer Spalte):

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

Update für dplyr> = 0.5: summarise_each wurde ersetzt durch summarise_all, summarise_at und summarise_if familie von funktionen in dplyr.

Wenn Sie mehrere Spalten gruppieren möchten , können Sie alle in group_by durch Kommas getrennt angeben:

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

Weitere Informationen, einschließlich des Operators %>%, finden Sie in der Einführung in dplyr .

186

Die Antwort von rcs funktioniert und ist einfach. Wenn Sie jedoch größere Datenmengen verarbeiten und eine Leistungssteigerung benötigen, gibt es eine schnellere Alternative:

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 

Vergleichen wir das mit data.frame und dem obigen Beispiel:

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 

Und wenn Sie die Spalte behalten möchten, ist dies die Syntax:

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

Der Unterschied wird bei größeren Datenmengen deutlicher, wie der folgende Code zeigt:

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 

Für mehrere Aggregationen können Sie lapply und .SD wie folgt kombinieren

data[, lapply(.SD, sum), by = Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34
65
asieira

Dies ist etwas im Zusammenhang mit dieser Frage .

Sie können auch einfach die durch() Funktion:

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

Diese anderen Pakete (plyr, reshape) haben den Vorteil, dass sie einen data.frame zurückgeben, aber es lohnt sich, mit by () vertraut zu sein, da es sich um eine Basisfunktion handelt.

36
Shane
library(plyr)
ddply(tbl, .(Category), summarise, sum = sum(Frequency))
25
learnr

Einige Jahre später, nur um eine weitere einfache Basis-R-Lösung hinzuzufügen, die aus irgendeinem Grund hier nicht vorhanden ist- xtabs

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

Oder wenn du einen data.frame zurück haben willst

as.data.frame(xtabs(Frequency ~ Category, df))
#   Category Freq
# 1    First   30
# 2   Second    5
# 3    Third   34
24
David Arenburg

Wenn x ein Datenrahmen mit Ihren Daten ist, wird Folgendes tun, was Sie wollen:

require(reshape)
recast(x, Category ~ ., fun.aggregate=sum)
19
Rob Hyndman

Nur um eine dritte Option hinzuzufügen:

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

EDIT: Dies ist eine sehr alte Antwort. Jetzt würde ich die Verwendung von group_by und summarise von dplyr empfehlen, wie in @docendo answer.

16
dalloliogm

Während ich vor kurzem für die meisten dieser Vorgänge zu dplyr konvertiert wurde, ist das sqldf -Paket für einige Dinge immer noch sehr gut (und meiner Meinung nach besser lesbar).

Hier ist ein Beispiel, wie diese Frage mit sqldf beantwortet werden kann.

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
16
joemienko

Ich finde ave sehr hilfreich (und effizient), wenn Sie verschiedene Aggregationsfunktionen auf verschiedene Spalten anwenden müssen (und Sie auf Basis R bleiben müssen/möchten):

z.B.

Bei dieser Eingabe:

DF <-                
data.frame(Categ1=factor(c('A','A','B','B','A','B','A')),
           Categ2=factor(c('X','Y','X','X','X','Y','Y')),
           Samples=c(1,2,4,3,5,6,7),
           Freq=c(10,30,45,55,80,65,50))

> DF
  Categ1 Categ2 Samples Freq
1      A      X       1   10
2      A      Y       2   30
3      B      X       4   45
4      B      X       3   55
5      A      X       5   80
6      B      Y       6   65
7      A      Y       7   50

wir wollen nach Categ1 und Categ2 gruppieren und die Summe von Samples und dem Mittelwert von Freq berechnen.
Hier ist eine mögliche Lösung mit ave:

# create a copy of DF (only the grouping columns)
DF2 <- DF[,c('Categ1','Categ2')]

# add sum of Samples by Categ1,Categ2 to DF2 
# (ave repeats the sum of the group for each row in the same group)
DF2$GroupTotSamples <- ave(DF$Samples,DF2,FUN=sum)

# add mean of Freq by Categ1,Categ2 to DF2 
# (ave repeats the mean of the group for each row in the same group)
DF2$GroupAvgFreq <- ave(DF$Freq,DF2,FUN=mean)

# remove the duplicates (keep only one row for each group)
DF2 <- DF2[!duplicated(DF2),]

Ergebnis:

> DF2
  Categ1 Categ2 GroupTotSamples GroupAvgFreq
1      A      X               6           45
2      A      Y               9           40
3      B      X               7           50
6      B      Y               6           65
4
digEmAll

Das kürzlich hinzugefügte dplyr::tally() macht dies jetzt einfacher als je zuvor:

tally(x, Category)

Category     n
First        30
Second       5
Third        34
4
dmca

Sie können die Funktion group.sum aus package Rfast verwenden.

Category <- Rfast::as_integer(Category,result.sort=FALSE) # convert character to numeric. R's as.numeric produce NAs.
result <- Rfast::group.sum(Frequency,Category)
names(result) <- Rfast::Sort(unique(Category)
# 30 5 34

Rfast hat viele Gruppenfunktionen und group.sum ist eine davon.

3
Csd

verwenden von cast anstelle von recast (Anmerkung 'Frequency' ist jetzt '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)

bekommen:

Category (all)
First     30
Second    5
Third     34
2
Grant Shannon