2009-11-02 12 views
207

Załóżmy, że mam dwie kolumny danych. Pierwszy zawiera kategorie takie jak "Pierwszy", "Drugi", "Trzeci" itp. Drugi ma liczby, które reprezentują liczbę razy, kiedy zobaczyłem "Pierwszy".Jak podsumować zmienną według grupy?

Na przykład:

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

chcę sortować dane według kategorii i zsumować Częstotliwości:

Category  Frequency 
First  30 
Second  5 
Third  34 

Jak zrobić to w R?

Odpowiedz

234

Korzystanie aggregate:

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

(osadzanie @thelatemail komentarz) aggregate posiada interfejs formułą zbyt

aggregate(Frequency ~ Category, x, sum) 

Albo jeśli chcesz agregować wiele kolumn, to może wykorzystać . notacja (dotyczy również jednej kolumny)

aggregate(. ~ Category, x, sum) 

lub tapply:

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

Stosując te dane:

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

@AndrewMcKinlay, R używa tyldy do definiowania formuł symbolicznych, dla statystyk i innych funkcji. Może być interpretowany jako * "model Częstotliwość według kategorii" * lub * "Częstotliwość w zależności od kategorii" *.Nie wszystkie języki używają specjalnego operatora do zdefiniowania funkcji symbolicznej, jak to zrobiono w R tutaj. Być może dzięki tej "naturalno-językowej interpretacji" operatora tyldy staje się ona bardziej znacząca (a nawet intuicyjna). Osobiście uważam, że ta symboliczna reprezentacja formuły jest lepsza niż niektóre bardziej szczegółowe alternatywy. – r2evans

13

Jeśli x jest dataframe ze swoimi danymi, a następnie dodaje się będzie robić to, co chcesz:

require(reshape) 
recast(x, Category ~ ., fun.aggregate=sum) 
19
library(plyr) 
ddply(tbl, .(Category), summarise, sum = sum(Frequency)) 
15

Wystarczy dodać trzecią opcję:

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

EDIT: jest bardzo stara odpowiedź. Teraz polecam użycie group_by i podsumuję od dplyr, jak w odpowiedzi @docendo.

30

Jest to nieco related to this question.

Można też po prostu użyć przez() funkcję:

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

Te inne pakiety (plyr, przekształcenia) mają korzyści z przekazaniem data.frame, ale warto jest znać przez (), ponieważ jest to funkcja podstawowa.

48

Odpowiedź udzielona przez rcs działa i jest prosta. Jednakże, jeśli są obsługi większych zbiorów danych i potrzebują wzrost wydajności jest 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 z wykorzystaniem danych.Rama i powyżej powyż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 

A 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 staną się bardziej widoczne z większych zbiorów danych, jak poniżej kod demonstruje:

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 skupisk, można połączyć lapply i .SD następująco

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

+1 Ale 0.296 vs 0.059 nie robi szczególnie imponującego. Rozmiar danych musi być znacznie większy niż 300 tys. Wierszy, a przy więcej niż 3 grupach, aby data.table mogła świecić. Na przykład wkrótce spróbujemy obsłużyć ponad 2 miliardy wierszy, ponieważ niektórzy użytkownicy data.table mają 250 GB pamięci RAM, a GNU R obsługuje teraz długość> 2^31. –

+1

Prawda. Okazuje się, że nie mam całej pamięci RAM i po prostu starałem się dostarczyć dowodów na lepszą wydajność data.table. Jestem pewien, że różnica byłaby jeszcze większa przy większej ilości danych. – asieira

+0

Miałem 7 mil obserwacji dplyr wziął .3 sekundy i agregacji() trwało 22 sekundy, aby zakończyć operację. Zamierzałem opublikować to na ten temat, a ty mnie biłeś! – zazu

114

Ostatnio, można również użyć dplyr pakiet do tego celu:

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 

Albo na wielu kolumn podsumowania (działa z jednej kolumnie zbyt):

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

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

Albo, jeśli masz wiele kolumn do grupy przez, można 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, w tym operatora %>%, zobacz introduction to dplyr.

+0

Jaka jest szybkość w porównaniu z tabelami data.table i aggregate przedstawionymi w innych odpowiedziach? – asieira

+2

@asieira, która jest najszybsza i jak duża różnica (lub różnica jest zauważalna) zawsze zależy od rozmiaru danych. Zazwyczaj w przypadku dużych zbiorów danych, na przykład niektórych GB, data.table będzie najprawdopodobniej najszybsza. Przy mniejszych rozmiarach danych data.table i dplyr są często bliskie, także w zależności od liczby grup. Zarówno dane, tabela, jak i dplyr będą znacznie szybsze niż funkcje podstawowe (może być nawet 100-1000 razy szybsze w przypadku niektórych operacji). Zobacz także [tutaj] (http://stackoverflow.com/questions/21435339/data-table-vs-dplyr-can-one-do-something-well-the-other-cant-or-does-poorly) –

15

Kilka lat później, po prostu dodać kolejny proste rozwiązanie baza R, który nie jest obecny tutaj jakiegoś rozsądnym xtabs

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

Lub jeśli chcesz data.frame z powrotem

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

Chociaż mam Niedawno stał się konwerterem na dplyr dla większości tego typu operacji, pakiet sqldf jest nadal bardzo miły (i IMHO bardziej czytelny) dla niektórych rzeczy.

Oto przykład jak to pytanie można odpowiedzieć 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 
0

użyciu cast zamiast recast (nota '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) 

dostać:

Category (all) 
First  30 
Second 5 
Third  34