Da habe ich festgestellt, dass (die sehr ausgezeichneten) Antworten dieses Beitrags fehlen by
und aggregate
Erklärungen. Hier ist mein Beitrag.
DURCH
Die by
in der Dokumentation angegebene Funktion kann jedoch als "Wrapper" für tapply
. Die Kraft von by
entsteht, wenn wir eine Aufgabe berechnen wollen, tapply
die nicht erledigt werden 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 drucken ct
und cb
"im Wesentlichen" die gleichen Ergebnisse erzielen und die einzigen Unterschiede darin bestehen, wie sie angezeigt werden und in welchen unterschiedlichen class
Attributen by
für cb
und array
für ct
.
Wie ich schon sagte, by
entsteht die Kraft von , wenn wir nicht nutzen können 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 iris
entlang des Faktors berechnen Species
": aber R kann das einfach nicht, weil es nicht weiß, wie es zu handhaben ist.
Mit der by
Funktion R wird eine bestimmte Methode für die data frame
Klasse ausgelöst und die summary
Funktion dann auch dann funktionieren gelassen , wenn die Länge des ersten Arguments (und auch der Typ) unterschiedlich sind.
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 in der Tat und das Ergebnis ist sehr überraschend. Es ist ein Objekt der Klasse by
, das zusammen Species
(etwa für jedes von ihnen) das summary
von jeder Variablen berechnet .
Beachten Sie, dass data frame
die ausgelöste Funktion eine Methode für diese Objektklasse haben muss , wenn das erste Argument a ist . Zum Beispiel verwenden wir diesen Code mit der mean
Funktion, dass wir diesen Code haben, 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 angesehen werden, tapply
wenn wir es so verwenden.
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 der aggregate
muss eine Liste sein , während tapply
kann (nicht zwingend) eine Liste sein und dass der Ausgang aggregate
ist ein Datenrahmen , während der eine von tapply
einem ist array
.
Die Stärke von aggregate
ist, dass es leicht Teilmengen der Daten mit subset
Argumenten verarbeiten kann und dass es Methoden für ts
Objekte und formula
auch hat.
Diese Elemente aggregate
erleichtern tapply
in einigen Situationen die Arbeit damit . Hier einige Beispiele (in der Dokumentation verfügbar):
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 erreichen, tapply
aber die Syntax ist etwas schwieriger und die Ausgabe (unter bestimmten 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 verwenden können by
oder tapply
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
einem Aufruf erhalten, aber wir müssen den Mittelwert Month
für jedes Element berechnen und dann kombinieren (beachten Sie auch, dass wir das aufrufen müssen na.rm = TRUE
, da die formula
Methoden der aggregate
Funktion standardmäßig das haben 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 by
wir dies einfach nicht erreichen können, gibt der folgende Funktionsaufruf einen Fehler zurück (aber höchstwahrscheinlich hängt er mit der bereitgestellten Funktion zusammen mean
):
by(airquality[c("Ozone", "Temp")], airquality$Month, mean, na.rm = TRUE)
In anderen Fällen sind die Ergebnisse gleich und die Unterschiede liegen nur in der Klasse (und dann, wie es angezeigt / gedruckt wird und nicht nur - Beispiel, wie man es untergibt) 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 Tool nur eine Frage des persönlichen Geschmacks und der persönlichen Bedürfnisse. Die beiden vorherigen Objekte haben sehr unterschiedliche Anforderungen an die Teilmenge.
*apply()
undby
. plyr (zumindest für mich) scheint viel konsistenter zu sein, da ich immer genau weiß, welches Datenformat es erwartet und was es genau ausspucken wird. Das erspart mir viel Ärger.