自从我意识到这篇文章的(非常出色的)答案缺少by
和aggregate
解释。这是我的贡献。
通过
by
但是,如文档中所述,该功能可以用作的“包装器” tapply
。by
当我们要计算tapply
无法处理的任务时,就会产生力量。此代码是一个示例:
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
如果我们打印这两个对象,ct
并且cb
,我们“基本上”具有相同的结果和唯一的差别是它们是如何显示和不同的class
分别的属性,by
对于cb
和array
为ct
。
就像我说过的那样,by
当我们不能使用时,力量就会产生tapply
。以下代码是一个示例:
tapply(iris, iris$Species, summary )
Error in tapply(iris, iris$Species, summary) :
arguments must have same length
R说参数必须具有相同的长度,比如说“我们要计算沿因子summary
的所有变量的iris
和Species
”:但是R不能这样做,因为它不知道如何处理。
使用by
函数R调度data frame
类的特定方法,然后summary
即使第一个参数的长度(和类型也不同)也可以让函数正常工作。
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
它确实有效,并且结果令人惊讶。这是一个类的对象,by
它Species
(针对summary
每个变量)计算每个变量的。
请注意,如果第一个参数是a data frame
,则分派的函数必须具有用于该类对象的方法。例如,我们将此代码与mean
函数一起使用,我们将获得完全没有意义的代码:
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
骨料
aggregate
tapply
如果我们以这种方式使用它,可以将其视为另一种不同的使用方法。
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
两者的直接区别是,的第二个参数aggregate
必须是一个列表,而tapply
可以(不是必须的)是一个列表,并且的输出aggregate
是一个数据帧,而其中的一个tapply
是一个array
。
它的强大之aggregate
处在于它可以轻松地处理带有subset
参数的数据子集,并且具有用于ts
对象的方法formula
。
这些元素在某些情况下使其aggregate
更易于使用tapply
。以下是一些示例(可在文档中找到):
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
我们可以用以下方法实现相同的功能,tapply
但是语法稍微难一些,并且输出(在某些情况下)可读性较低:
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
在其他时候,我们不能使用by
或tapply
,而必须使用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
我们无法tapply
在一次调用中获得先前的结果,但必须计算Month
每个元素的平均值,然后将它们组合在一起(还请注意,我们必须调用na.rm = TRUE
,因为formula
该aggregate
函数的方法默认具有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
而by
实际上我们无法实现以下功能调用返回错误(但很可能与所提供的功能有关mean
):
by(airquality[c("Ozone", "Temp")], airquality$Month, mean, na.rm = TRUE)
其他时候,结果是相同的,不同之处仅在于类(然后是如何显示/打印,而不仅是-例如,如何对其进行子集化)对象:
byagg <- by(airquality[c("Ozone", "Temp")], airquality$Month, summary)
aggagg <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, summary)
先前的代码实现了相同的目标和结果,在某些时候,使用哪种工具只是个人喜好和需求的问题。就子集而言,前两个对象有非常不同的需求。
*apply()
和by
。plyr(至少对我而言)似乎更加一致,因为我始终确切知道它期望的数据格式以及它要吐出的数据。那省了我很多麻烦。