beispiel - tapply r deutsch




Gruppierungsfunktionen(tapply, by, aggregate) und die*apply-Familie (6)

Auf der Seite Note, hier ist, wie die verschiedenen plyr Funktionen zu den Basis *apply Funktionen (aus dem Intro zu plyr Dokument von der Plyr-Webseite http://had.co.nz/plyr/ )

Base function   Input   Output   plyr function 
---------------------------------------
aggregate        d       d       ddply + colwise 
apply            a       a/l     aaply / alply 
by               d       l       dlply 
lapply           l       l       llply  
mapply           a       a/l     maply / mlply 
replicate        r       a/l     raply / rlply 
sapply           l       a       laply 

Eines der Ziele von plyr besteht darin, konsistente Benennungskonventionen für jede der Funktionen bereitzustellen und die Eingabe- und Ausgabedatentypen im Funktionsnamen zu codieren. Es sorgt auch für eine konsistente Ausgabe, da die Ausgabe von dlply() leicht an ldply() , um eine brauchbare Ausgabe usw. zu erzeugen.

Konzeptionell ist das Lernen von plyr nicht schwieriger als das Verständnis der basis *apply Funktionen.

plyr und plyr haben fast alle diese Funktionen in meinem täglichen Gebrauch ersetzt. Aber auch aus dem Intro zu Plyr Dokument:

Zugehörige Funktionen tapply und sweep haben keine entsprechende Funktion in plyr und bleiben nützlich. merge ist nützlich, um Zusammenfassungen mit den Originaldaten zu kombinieren.

Wann immer ich etwas "map" py in R machen möchte, versuche ich normalerweise eine Funktion in der apply .

Allerdings habe ich nie die Unterschiede zwischen ihnen verstanden - wie { sapply , lapply , etc.} die Funktion auf die Eingabe / gruppierte Eingabe anwenden, wie die Ausgabe aussehen wird oder sogar was die Eingabe sein kann - so Ich gehe oft alle durch, bis ich das bekomme, was ich will.

Kann jemand erklären, wie man welchen wann benutzt?

Mein aktuelles (wahrscheinlich inkorrektes / unvollständiges) Verständnis ist ...

  1. sapply(vec, f) : Eingabe ist ein Vektor. Ausgabe ist ein Vektor / eine Matrix, wobei Element i f(vec[i]) ist und Ihnen eine Matrix gibt, wenn f eine Ausgabe mit mehreren Elementen hat

  2. lapply(vec, f) : wie sapply , aber die Ausgabe ist eine Liste?

  3. apply(matrix, 1/2, f) : Eingabe ist eine Matrix. Ausgabe ist ein Vektor, wobei Element i f ist (Zeile / Spalte der Matrix)
  4. tapply(vector, grouping, f) : output ist eine Matrix / ein Array, wobei ein Element in der Matrix / Array der Wert von f in einer Gruppierung g des Vektors ist und g in die Zeilen- / Spaltennamen geschoben wird
  5. by(dataframe, grouping, f) : Sei g eine Gruppierung. Wenden Sie f auf jede Spalte der Gruppe / des Datenrahmens an. Zieh die Gruppierung und den Wert von f in jeder Spalte an.
  6. aggregate(matrix, grouping, f) : ähnlich wie by , aber anstatt die ausgabe hübsch zu drucken, bleibt alles in einem datenrahmen stecken.

Side question: Ich habe noch nicht plrr gelernt oder umgestaltet - würde plyr oder reshape all diese komplett ersetzen?


Da habe ich gemerkt, dass die (sehr sehr guten) Antworten dieses Beitrags auf fehlende und aggregate Erklärungen verzichten. Hier ist mein Beitrag.

DURCH

Die by Funktion, wie in der Dokumentation angegeben, kann jedoch als "Wrapper" für tapply . Die Macht von by entsteht, wenn wir eine Aufgabe berechnen wollen, die tapply nicht bewältigen kann. Ein Beispiel ist dieser Code:

ct <- tapply(iris$Sepal.Width , iris$Species , summary )
cb <- by(iris$Sepal.Width , iris$Species , summary )

 cb
iris$Species: setosa
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.300   3.200   3.400   3.428   3.675   4.400 
-------------------------------------------------------------- 
iris$Species: versicolor
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   2.525   2.800   2.770   3.000   3.400 
-------------------------------------------------------------- 
iris$Species: virginica
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.200   2.800   3.000   2.974   3.175   3.800 


ct
$setosa
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.300   3.200   3.400   3.428   3.675   4.400 

$versicolor
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.000   2.525   2.800   2.770   3.000   3.400 

$virginica
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  2.200   2.800   3.000   2.974   3.175   3.800 

Wenn wir diese beiden Objekte, ct und cb , drucken, haben wir "im Wesentlichen" die gleichen Ergebnisse und die einzigen Unterschiede bestehen darin, wie sie gezeigt werden, und die verschiedenen class , jeweils nach cb und array nach ct .

Wie ich gesagt habe, entsteht die Macht des tapply , wenn wir tapply nicht benutzen tapply ; Der folgende Code ist ein Beispiel:

 tapply(iris, iris$Species, summary )
Error in tapply(iris, iris$Species, summary) : 
  arguments must have same length

R sagt, dass Argumente die gleiche Länge haben müssen, sagen wir "wir wollen die summary aller Variablen in der iris entlang des Faktors Species berechnen": aber R kann das einfach nicht machen, weil es nicht weiß, wie es damit umgehen soll.

Mit der by Funktion R verschicken Sie eine spezifische Methode für data frame und lassen dann die summary Funktion auch dann laufen, wenn die Länge des ersten Arguments (und auch der Typ) unterschiedlich ist.

bywork <- by(iris, iris$Species, summary )

bywork
iris$Species: setosa
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.300   Min.   :2.300   Min.   :1.000   Min.   :0.100   setosa    :50  
 1st Qu.:4.800   1st Qu.:3.200   1st Qu.:1.400   1st Qu.:0.200   versicolor: 0  
 Median :5.000   Median :3.400   Median :1.500   Median :0.200   virginica : 0  
 Mean   :5.006   Mean   :3.428   Mean   :1.462   Mean   :0.246                  
 3rd Qu.:5.200   3rd Qu.:3.675   3rd Qu.:1.575   3rd Qu.:0.300                  
 Max.   :5.800   Max.   :4.400   Max.   :1.900   Max.   :0.600                  
-------------------------------------------------------------- 
iris$Species: versicolor
  Sepal.Length    Sepal.Width     Petal.Length   Petal.Width          Species  
 Min.   :4.900   Min.   :2.000   Min.   :3.00   Min.   :1.000   setosa    : 0  
 1st Qu.:5.600   1st Qu.:2.525   1st Qu.:4.00   1st Qu.:1.200   versicolor:50  
 Median :5.900   Median :2.800   Median :4.35   Median :1.300   virginica : 0  
 Mean   :5.936   Mean   :2.770   Mean   :4.26   Mean   :1.326                  
 3rd Qu.:6.300   3rd Qu.:3.000   3rd Qu.:4.60   3rd Qu.:1.500                  
 Max.   :7.000   Max.   :3.400   Max.   :5.10   Max.   :1.800                  
-------------------------------------------------------------- 
iris$Species: virginica
  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width          Species  
 Min.   :4.900   Min.   :2.200   Min.   :4.500   Min.   :1.400   setosa    : 0  
 1st Qu.:6.225   1st Qu.:2.800   1st Qu.:5.100   1st Qu.:1.800   versicolor: 0  
 Median :6.500   Median :3.000   Median :5.550   Median :2.000   virginica :50  
 Mean   :6.588   Mean   :2.974   Mean   :5.552   Mean   :2.026                  
 3rd Qu.:6.900   3rd Qu.:3.175   3rd Qu.:5.875   3rd Qu.:2.300                  
 Max.   :7.900   Max.   :3.800   Max.   :6.900   Max.   :2.500     

Es funktioniert tatsächlich und das Ergebnis ist sehr überraschend. Es ist ein Objekt der Klasse, dass entlang Species (sagen wir für jedes von ihnen) die summary jeder Variable berechnet.

Beachten Sie, dass, wenn das erste Argument ein data frame , die abgesetzte Funktion eine Methode für diese Objektklasse haben muss. Zum Beispiel verwenden wir diesen Code mit der mean Funktion, die wir diesen Code haben werden, der überhaupt keinen Sinn hat:

 by(iris, iris$Species, mean)
iris$Species: setosa
[1] NA
------------------------------------------- 
iris$Species: versicolor
[1] NA
------------------------------------------- 
iris$Species: virginica
[1] NA
Warning messages:
1: In mean.default(data[x, , drop = FALSE], ...) :
  argument is not numeric or logical: returning NA
2: In mean.default(data[x, , drop = FALSE], ...) :
  argument is not numeric or logical: returning NA
3: In mean.default(data[x, , drop = FALSE], ...) :
  argument is not numeric or logical: returning NA

AGGREGAT

aggregate kann als eine andere Art der Verwendung tapply wenn wir es so benutzen.

at <- tapply(iris$Sepal.Length , iris$Species , mean)
ag <- aggregate(iris$Sepal.Length , list(iris$Species), mean)

 at
    setosa versicolor  virginica 
     5.006      5.936      6.588 
 ag
     Group.1     x
1     setosa 5.006
2 versicolor 5.936
3  virginica 6.588

Die beiden unmittelbaren Unterschiede sind, dass das zweite Argument von aggregate eine Liste sein muss , während tapply (nicht zwingend) eine Liste sein kann und dass die Ausgabe von aggregate ein tapply ist, während die von tapply ein array .

Die Stärke des aggregate besteht darin, dass es leicht Teilmengen der Daten mit subset und dass es auch Methoden für ts Objekte und formula .

Diese Elemente erleichtern die Arbeit mit diesem tapply in einigen Situationen. Hier einige Beispiele (verfügbar in der Dokumentation):

ag <- aggregate(len ~ ., data = ToothGrowth, mean)

 ag
  supp dose   len
1   OJ  0.5 13.23
2   VC  0.5  7.98
3   OJ  1.0 22.70
4   VC  1.0 16.77
5   OJ  2.0 26.06
6   VC  2.0 26.14

Wir können dasselbe mit tapply aber die Syntax ist etwas schwieriger und die Ausgabe (unter Umständen) weniger lesbar:

att <- tapply(ToothGrowth$len, list(ToothGrowth$dose, ToothGrowth$supp), mean)

 att
       OJ    VC
0.5 13.23  7.98
1   22.70 16.77
2   26.06 26.14

Es gibt andere Zeiten, in denen wir nicht by oder tapply und wir müssen aggregate .

 ag1 <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, mean)

 ag1
  Month    Ozone     Temp
1     5 23.61538 66.73077
2     6 29.44444 78.22222
3     7 59.11538 83.88462
4     8 59.96154 83.96154
5     9 31.44828 76.89655

Wir können das vorherige Ergebnis nicht mit tapply in einem Aufruf erhalten, aber wir müssen den Mittelwert pro Month für jedes Element berechnen und dann kombinieren (beachten Sie auch, dass wir die na.rm = TRUE aufrufen na.rm = TRUE , weil die na.rm = TRUE der aggregate hat standardmäßig die na.action = na.omit ):

ta1 <- tapply(airquality$Ozone, airquality$Month, mean, na.rm = TRUE)
ta2 <- tapply(airquality$Temp, airquality$Month, mean, na.rm = TRUE)

 cbind(ta1, ta2)
       ta1      ta2
5 23.61538 65.54839
6 29.44444 79.10000
7 59.11538 83.90323
8 59.96154 83.96774
9 31.44828 76.90000

während mit by wir einfach nicht erreichen, dass der folgende Funktionsaufruf tatsächlich einen Fehler zurückgibt (aber höchstwahrscheinlich bezieht er sich auf die gelieferte Funktion, mean ):

by(airquality[c("Ozone", "Temp")], airquality$Month, mean, na.rm = TRUE)

Zu anderen Zeiten sind die Ergebnisse gleich und die Unterschiede sind nur in der Klasse (und dann, wie es gezeigt / gedruckt wird und nicht nur - Beispiel, wie es Teilmenge) Objekt:

byagg <- by(airquality[c("Ozone", "Temp")], airquality$Month, summary)
aggagg <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, summary)

Der vorherige Code erreicht das gleiche Ziel und die gleichen Ergebnisse. An einigen Stellen ist das zu verwendende Werkzeug nur eine Frage des persönlichen Geschmacks und der Bedürfnisse; Die vorherigen zwei Objekte haben sehr unterschiedliche Bedürfnisse hinsichtlich der Teilmenge.


Es ist vielleicht erwähnenswert ave ave ist tapply freundliche Cousine. Sie gibt Ergebnisse in einem Formular zurück, das Sie direkt in Ihren Datenrahmen einfügen können.

dfr <- data.frame(a=1:20, f=rep(LETTERS[1:5], each=4))
means <- tapply(dfr$a, dfr$f, mean)
##  A    B    C    D    E 
## 2.5  6.5 10.5 14.5 18.5 

## great, but putting it back in the data frame is another line:

dfr$m <- means[dfr$f]

dfr$m2 <- ave(dfr$a, dfr$f, FUN=mean) # NB argument name FUN is needed!
dfr
##   a f    m   m2
##   1 A  2.5  2.5
##   2 A  2.5  2.5
##   3 A  2.5  2.5
##   4 A  2.5  2.5
##   5 B  6.5  6.5
##   6 B  6.5  6.5
##   7 B  6.5  6.5
##   ...

Es gibt nichts im Basispaket, das für ganze Datenframes wie ave funktioniert (wie by tapply für Datenframes). Aber Sie können es täuschen:

dfr$foo <- ave(1:nrow(dfr), dfr$f, FUN=function(x) {
    x <- dfr[x,]
    sum(x$m*x$m2)
})
dfr
##     a f    m   m2    foo
## 1   1 A  2.5  2.5    25
## 2   2 A  2.5  2.5    25
## 3   3 A  2.5  2.5    25
## ...

Ich habe kürzlich die eher nützliche sweep Funktion entdeckt und hier der Vollständigkeit halber hinzugefügt:

fegen

Die Grundidee besteht darin , ein Array zeilen- oder spaltenweise zu durchlaufen und ein modifiziertes Array zurückzugeben. Ein Beispiel wird dies verdeutlichen (Quelle: datacamp ):

Nehmen wir an, Sie haben eine Matrix und möchten diese spaltenweise standardize :

dataPoints <- matrix(4:15, nrow = 4)

# Find means per column with `apply()`
dataPoints_means <- apply(dataPoints, 2, mean)

# Find standard deviation with `apply()`
dataPoints_sdev <- apply(dataPoints, 2, sd)

# Center the points 
dataPoints_Trans1 <- sweep(dataPoints, 2, dataPoints_means,"-")
print(dataPoints_Trans1)
##      [,1] [,2] [,3]
## [1,] -1.5 -1.5 -1.5
## [2,] -0.5 -0.5 -0.5
## [3,]  0.5  0.5  0.5
## [4,]  1.5  1.5  1.5
# Return the result
dataPoints_Trans1
##      [,1] [,2] [,3]
## [1,] -1.5 -1.5 -1.5
## [2,] -0.5 -0.5 -0.5
## [3,]  0.5  0.5  0.5
## [4,]  1.5  1.5  1.5
# Normalize
dataPoints_Trans2 <- sweep(dataPoints_Trans1, 2, dataPoints_sdev, "/")

# Return the result
dataPoints_Trans2
##            [,1]       [,2]       [,3]
## [1,] -1.1618950 -1.1618950 -1.1618950
## [2,] -0.3872983 -0.3872983 -0.3872983
## [3,]  0.3872983  0.3872983  0.3872983
## [4,]  1.1618950  1.1618950  1.1618950

NB: Für dieses einfache Beispiel kann natürlich das gleiche Ergebnis leichter erreicht werden
apply(dataPoints, 2, scale)


Trotz all der tollen Antworten gibt es 2 weitere Basisfunktionen, die erwähnt werden sollten, die nützliche outer Funktion und die obskure eapply Funktion

äußere

outer ist eine sehr nützliche Funktion, die als banaler verborgen ist. Wenn du die Hilfe für outer liest, heißt es in der Beschreibung:

The outer product of the arrays X and Y is the array A with dimension  
c(dim(X), dim(Y)) where element A[c(arrayindex.x, arrayindex.y)] =   
FUN(X[arrayindex.x], Y[arrayindex.y], ...).

was es so erscheinen lässt, dass dies nur für Dinge der linearen Algebra nützlich ist. Es kann jedoch ähnlich wie mapply , um eine Funktion auf zwei Vektoren von Eingaben anzuwenden. Der Unterschied besteht darin, dass mapply die Funktion auf die ersten beiden Elemente und dann auf die zweiten beiden usw. anwendet, während outer die Funktion auf jede Kombination eines Elements vom ersten Vektor und eins vom zweiten Vektor anwendet. Beispielsweise:

 A<-c(1,3,5,7,9)
 B<-c(0,3,6,9,12)

mapply(FUN=pmax, A, B)

> mapply(FUN=pmax, A, B)
[1]  1  3  6  9 12

outer(A,B, pmax)

 > outer(A,B, pmax)
      [,1] [,2] [,3] [,4] [,5]
 [1,]    1    3    6    9   12
 [2,]    3    3    6    9   12
 [3,]    5    5    6    9   12
 [4,]    7    7    7    9   12
 [5,]    9    9    9    9   12

Ich habe das persönlich benutzt, wenn ich einen Vektor von Werten und einen Vektor von Bedingungen habe und möchte sehen, welche Werte welche Bedingungen erfüllen.

wenden Sie an

eapply ist wie lapply außer dass eine Funktion nicht auf jedes Element in einer Liste eapply wird, sondern eine Funktion auf jedes Element in einer Umgebung eapply wird. Zum Beispiel, wenn Sie eine Liste von benutzerdefinierten Funktionen in der globalen Umgebung finden möchten:

A<-c(1,3,5,7,9)
B<-c(0,3,6,9,12)
C<-list(x=1, y=2)
D<-function(x){x+1}

> eapply(.GlobalEnv, is.function)
$A
[1] FALSE

$B
[1] FALSE

$C
[1] FALSE

$D
[1] TRUE 

Ehrlich gesagt, benutze ich das nicht sehr, aber wenn Sie viele Pakete erstellen oder viele Umgebungen erstellen, kann es nützlich sein.


Von Folie 21 von http://www.slideshare.net/hadley/plyr-one-data-analytic-strategy :

(Hoffentlich ist klar, dass apply entspricht @ Hadleys aaply und aggregate entspricht @ Hadleys ddply etc. Slide 20 der gleichen Slideshare wird klären, wenn Sie es nicht von diesem Bild bekommen.)

(links ist Eingabe, oben wird ausgegeben)





r-faq