根据日期计算数据 table 中的前几行
Counting previous rows in a data table based on date
(抱歉,如果这里的某些术语不适用 - 我来自 SQL 背景,我才刚刚进入 R 世界)
我有一个数据 table,其中包含一系列按日期排序的条目。数据table其中一个字段是分组值,一个是时间值。
数据按组排序(或键控 - 我是 R 的新手,但仍然不确定差异)然后是日期,我想计算,对于每一行,该组中有多少行在当前行之前(包括当前),在给定的时间跨度内。
这是我正在尝试做的一个简化示例,使用 Loblolly 数据集:
正在准备示例数据:
library(lubridate)
library(zoo)
library(data.table)
DT = as.data.table(Loblolly)
DT[,rd := Sys.time() + years(age)]
setkey(DT,Seed,rd)
现在我们有一个按 Seed(组)和 rd(我的日期列)排序的数据 table。我有一个解决方案,可以根据 10 年的时间间隔生成我的计数值 (ct):
DT[,.ct:=mapply(function(x,y) DT[(rd>x-years(10) & rd<=x &Seed==y),.N],DT$rd,DT$Seed)]
这会在此示例数据集中产生所需的结果:
height age Seed rd ct
1: 3.93 3 329 2019-03-01 13:38:00 1
2: 9.34 5 329 2021-03-01 13:38:00 2
3: 26.08 10 329 2026-03-01 13:38:00 3
4: 37.79 15 329 2031-03-01 13:38:00 2
5: 48.31 20 329 2036-03-01 13:38:00 2
6: 56.43 25 329 2041-03-01 13:38:00 2
7: 4.12 3 327 2019-03-01 13:38:00 1
8: 9.92 5 327 2021-03-01 13:38:00 2
9: 26.54 10 327 2026-03-01 13:38:00 3
10: 37.82 15 327 2031-03-01 13:38:00 2
...
...
但是,我需要将其扩展到处理超过 500 万条记录,跨越大约 10,000 个组,运行 需要很长时间才能完成。有没有更快更简单的方法来完成我想做的事情?
这是使用 data.table::foverlaps
的可能解决方案。这里的想法是首先加入 {Sys.time() - years(10), Sys.time() + years(age)}
的整个范围。然后,只计算差异小于 <= 10 年的实例。
DT <- as.data.table(Loblolly)
DT[, c("rd", "rd2") := Sys.time() + years(age)] # create identical columns so foverlaps will work
setkey(DT, Seed, rd, rd2) # key by all for same reason
DT2 <- DT[, .(Seed, rd = rd - years(10), rd2, indx = .I)] # create minum range, create index to store row number
DT[, ct := foverlaps(DT, DT2)[i.rd > rd, .N, by = indx]$N] # run foverlaps, subset by condition and count
head(DT, 10)
# height age Seed rd rd2 ct
# 1: 3.93 3 329 2019-03-01 22:59:02 2019-03-01 22:59:02 1
# 2: 9.34 5 329 2021-03-01 22:59:02 2021-03-01 22:59:02 2
# 3: 26.08 10 329 2026-03-01 22:59:02 2026-03-01 22:59:02 3
# 4: 37.79 15 329 2031-03-01 22:59:02 2031-03-01 22:59:02 2
# 5: 48.31 20 329 2036-03-01 22:59:02 2036-03-01 22:59:02 2
# 6: 56.43 25 329 2041-03-01 22:59:02 2041-03-01 22:59:02 2
# 7: 4.12 3 327 2019-03-01 22:59:02 2019-03-01 22:59:02 1
# 8: 9.92 5 327 2021-03-01 22:59:02 2021-03-01 22:59:02 2
# 9: 26.54 10 327 2026-03-01 22:59:02 2026-03-01 22:59:02 3
# 10: 37.82 15 327 2031-03-01 22:59:02 2031-03-01 22:59:02 2
编辑 2017 年 3 月 17 日:
使用 data.table v1.10.4+,您现在可以结合使用非 uqui 连接和 by = .EACHI
。这基本上允许您在加入时使用 >=
和 <=
而不仅仅是精确加入和 运行 计算(为了避免像您的情况那样的笛卡尔加入)和 return 只是最后的结果。所以在你的具体情况下你可以做
DT[, rd10 := rd - years(10)]
DT[, ct := DT[DT, .N, on = .(Seed, rd <= rd, rd > rd10), by = .EACHI]$N]
(抱歉,如果这里的某些术语不适用 - 我来自 SQL 背景,我才刚刚进入 R 世界)
我有一个数据 table,其中包含一系列按日期排序的条目。数据table其中一个字段是分组值,一个是时间值。 数据按组排序(或键控 - 我是 R 的新手,但仍然不确定差异)然后是日期,我想计算,对于每一行,该组中有多少行在当前行之前(包括当前),在给定的时间跨度内。
这是我正在尝试做的一个简化示例,使用 Loblolly 数据集:
正在准备示例数据:
library(lubridate)
library(zoo)
library(data.table)
DT = as.data.table(Loblolly)
DT[,rd := Sys.time() + years(age)]
setkey(DT,Seed,rd)
现在我们有一个按 Seed(组)和 rd(我的日期列)排序的数据 table。我有一个解决方案,可以根据 10 年的时间间隔生成我的计数值 (ct):
DT[,.ct:=mapply(function(x,y) DT[(rd>x-years(10) & rd<=x &Seed==y),.N],DT$rd,DT$Seed)]
这会在此示例数据集中产生所需的结果:
height age Seed rd ct
1: 3.93 3 329 2019-03-01 13:38:00 1
2: 9.34 5 329 2021-03-01 13:38:00 2
3: 26.08 10 329 2026-03-01 13:38:00 3
4: 37.79 15 329 2031-03-01 13:38:00 2
5: 48.31 20 329 2036-03-01 13:38:00 2
6: 56.43 25 329 2041-03-01 13:38:00 2
7: 4.12 3 327 2019-03-01 13:38:00 1
8: 9.92 5 327 2021-03-01 13:38:00 2
9: 26.54 10 327 2026-03-01 13:38:00 3
10: 37.82 15 327 2031-03-01 13:38:00 2
...
...
但是,我需要将其扩展到处理超过 500 万条记录,跨越大约 10,000 个组,运行 需要很长时间才能完成。有没有更快更简单的方法来完成我想做的事情?
这是使用 data.table::foverlaps
的可能解决方案。这里的想法是首先加入 {Sys.time() - years(10), Sys.time() + years(age)}
的整个范围。然后,只计算差异小于 <= 10 年的实例。
DT <- as.data.table(Loblolly)
DT[, c("rd", "rd2") := Sys.time() + years(age)] # create identical columns so foverlaps will work
setkey(DT, Seed, rd, rd2) # key by all for same reason
DT2 <- DT[, .(Seed, rd = rd - years(10), rd2, indx = .I)] # create minum range, create index to store row number
DT[, ct := foverlaps(DT, DT2)[i.rd > rd, .N, by = indx]$N] # run foverlaps, subset by condition and count
head(DT, 10)
# height age Seed rd rd2 ct
# 1: 3.93 3 329 2019-03-01 22:59:02 2019-03-01 22:59:02 1
# 2: 9.34 5 329 2021-03-01 22:59:02 2021-03-01 22:59:02 2
# 3: 26.08 10 329 2026-03-01 22:59:02 2026-03-01 22:59:02 3
# 4: 37.79 15 329 2031-03-01 22:59:02 2031-03-01 22:59:02 2
# 5: 48.31 20 329 2036-03-01 22:59:02 2036-03-01 22:59:02 2
# 6: 56.43 25 329 2041-03-01 22:59:02 2041-03-01 22:59:02 2
# 7: 4.12 3 327 2019-03-01 22:59:02 2019-03-01 22:59:02 1
# 8: 9.92 5 327 2021-03-01 22:59:02 2021-03-01 22:59:02 2
# 9: 26.54 10 327 2026-03-01 22:59:02 2026-03-01 22:59:02 3
# 10: 37.82 15 327 2031-03-01 22:59:02 2031-03-01 22:59:02 2
编辑 2017 年 3 月 17 日:
使用 data.table v1.10.4+,您现在可以结合使用非 uqui 连接和 by = .EACHI
。这基本上允许您在加入时使用 >=
和 <=
而不仅仅是精确加入和 运行 计算(为了避免像您的情况那样的笛卡尔加入)和 return 只是最后的结果。所以在你的具体情况下你可以做
DT[, rd10 := rd - years(10)]
DT[, ct := DT[DT, .N, on = .(Seed, rd <= rd, rd > rd10), by = .EACHI]$N]