这是一个有趣的问题。如果我理解正确,如果前一个组有Status == 1 并且当前组有Status == 0,则OP 会要求在Status 的每组连续值之间插入额外的行。此外,我了解 Status == 1 连续填充缺失的日期是不要求的。
所以这里有两种不同的data.table 方法:
1。对每个 Status == 0 组进行分组和附加行
此解决方案从Matt Dowle's answer 借用到Get the last row of a previous group in data.table(参见here 了解另一个用例)。
它在Status(使用rleid())中创建0/1值的连续条纹组。对于每个组,检查是否需要插入行。如果是这样,则将附加行添加到当前组的行之前(使用rbind())。
library(data.table)
options(datatable.print.class = TRUE)
dt[, timestamp := as.IDate(timestamp, "%d-%m-%Y")] # coerce character date to numeric
dt[, grp := rleid(Status)] # create groups of consecutive values of Status
dt[, new := ""] # just for test & demonstration
pg <- first(dt) # initialise storage of last row of previous group
dt[, {
if (first(timestamp) - pg$timestamp > 1L & pg$Status == 1L) {
# if there is a gap and Status switches from 1 to 0 the fill the gap
add <- .(timestamp = seq(pg$timestamp + 1L, first(timestamp) - 1L, by = 1L), Status = 1L, new = "*")
} else {
# no gap to fill
add <- .SD[0L]
}
pg <- last(.SD) # remember last row
rbind(add, .SD) # prepend additional rows
}, by = grp][, grp := NULL][] # remove grouping variable
timestamp Status new
<IDat> <int> <char>
1: 2020-01-05 0
2: 2020-01-06 0
3: 2020-01-07 1
4: 2020-01-08 1
5: 2020-01-09 1
6: 2020-01-10 1 *
7: 2020-01-11 0
8: 2020-01-13 1
9: 2020-01-14 0
10: 2020-01-16 1
11: 2020-01-17 1
12: 2020-01-18 1 *
13: 2020-01-19 1 *
14: 2020-01-20 0
请注意,已使用增强数据集(见下文)以进行更彻底的测试。此外,添加列new 只是为了演示插入行的位置。
2。识别间隙、创建缺失的行、追加和重新排序
这种方法是不同的。它识别要填补的空白,创建缺失的行,将它们附加到原始数据集,并按时间戳对行重新排序:
library(data.table)
options(datatable.print.class = TRUE)
library(magrittr) # piping used to improve readability
dt[, timestamp := as.IDate(timestamp, "%d-%m-%Y")] # coerce character date to numeric
lapply(
dt[, .I[timestamp - shift(timestamp, fill = first(timestamp)) > 1L & shift(Status) == 1 & Status == 0]],
function(i) dt[, .(timestamp = seq(timestamp[i - 1L] + 1L, timestamp[i] - 1L, by = 1L), Status = 1L)]
) %>%
c(list(dt)) %>%
rbindlist() %>%
.[order(timestamp)]
timestamp Status
<IDat> <int>
1: 2020-01-05 0
2: 2020-01-06 0
3: 2020-01-07 1
4: 2020-01-08 1
5: 2020-01-09 1
6: 2020-01-10 1
7: 2020-01-11 0
8: 2020-01-13 1
9: 2020-01-14 0
10: 2020-01-16 1
11: 2020-01-17 1
12: 2020-01-18 1
13: 2020-01-19 1
14: 2020-01-20 0
表达式
dt[, .I[timestamp - shift(timestamp, fill = first(timestamp)) > 1L & shift(Status) == 1 & Status == 0]]
通过返回原始数据集dt 中的索引来标识要填补的空白,在这些空白处需要在之前插入其他行。
[1] 6 11
因此,需要分别在第 5 行到第 6 行和第 10 行到第 11 行之间插入额外的行。
3。数据
已扩展数据集以进行更彻底的测试。
dt <- fread(
"timestamp Status
05-01-2020 0
06-01-2020 0
07-01-2020 1
08-01-2020 1
09-01-2020 1
11-01-2020 0
13-01-2020 1
14-01-2020 0
16-01-2020 1
17-01-2020 1
20-01-2020 0")
请注意,到目前为止发布的所有解决方案都假定dt 是通过增加timestamp 来排序的。如果没有,可以通过
setorder(dt, timestamp)