Depuis que je me suis rendu compte que (les très excellentes) réponses de ce post manquent byet d' aggregateexplications. Voici ma contribution.
PAR
La byfonction, comme indiqué dans la documentation, peut cependant être un "wrapper" pour tapply. La puissance de bysurgit lorsque nous voulons calculer une tâche qui tapplyne peut pas être gérée. Un exemple est ce 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 
Si nous imprimons ces deux objets, ctet cb, nous avons "essentiellement" les mêmes résultats et les seules différences sont dans la façon dont ils sont affichés et les différents classattributs, respectivement bypour cbet arraypour ct.
Comme je l'ai dit, le pouvoir de bysurgit lorsque nous ne pouvons pas utiliser tapply; le code suivant en est un exemple:
 tapply(iris, iris$Species, summary )
Error in tapply(iris, iris$Species, summary) : 
  arguments must have same length
R dit que les arguments doivent avoir les mêmes longueurs, disons "nous voulons calculer la summaryvariable de iristout le long du facteur Species": mais R ne peut tout simplement pas faire cela car il ne sait pas comment gérer.
Avec la byfonction R, distribuez une méthode spécifique pour la data frameclasse, puis laissez la summaryfonction fonctionner même si la longueur du premier argument (et le type aussi) est différente.
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     
cela fonctionne en effet et le résultat est très surprenant. C'est un objet de classe byqui le long Species(disons, pour chacun d'eux) calcule le summaryde chaque variable.
Notez que si le premier argument est un data frame, la fonction distribuée doit avoir une méthode pour cette classe d'objets. Par exemple, si nous utilisons ce code avec la meanfonction, nous aurons ce code qui n'a aucun sens:
 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
AGRÉGAT
aggregatepeut être considéré comme un autre mode d'utilisation différent tapplysi nous l'utilisons de cette manière.
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
Les deux différences immédiates sont que le deuxième argument de aggregate doit être une liste tandis que tapply peut (non obligatoire) être une liste et que la sortie de aggregateest une trame de données tandis que celle de tapplyest un array.
La puissance de aggregateest qu'il peut gérer facilement des sous-ensembles de données avec subsetargument et qu'il a des méthodes pour les tsobjets et formulaaussi.
Ces éléments aggregatefacilitent le travail avec cela tapplydans certaines situations. Voici quelques exemples (disponibles dans la documentation):
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
Nous pouvons obtenir la même chose avec tapplymais la syntaxe est légèrement plus difficile et la sortie (dans certaines circonstances) moins lisible:
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
Il y a d'autres moments où nous ne pouvons pas utiliser byou tapplyet nous devons utiliser 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
Nous ne pouvons pas obtenir le résultat précédent avec tapplyen un seul appel mais nous devons calculer la moyenne Monthpour chaque élément et ensuite les combiner (notez également que nous devons appeler le na.rm = TRUE, car les formulaméthodes de la aggregatefonction ont par défaut le 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
alors qu'avec bynous, nous ne pouvons tout simplement pas y parvenir en fait, l'appel de fonction suivant renvoie une erreur (mais il est très probablement lié à la fonction fournie mean):
by(airquality[c("Ozone", "Temp")], airquality$Month, mean, na.rm = TRUE)
D'autres fois, les résultats sont les mêmes et les différences ne concernent que la classe (et ensuite comment elle est affichée / imprimée et pas seulement - par exemple, comment la sous-définir).
byagg <- by(airquality[c("Ozone", "Temp")], airquality$Month, summary)
aggagg <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, summary)
Le code précédent atteint le même objectif et les mêmes résultats, à certains moments, quel outil utiliser n'est qu'une question de goûts et de besoins personnels; les deux objets précédents ont des besoins très différents en termes de sous-ensemble.
               
              
*apply()etby. plyr (du moins pour moi) semble beaucoup plus cohérent dans la mesure où je sais toujours exactement quel format de données il attend et exactement ce qu'il va cracher. Cela m'évite beaucoup de tracas.