优雅的方法来识别data.table中的运行

Ben*_*Ben 5 r data.table

我在过去两周内遇到过这个问题两次,所以我认为值得发帖.我正在尝试识别内部的"运行" data.table,但我无法找到一种优雅的方法来实现它.

set.seed(2016)
dt <- data.table(ID = 1:50, Char = sample(LETTERS, 50, replace=TRUE))
dt <- dt[order(Char, ID)]

    ID Char
 1:  9    A
 2: 10    B
 3: 20    C
 4: 42    C
 5:  2    D
 6:  4    D
 7:  6    D
 8: 18    D
 ...
Run Code Online (Sandbox Code Playgroud)

在这里,我想识别和分组ID在上/下行的2行内的行.这是我目前难看的解决方案

# Runs of 2 or more IDs within 2 of each other
dt[, `:=`(InRun = FALSE, InRunStart = FALSE)]
dt[abs(ID - shift(ID, type="lag")) <= 2 | abs(shift(ID, type="lead") - ID) <= 2, InRun := TRUE]
dt[InRun == TRUE & abs(ID - shift(ID, type="lag")) > 2 | is.na(shift(ID, type="lag")), InRunStart := TRUE]
dt[InRun == TRUE, RunID := cumsum(InRunStart)]
dt[, c("InRun", "InRunStart") := NULL]
dt
    ID Char RunID
 1:  9    A     1
 2: 10    B     1
 3: 20    C    NA
 4: 42    C    NA
 5:  2    D     2
 6:  4    D     2
 7:  6    D     2
 8: 18    D    NA
 ...
Run Code Online (Sandbox Code Playgroud)

有一个更好的方法吗?


编辑:似乎对我如何定义"运行"存在一些困惑.更明确地说,当且仅当它们的ID在2的距离内时,row_i和row_i + 1应该具有相同的RunID.

Fra*_*ank 3

生成此运行 ID 后我会停止:

dt[, run_id0 := 1L + cumsum(abs(ID - shift(ID, fill=ID[1L])) > 2)]
Run Code Online (Sandbox Code Playgroud)

但要获取 OP 的运行 ID(忽略长度为 1 的运行),可以采用以下几种方法:

dt[duplicated(run_id0) | duplicated(run_id0, fromLast=TRUE), run_id1 := .GRP, by=run_id0 ]
# or
dt[, run_len := .N, by=run_id0 ][ run_len > 1L, run_id2 := .GRP, by=run_id0 ]
Run Code Online (Sandbox Code Playgroud)