Fråga:
Hur summerar jag data efter grupp i R?
Yuriy Petrovskiy
2011-03-13 17:02:39 UTC
view on stackexchange narkive permalink

Jag har R-dataram så här:

  åldersgrupp1 23.0883 12 25.8344 13 29.4648 14 32.7858 25 33.6372 16 34.9350 17 35.2115 28 35.2115 29 35.2115 210 36.7803 1 ...  

Jag måste få dataramen i följande form:

  gruppmedelvärde sd1 34,5 5,62 32,3 4,2 ...  

Grupp numret kan variera, men deras namn och kvantitet kan erhållas genom att ringa levels(factor(data$group))

Vilka manipulationer bör göras med data för att få resultatet?

komma i resultatdataramen betyder något speciellt, eller är det bara decimalpunkten?
@mpiktas Tack för att du noterade det. Rättad. Det här var lokala problem (jag är ryska) - vi använder komma för decimalavgränsning.
Jag misstänkte det. Hela [Europa] (http://en.wikipedia.org/wiki/File:DecimalSeparator.svg) använder komma utom britterna.
Trots att jag inte är brittisk föredrar jag punkt för decimalavgränsare.
Se "aggregat", "tapply" och sedan http://stackoverflow.com för eventuella efterföljande kodfrågor av denna typ.
Nio svar:
mpiktas
2011-03-13 17:44:14 UTC
view on stackexchange narkive permalink

Här är plyr en linjevariant som använder ddply):

  dt <- data.frame (age = rchisq (20, 10), grupp = prov (1: 2,20, rep = T)) ddply (dt, ~ grupp, sammanfatta, medelvärde = medelvärde (ålder), sd = sd (ålder))  

Här är en annan variant med en rad med nytt paket data.table .

  dtf <- data.frame (age = rchisq (100000,10), group = factor (sample (1: 10,100000, rep = T))) dt <- data.table (dtf) dt [, lista (medelvärde = medelvärde (ålder), sd = sd (ålder)), efter = grupp]  

Den här är snabbare, men detta syns bara på bordet med 100 000 rader. Tider på min Macbook Pro med 2.53 Ghz Core 2 Duo-processor och R 2.11.1:

  > system.time (aa <- ddply (dtf, ~ grupp, sammanfatta, medelvärde = medelålder ), sd = sd (ålder))) utilisateur système écoulé 0.513 0.180 0.692 > system.time (aa <- dt [, lista (medelvärde = medelvärde (ålder), sd = sd (ålder)), efter = grupp]) utilisateur système écoulé 0,087 0,018 0,103 

Ytterligare besparingar är möjliga om vi använder setkey:

  > setkey (dt, group) > system.time (dt [, lista (medelvärde = medelvärde (ålder), sd = sd (ålder)), efter = grupp]) utilisateur système écoulé 0,040 0,007 0,048  
@chl, det gav mig en chans att prova detta nya ** data.table ** paket. Det ser väldigt lovande ut.
+6000 för datatabell. Det är verkligen så mycket snabbare än ddply, även för mig på dataset mindre än 100k (jag har en med bara 20k rader). Måste vara något att göra med de funktioner jag tillämpar, men ddply tar minuter och data.table några sekunder.
Enkelt skrivfel: Jag tror att du menade "dt <- data.table (dtf)" istället för "dt <- data.table (dt)" i det andra kodblocket.På det sättet skapar du datatabellen från en dataram istället för från dt-funktionen från paketet 'stats'.Jag försökte redigera den, men jag kan inte redigera under sex tecken.
Enligt min (inte ödmjuka i det här fallet) är 'data.table' det bästa sättet att aggregera data och det här svaret är fantastiskt, men ändå bara repor på ytan.Förutom att vara syntaktiskt överlägsen, är den också extremt flexibel och har många avancerade funktioner som involverar anslutningar och intern mekanik.Kolla in FAQ, github-sida eller kurs för mer info.
ocram
2011-03-13 17:12:54 UTC
view on stackexchange narkive permalink

En möjlighet är att använda aggregeringsfunktionen. Till exempel

  aggregat (data $ age, by = list (data $ group), FUN = medel ) [2]  

ger dig den andra kolumnen med önskat resultat.

Länk inte till din lokala hjälpserver :-) +1 men se mina kommentarer till @steffen's-svaret.
Gör saken genom att ringa `data.frame (grupp = nivåer (faktor (data $ grupp)), medelvärde = (aggregerad (data $ ålder, efter = lista (data $ grupp), FUN = medel) $ x), sd = (aggregerat (data $ age, by = list (data $ group), FUN = sd) $ x) 'men jag är inte säker på att det är rätt sätt. Jag är inte säker på vad som kommer att hända då kommer resultaten av bundna kolumner att vara i olika ordning (jag tror att det är möjligt). Vad är ditt åsikt?
@Yuriy Raderna ska inte vara i ordning, men här är ett sätt att göra det ett samtal till `aggregat ()`: `aggregat (ålder ~ grupp, data = dat, FUN = funktion (x) c (M = medelvärde ( x), SD = sd (x))) `
@lockedoff: Tack för att du har slutfört mitt svar!
Bastiaan Quast
2014-07-15 17:26:23 UTC
view on stackexchange narkive permalink

Eftersom du manipulerar en dataram är paketet dplyr förmodligen det snabbaste sättet att göra det.

  library (dplyr) dt <- data.frame (ålder = rchisq (20,10), grupp = prov (1: 2,20, rep = T)) grp <- grupp_by (dt, grupp) sammanfatta (grp, medelvärde = medelvärde (ålder), sd = sd (ålder ))  

eller motsvarande, med dplyr / magrittr röroperatör:

  bibliotek ( dplyr) dt <- data.frame (age = rchisq (20,10), group = sample (1: 2,20, rep = T)) group_by (dt, group)% >% summer (medelvärde = medelvärde (ålder) , sd = sd (ålder)  

REDIGERA fullständig användning av röroperatör:

  bibliotek (dplyr) data.frame (age = rchisq (20, 10), grupp = prov (1: 2,20, rep = T))% >% group_by (grupp)% >% sammanfattar (medelvärde = medelvärde (ålder), sd = sd (ålder))   före>
+1 för `dplyr`. Det har gjort så många R-uppgifter enkla och många av dessa metoder föråldrade.
Den fullständiga användningen av röroperatörsversionen fungerar tyvärr inte för mig
laddade du dplyr eller magrittr?
tack så mycket @bquast för att du pekade på lösningen, sammanfattningsfunktionen kallades från `plyr` istället för` dplyr` som orsakade problemet.
Matifou
2014-07-15 20:01:29 UTC
view on stackexchange narkive permalink

Bra, tack bquast för att du lagt till dplyr-lösningen!

Visar sig att då är dplyr och data.table väldigt nära:

  bibliotek (plyr) bibliotek ( dplyr) bibliotek (data.table) bibliotek (rbenchmark) dtf <- data.frame (age = rchisq (100000,10), group = factor (sample (1: 10,100000, rep = T))) dt <- data .table (dtf) setkey (dt, group) a<-benchmark (ddply (dtf, ~ group, plyr ::: summarize, mean = mean (age), sd = sd (age)), dt [, list (mean = medelvärde (ålder), sd = sd (ålder)), efter = grupp], grupp_by (dt, grupp)% >% sammanfatta (medelvärde = medelvärde (ålder), sd = sd (ålder)), grupp_by (dtf, grupp) % >% sammanfattar (medelvärde = medelvärde (ålder), sd = sd (ålder)) a [, c (1,3,4)]  

data.tabellen är fortfarande den snabbaste , följt mycket nära av dplyr (), som intressant verkar snabbare på data.frame än data.table:

  testet gått relativt1 ddply (dtf, ~ group, plyr ::: summer , medelvärde = medelvärde (ålder), sd = sd (ålder)) 1,689 4,8672 dt [, lista (medelvärde = medelvärde (ålder), sd = sd (ålder)), efter = grupp] 0,347 1.0004 grupp_by (dtf, grupp)% >% sammanfatta (medelvärde = medelvärde (ålder), sd = sd (ålder) ) 0,369 1,0633 grupp_by (dt, grupp)% >% sammanfattar (medelvärde = medelvärde (ålder), sd = sd (ålder)) 0,580 1,671  
Först trodde jag att du behövde flytta setkey till riktmärket, men det visar sig att det tar nästan ingen tid alls.
Jeromy Anglim
2011-03-13 17:38:58 UTC
view on stackexchange narkive permalink

Förutom befintliga förslag kanske du vill kolla in funktionen beskriv.av i paketet psyk .

Det ger ett nummer beskrivande statistik inklusive medelvärdet och standardavvikelsen baserat på en grupperingsvariabel.

det är trevligt, men lite knepigt att exportera till LaTeX IME.
gung - Reinstate Monica
2013-05-17 02:53:17 UTC
view on stackexchange narkive permalink

Jag har funnit att funktionen summaryBy i doBy-paketet är den mest praktiska för detta:

  library (doBy) age = c (23.0883, 25.8344, 29.4648, 32.7858, 33.6372, 34.935, 35.2115, 35.2115, 5.2115, 36.7803) grupp = c (1, 1, 1, 2, 1, 1, 2, 2, 2, 1) dframe = data .ram (ålder = ålder, grupp = grupp) sammanfattning Av (ålder ~ grupp, data = dframe, FUN = c (medelvärde, sd)) # # gruppålder. medelålder.sd # 1 1 30.62333 5.415439 # 2 2 27.10507 14.640441  
KalEl
2013-05-24 03:25:57 UTC
view on stackexchange narkive permalink

Använd paketet sqldf . Detta gör att du nu kan använda SQL för att sammanfatta data. När du väl laddat den kan du skriva något som -

  sqldf ('select group, avg (age) from data group for group')  
steffen
2011-03-13 17:15:30 UTC
view on stackexchange narkive permalink

Redigerad: Enligt chls förslag

Funktionen du letar efter kallas "tapply" som tillämpar en funktion per grupp som anges av en faktor.

  # skapa några konstgjorda dataset.seed (42) grupper <- 5agedat <- c () groupdat <- c () för (grupp i 1: grupper) {agedat <- c (agedat, rnorm (100, medelvärde = 0 + grupp, 1 / grupp)) groupdat <- c (groupdat, rep (grupp, 100))} dat <- data.frame ("age" = agedat, "group" = factor (groupdat)) # beräkna medel- och stdev-ålder per grupp <- rbind.data.frame (grupp = 1: 5, med (dat, tapply (ålder, grupp, funktion (x) c (medelvärde (x), sd (x)))) namn (res) <- klistra in ("grupp", 1: 5) rad.names (res) [2: 3] <- c ("medel", "sd")  

I föreslår verkligen att du arbetar igenom en grundläggande R-handledning som förklarar alla vanliga datastrukturer och metoder. Annars kommer du att fastna varje tum under programmeringen. Se den här frågan för en samling gratis tillgängliga resurser.

@steffen +1 men det finns inget behov av en `för`-slinga här, du kan konstruera din dataframe inline, IMO. För "tapply" -samtalet, använd "funktion (x) c (medelvärde (x), sd (x)))" och "cbind" resultatet när OP frågade om båda statistiken. Dessutom kan `ddply` från paketet [plyr] (http://had.co.nz/plyr/) göra det smidigt.
@steffen Problemet är att jag behöver exakt den tabellstruktur som jag beskrev. Det finns inga problem med att få medel och sd. Problemet är med struktur.
@chl: Tack för din kommentar, visste inte om plyr :). Jag lade till cbind, men lämnade resten orörd. Må en annan ta æren, detta svar ska förbli ett mindre optimalt exempel.
@Yuriy: Lagt till cbind. Om du redan visste hur du tillämpar funktioner per grupp kan du formulera om din fråga (bara för tydlighetens skull;)).
@steffen `cbind (" betyder "= mperage," stdev "= stperage) ger ingen" grupp "-kolumn. Kommer att gå med `cbind (group = levels (factor (data $ group))," mean "= mperage," stdev "= stperage)` korrekt?
@Yuriy: Radnamnen är gruppnamnen .... Ändå lade jag till en separat kolumn (använder nu data.frame) för att visa detta.
@steffen Är du säker på att det inte kommer att finnas några beställningsproblem när du går med i kolumner?
@Yuriy, ordnar resultaten efter ordning på nivåerna, så att beställningsproblem inte uppstår. @steffen, Jag röstade upp svaret för ansträngningen, innan jag visste plyr, brukade jag lösa sådana problem på liknande sätt.
@steffen Försök att ersätta de tre sista raderna med kod med: `t (rbind.data.frame (grupp = 1: 5, med (dat, tapply (ålder, grupp, funktion (x) c (medelvärde (x), sd ( x)))))) `(+ byt namn på de två sista kolumnerna som` medel` och `sd`).
Stéphane Laurent
2012-11-08 12:41:07 UTC
view on stackexchange narkive permalink

Här är ett exempel med funktionen aggregates () Jag gjorde själv för en tid sedan:

  # simulerar dataset.seed (666) (dat <- data . ram (grupp = gl (3,6), nivå = faktor (rep (c ("A", "B", "C"), 6)), y = rund (rnorm (18,10), 1) )) > dat gruppnivå y1 1 A 10.82 1 B 12.03 1 C 9.64 1 A 12.05 1 B 7.86 1 C 10.87 2 A 8.78 2 B 9.29 2 C 8.210 2 A 10.011 2 B 12.212 2 C 8.213 3 A 10.914 3 B 8.315 3 C 10.116 3 A 9.917 3 B 10.918 3 C 10.3 # aggregates () functionaggregates <- function (formula, data = NULL, FUNS) {if (class (FUNS) == "list") {f <- function (x) sapply (FUNS, funktion (kul) kul (x))} annat {f <- FUNS} temp <- aggregat (formel, data, f) ut <- data.frame (temp [, - ncol (temp)], temp [ , ncol (temp)]) kolumn (out) [1] <- colnames (temp) [1] return (out)} # exempel FUNS <- funktion (x) c (medel = rund (medel (x), 0), sd = rund (sd (x), 0 )) (ag <- aggregat (y ~ grupp: nivå, data = dat, FUNS = FUNS)) 

Det ger följande resultat:

  > ag gruppnivå medelvärde sd1 1 A 11 12 2 A 9 13 3 A 10 14 1 B 10 35 2 B 11 26 3 B 10 27 1 C 10 18 2 C 8 09 3 C 10 0  

Kanske kan du få samma resultat från R-split ():

  > med (dat, sapply (split (y, group: level), FUNS)) 1: A 1: B 1: C 2: A 2: B 2: C 3: A 3: B 3: Cmean 11 10 10 9 11 8 10 10 10sd 1 3 1 1 2 0 1 2 0  

Låt mig komma tillbaka till utdata från funktionen aggregates . Du kan förvandla den i en vacker tabell med omforma () , xtabs () och ftable () :

  rag <- omformning (ag, varierande = lista (3: 4), riktning = "lång", v.names = "y") rag $ tid <- faktor (rag $ tid) ft <- ftable (xtabs (y ~ grupp + nivå + tid, data = rag)) attribut (ft) $ col.vars <- list (c ("medel", "sd"))  

Detta ger:

  > ft medelvärde sdgruppnivå 1 A 11 1 B 10 3 C 10 12 A 9 1 B 11 2 C 8 03 A 10 1 B 10 2 C 10 0  kod > 

Vackert, eller hur? Du kan exportera denna tabell till en pdf med funktionen textplot () för paketet gplots .

Se här för andras lösningar.



Denna fråga och svar översattes automatiskt från det engelska språket.Det ursprungliga innehållet finns tillgängligt på stackexchange, vilket vi tackar för cc by-sa 2.0-licensen som det distribueras under.
Loading...