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

如何用data.table实现按用户累计分类事件计数的虚拟变量转换?

问题描述

我有一个名为current的data.table,包含3个用户的多条记录,每条记录包含person.id、分类类型的event列以及date列,且已按时间顺序排序。需要将其转换为名为desired的表:为每行新增各事件类型的列,记录该用户截至当前行时遇到对应事件的累计次数。此外原数据集还有其他需要保留到结果中的列。之前用循环实现,但面对百万级数据时效率极差,求高效数据处理方法。

附代码示例(修正原代码语法错误):

library(data.table)

current <- data.table(
  person.id = c(1,2,3,1,2,3),
  event = factor(c("categoryA", "categoryA", "categoryD", 
                   "categoryA", "categoryC", "categoryB")),
  date = as.Date(c("2020-01-01", "2020-03-23", "2020-09-09", 
                   "2020-12-30", "2021-06-03", "2022-03-22"))
)

# 期望的转换操作
desired <- current[, ...]

print(current)
print(desired)

原输出示例:

person.id     event       date
1:         1 categoryA 2020-01-01
2:         2 categoryA 2020-03-23
3:         3 categoryD 2020-09-09
4:         1 categoryA 2020-12-30
5:         2 categoryC 2021-06-03
6:         3 categoryB 2022-03-22

   person.id     event       date categoryA categoryB categoryC categoryD
1:         1 categoryA 2020-01-01         1         0         0         0
2:         2 categoryA 2020-03-23         1         0         0         0
3:         3 categoryD 2020-09-09         0         0         0         1
4:         1 categoryA 2020-12-30         2         0         0         0
5:         2 categoryC 2021-06-03         1         0         1         0
6:         3 categoryB 2022-03-22         0         1         0         1
高效解决方案

利用data.table的分组累积计算特性,直接在原表上批量生成各事件的累计计数列,完全避免循环,适合百万级数据:

library(data.table)

# 修正后的原始数据
current <- data.table(
  person.id = c(1,2,3,1,2,3),
  event = factor(c("categoryA", "categoryA", "categoryD", 
                   "categoryA", "categoryC", "categoryB")),
  date = as.Date(c("2020-01-01", "2020-03-23", "2020-09-09", 
                   "2020-12-30", "2021-06-03", "2022-03-22"))
)

# 获取所有事件类型
event_types <- levels(current$event)

# 按person.id分组,为每个事件类型生成累计计数列
current[, (event_types) := lapply(event_types, function(type) {
  cumsum(event == type)
}), by = person.id]

# 此时current就是期望的desired表
print(current)

原理说明

  1. 分组隔离:by = person.id确保每个用户的累计计数独立计算,不会跨用户混淆。
  2. 批量列生成:(event_types)用变量名批量创建新列,无需手动逐个编写事件列名。
  3. 高效向量运算:cumsum(event == type)对分组内数据执行向量式累积求和,data.table底层优化过的运算逻辑比循环快几个数量级。
  4. 自动保留原列:所有原始列(包括其他需要保留的列)都会被完整保留,无需额外处理。

运行结果与示例中的desired表完全一致。

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 09:07:24