Vì tôi nhận ra rằng (những câu trả lời rất xuất sắc) của bài đăng này thiếu by
và aggregate
giải thích. Đây là đóng góp của tôi.
BỞI
Các by
chức năng, như đã nêu trong tài liệu có thể được mặc dù, như là một "wrapper" cho tapply
. Sức mạnh by
phát sinh khi chúng ta muốn tính toán một nhiệm vụ tapply
không thể xử lý. Một ví dụ là mã này:
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
Nếu chúng ta in hai đối tượng này, ct
và cb
, "về cơ bản" chúng ta có cùng kết quả và sự khác biệt duy nhất là cách chúng được hiển thị và các class
thuộc tính khác nhau , tương ứng by
cho cb
và array
choct
.
Như tôi đã nói, sức mạnh by
phát sinh khi chúng ta không thể sử dụng tapply
; đoạn mã sau đây là một ví dụ:
tapply(iris, iris$Species, summary )
Error in tapply(iris, iris$Species, summary) :
arguments must have same length
R nói rằng các đối số phải có cùng độ dài, nói rằng "chúng tôi muốn tính toán summary
tất cả các biến iris
theo yếu tố Species
": nhưng R không thể làm điều đó vì không biết cách xử lý.
Với by
hàm R gửi một phương thức cụ thể cho data frame
lớp và sau đó cho phép summary
hàm hoạt động ngay cả khi độ dài của đối số đầu tiên (và kiểu cũng vậy) khác nhau.
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
Nó thực sự hoạt động và kết quả là rất đáng ngạc nhiên. Nó là một đối tượng của lớp by
mà theo đó Species
(giả sử cho mỗi trong số chúng) tính toán summary
của từng biến.
Lưu ý rằng nếu đối số đầu tiên là a data frame
, hàm được gửi phải có một phương thức cho lớp đối tượng đó. Ví dụ: chúng tôi sử dụng mã này với mean
chức năng, chúng tôi sẽ có mã này hoàn toàn không có ý nghĩa:
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
ĐỒNG Ý
aggregate
có thể được coi là một cách sử dụng khác tapply
nếu chúng ta sử dụng nó theo cách như vậy.
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
Hai điểm khác biệt trước mắt là đối số thứ hai aggregate
phải là một danh sách trong khi tapply
có thể (không bắt buộc) là một danh sách và đầu ra của aggregate
là một khung dữ liệu trong khi đối số tapply
là mộtarray
.
Sức mạnh của aggregate
nó là nó có thể xử lý các tập hợp con dữ liệu dễ dàng bằng subset
đối số và nó cũng có các phương thức cho ts
các đối tượng formula
.
Những yếu tố này làm cho aggregate
dễ dàng hơn để làm việc với điều đó tapply
trong một số tình huống. Dưới đây là một số ví dụ (có sẵn trong tài liệu):
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
Chúng ta có thể đạt được điều tương tự với tapply
nhưng cú pháp hơi khó hơn và đầu ra (trong một số trường hợp) ít đọc hơn:
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
Có những lúc khác chúng ta không thể sử dụng by
hoặc tapply
chúng ta phải sử dụng 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
Chúng ta không thể có được kết quả trước đó tapply
trong một cuộc gọi nhưng chúng ta phải tính giá trị trung bình Month
cho từng phần tử và sau đó kết hợp chúng (cũng lưu ý rằng chúng ta phải gọi na.rm = TRUE
, bởi vì các formula
phương thức của aggregate
hàm theo mặc định là 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
trong khi với by
chúng ta không thể đạt được điều đó trong thực tế, lệnh gọi hàm sau trả về lỗi (nhưng rất có thể nó liên quan đến hàm được cung cấp, mean
):
by(airquality[c("Ozone", "Temp")], airquality$Month, mean, na.rm = TRUE)
Mặt khác, các kết quả là như nhau và sự khác biệt chỉ là trong lớp (và sau đó cách nó được hiển thị / in và không chỉ - ví dụ, làm thế nào để đặt lại nó) đối tượng:
byagg <- by(airquality[c("Ozone", "Temp")], airquality$Month, summary)
aggagg <- aggregate(cbind(Ozone, Temp) ~ Month, data = airquality, summary)
Mã trước đó đạt được cùng một mục tiêu và kết quả, tại một số điểm, công cụ nào để sử dụng chỉ là vấn đề sở thích và nhu cầu cá nhân; hai đối tượng trước có nhu cầu rất khác nhau về mặt đặt lại.
*apply()
vàby
. plyr (ít nhất là với tôi) có vẻ phù hợp hơn nhiều ở chỗ tôi luôn biết chính xác định dạng dữ liệu mà nó mong đợi và chính xác những gì nó sẽ nhổ ra. Điều đó giúp tôi tiết kiệm rất nhiều rắc rối.