R中管道与$符号处理大数据集的性能差异及相关疑问
R语言大数据处理疑问解答
背景情况
处理一个包含570万+行的数据框df,列名如下:
[1] "ride_id" "rideable_type" "started_at" "ended_at" "member_casual" "date" [7] "month" "day" "year" "day_of_week" "ride_length"
通过以下代码做聚合统计:
aggregate(ride_length ~ member_casual + day_of_week, data = df, FUN = sum)
得到的result_1中day_of_week顺序混乱,想要调整为Sun、Mon至Sat的顺序,尝试了两种方法:
- 管道写法(运行1.5小时未完成,被迫中断):
df$day_of_week <- df %>% ordered(day_of_week, levels = c("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"))
- 非管道写法(耗时不到1秒):
df$day_of_week <- ordered(df$day_of_week, levels=c("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"))
问题解答
1. 是否有人遇到过类似问题?性能差异的原因是什么?
肯定有不少人碰到过这种情况。核心原因是你用管道的写法写错了,不是管道本身慢。
你写的df %>% ordered(day_of_week, ...)等价于ordered(df, day_of_week, ...)——这相当于把整个570万行的数据框传给ordered()当第一个参数,但ordered()原本只需要一列向量。函数内部会尝试把整个数据框转换成有序因子,这必然会巨慢,甚至可能触发内存溢出。
正确的管道写法应该先提取目标列,再转换:
df$day_of_week <- df %>% pull(day_of_week) %>% ordered(levels = c("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"))
这么写的话,性能和非管道写法几乎没区别。
2. 若该问题由管道导致,是否意味着管道有适用与不适用的场景?
管道本身没有性能问题,它只是一种优化代码可读性的工具,让操作逻辑更符合从左到右的阅读顺序。但确实有适合和不适合的场景:
- 适合场景:多步骤数据转换(比如筛选→分组→聚合→排序),用管道能避免嵌套函数,代码更清晰。
- 不适合场景:
- 单一步骤的简单操作(比如这次只需要提取一列转有序因子),管道反而多此一举。
- 对性能极致敏感的超大规模数据操作,虽然管道本身开销可以忽略,但如果写法失误(像这次传了整个数据框),会导致灾难级性能问题。
3. 一般而言,$符号的用途是什么?何时应该使用它?
$是R里提取数据框(或列表)元素的快捷符号:
- 作用:从数据框/列表中按名称提取单个列(或元素),返回向量(数据框列的情况)。
- 使用场景:
- 明确知道要提取的列名,且列名不含特殊字符(空格、标点等)时,用
$最方便,比如df$day_of_week。
- 明确知道要提取的列名,且列名不含特殊字符(空格、标点等)时,用
- 不适合场景:
- 列名存放在变量里时(比如
col_name <- "day_of_week",df$col_name会找名为col_name的列,而非变量指向的列,应该用df[[col_name]])。 - 列名有特殊字符时(比如列名是
day of week,$无法识别,得用df[["day of week"]])。
- 列名存放在变量里时(比如
4. 得到排序后的聚合结果result_2后,原始df的行顺序并未改变,这是为什么?若要将原始df按result_2的顺序排列,该如何操作?
原因:
aggregate()生成的是全新的聚合结果数据框,它只是修改了结果里day_of_week的有序因子属性,让聚合结果按指定顺序排列,但不会对原始数据框df做任何修改——两者是完全独立的对象。
操作方法:
要让原始df按result_2的顺序(member_casual分组后,day_of_week按Sun→Sat排序)排列:
- 先确保
df$day_of_week已经是有序因子(用你那行高效的非管道代码即可); - 用
dplyr包的arrange()排序:
library(dplyr) df_sorted <- df %>% arrange(member_casual, day_of_week)
或者用基础R的order():
df_sorted <- df[order(df$member_casual, df$day_of_week), ]
内容的提问来源于stack exchange,提问作者Abooboo
相关产品推荐
相关产品推荐

