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?
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))
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 .
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
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.
library(plyr)
ddply(tbl, .(Category), summarise, sum = sum(Frequency))
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
Wenn x
ein Datenrahmen mit Ihren Daten ist, wird Folgendes tun, was Sie wollen:
require(reshape)
recast(x, Category ~ ., fun.aggregate=sum)
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.
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
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
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
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.
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