9.6 拆分—应用—合并(Split-Apply-Combine)
在研究数据时一个很常见的问题是:如何对那些已被分成不同小组的变量进行统计计算。以下是经典的道路交通安全游戏Frogger的得分情况:
(frogger_scores <- data.frame(
player = rep(c("Tom", "Dick", "Harry"), times = c(2, 5, 3)),
score = round(rlnorm(10, 8), -1)
))
## player score
## 1 Tom 2250
## 2 Tom 1510
## 3 Dick 1700
## 4 Dick 410
## 5 Dick 3720
## 6 Dick 1510
## 7 Dick 4500
## 8 Harry 2160
## 9 Harry 5070
## 10 Harry 2930
计算每个玩家的平均得分需要三个步骤。首先,我们按玩家来分开数据集:
(scores_by_player <- with(
frogger_scores,
split(score, player)
))
## $Dick
## [1] 1700 410 3720 1510 4500
##
## $Harry
## [1] 2160 5070 2930
##
## $Tom
## [1] 2250 1510
然后,我们将(mean
)函数应用于每个元素:
(list_of_means_by_player <- lapply(scores_by_player, mean))
## $Dick
## [1] 2368
##
## $Harry
## [1] 3387
##
## $Tom
## [1] 1880
最后,我们把结果合并到单个向量中:
(mean_by_player <- unlist(list_of_means_by_player))
## Dick Harry Tom
## 2368 3387 1880
如果使用vapply
或sapply
,最后两个步骤可简化成一步,但拆分-应用-合并是如此常用,所以我们必须简化它。方法就是使用tapply
函数,它能一次执行所有的三个步骤,一气呵成:
with(frogger_scores, tapply(score, player, mean))
## Dick Harry Tom
## 2368 3387 1880
还有几个其他的tapply
包装函数,例如by
和aggregate
。它们的功能相同,但接口稍有不同。
提示
SQL的粉丝可能会注意到,拆分-应用-合并其实就是
GROUP BY
操作。