You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何data.table过滤观测数>20的分组比dplyr慢?如何优化?

data.table写法比dplyr慢7倍的原因及优化方案

拥有一个含850万行的数据集,计划将大部分代码从dplyr迁移至data.table以提升效率。当前使用的data.table写法为:

df <- df[, .SD[.N > 20], by = cols]

此前使用的dplyr等效写法为:

df <- df %>% 
  group_by(across(all_of(cols))) %>%
  filter(n() > 20) %>%
  ungroup()

尽管操作前df已是data.table对象,但该data.table写法的耗时是dplyr的7倍。请问出现这种情况的原因是什么?如何改写data.table代码以提升速度?

为什么当前data.table写法更慢?

  • 核心问题出在.SD[.N > 20]的执行逻辑:data.table会为每个分组生成完整的.SD(即该分组的所有行数据副本),之后才判断.N > 20并保留符合条件的分组。这种处理方式会产生大量不必要的内存复制,在850万行的大规模数据集下,开销被放大,导致速度变慢。
  • 反观dplyr的实现:它在处理data.table后端时,内部会先计算所有分组的大小,直接标记出符合条件的分组,再提取对应行,全程跳过了创建完整.SD的步骤,因此效率更高。

优化后的data.table写法

方法1:条件触发.SD生成

df <- df[, if (.N > 20) .SD, by = cols]

这种写法会先判断分组大小,只有当.N > 20时才会生成.SD并保留该分组,避免了为不符合条件的分组做无用的内存复制,性能会有明显提升。

方法2:直接提取行索引(性能最优)

# 获取符合条件的分组对应的所有行索引
keep_rows <- df[, .I[.N > 20], by = cols]$V1
# 通过索引快速提取目标行
df <- df[keep_rows]

这种方式完全绕开了.SD的创建,利用.I直接获取符合条件的行号,再通过data.table的原生索引机制提取行,是处理大规模数据集时性能最优的写法。

内容的提问来源于stack exchange,提问作者Alberto Agudo Dominguez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 14:02:36