r - data.table:子集并查找每行的累积乘积
问题描述
我有一个包含三列的简单数据框:ID、日期和值。现在,我想在此过程之后根据这三列计算一个新值 newValue:
- 对于每一行(即,对于每一对 (id, date))
- 对于范围内的所有日期(日期,日期 + 2),我想找到该 id 值的累积乘积(然后减去 1)
下面带有虚构数字的简单示例进行计算:
df <- data.frame("id"=rep(1:10, 5),
"date"=c(rep(2000, 10), rep(2001, 10), rep(2002, 10), rep(2003, 10), rep(2004, 10)),
"value"=c(rep(1, 10), rep(2, 10), rep(3, 10), rep(4, 10), rep(5, 10)))
df$newValue <- 1 #initialize
for(idx in 1:dim(df)[1]) {
id <- df[idx, "id"]
lower <- df[idx, "date"]
upper <- lower + 3
df[idx, "newValue"] <- prod(df[(df$id == id) & (df$date >= lower) & (df$date < upper), ]$value + 1) - 1
}
这给了我输出(为简单起见,我对其进行了注释):
id date value newValue
1 1 2000 1 23 (= (1+1) * (2+1) * (3+1) - 1 = 23)
2 2 2000 1 23 (= (1+1) * (2+1) * (3+1) - 1 = 23)
....
12 2 2001 2 59 (= (2+1) * (3+1) * (4+1) - 1 = 59)
....
22 2 2002 3 119 (= (3+1) * (4+1) * (5+1) - 1 = 119)
....
但是,我的最终数据帧有 +100 万行,因此上面的代码非常耗时且效率低下。
有没有办法加快速度,也许使用 data.table?请注意,每个 id 可能有不同的行数,所以我为什么要明确设置子集。
解决方案
library(data.table)
library(purrr)
setDT(df)[, newValue := map_dbl(date, ~prod(value[between(date, .x, .x + 2)] + 1) - 1), by = id]
给出(仅显示id = 1
):
id date value newValue
1: 1 2000 1 23
2: 1 2001 2 59
3: 1 2002 3 119
4: 1 2003 4 29
5: 1 2004 5 5
更新:
因为每个date
最多一次,id
所以这应该更有效:
df <- setDT(df)[order(id, date)]
df[,
newValue := map2_dbl(
date, map(seq_len(.N), ~.x:min(.x+2, .N)),
~prod(value[.y][between(date[.y], .x, .x + 2)] + 1) - 1
),
by = id
]
如果您想要其他数字2
,则可以创建一些变量date_range
并替换2
为date_range
推荐阅读
- javascript - 我可以从 Realm React Native 中的嵌套对象架构上的关系方法访问具有循环引用的属性对象吗
- cpu-architecture - 用于可忽略负载的 Risc-V 扩展
- python - Python 数据框的堆积面积图
- php - 在 PHP 中使用简单的 html dom 抓取数据奇数属性
- r - 在R闪亮的navbarMenu的所有tabPanels中插入一个通用文本/框
- javascript - 样式表未使用 node.js 应用到我的本地服务器
- bazel - Bazel `repository_rule` 如何调整 `label_flag` (或者更一般的 `config_setting` )?
- javascript - Jquery .last() 等价于 Javascript
- python - 为什么使用 pytesseract 从图像中读取文本不起作用?
- github - cURL 在 GitHub 操作中失败