R4DS习题5.6.7 Q4:mutate与summarise能否互换的技术疑问
嘿,我来帮你理清楚这个问题!首先得明确:mutate和summarise根本不是可以互换的函数,它们的定位完全不同——这也是为什么参考代码里用了mutate,不过其实也有不用mutate的写法,只是可读性差一些。
先拆解题目需求:我们需要先判断每个航班是否取消,再按日期分组,计算当天取消航班的比例,以及平均延误时间。
为什么参考代码要用mutate?
mutate的核心作用是为每一行数据添加/修改列,保留原数据的行数。在这里,我们需要给每个航班(每一行)标记一个cancelled状态(TRUE/FALSE),这个是逐行判断的操作,summarise做不到——因为summarise的本质是对分组后的数据做聚合,输出的行数等于分组数,它不会保留每一行的细节。
用mutate先把cancelled列做出来,后续的summarise逻辑就非常清晰:直接对cancelled列取均值(因为TRUE会被当作1,FALSE当作0,均值就是比例),任何人看代码都能立刻明白你在做什么。
能不能只用summarise实现?
其实可以,但写法会更绕,而且可读性大打折扣。比如你可以把判断取消的逻辑直接嵌入到summarise的聚合计算里:
flights %>% group_by(year, month, day) %>% summarise( prop_cancelled = sum(is.na(arr_delay) | is.na(dep_delay)) / n(), avg_dep_delay = mean(dep_delay, na.rm = TRUE) )
这里我们直接计算当天取消的航班数(sum(...))除以当天总航班数(n()),得到取消比例,全程没用到mutate。但这种写法的问题在于,判断取消的逻辑被藏在了聚合计算里,不如先建cancelled列那么直观,尤其是当你后续还要基于这个取消状态做更多分析时,mutate的方式会更灵活。
再明确下mutate和summarise的核心区别
- mutate:不管分不分组,都会保留原数据的行数,是给每一行新增信息,属于「行级操作」
- summarise:分组后把每组压缩成一行,是对每组做汇总统计,属于「组级聚合操作」
所以两者完全不是一个层面的函数,不存在“互换”的说法——只是在这个特定场景下,你可以把mutate的行级判断逻辑,直接转化为summarise里的组级聚合计算,从而绕开mutate,但这绝不是互换。
内容的提问来源于stack exchange,提问作者Lee

