R 识别data.table内运行的优雅方式

R 识别data.table内运行的优雅方式,r,data.table,R,Data.table,仅在过去两周内,我就遇到过两次这个问题,所以我觉得值得一贴。我试图识别data.table中的“运行”,但我想不出一种优雅的方法来实现这一点 例子 set.seed(2016) dt不知道这是否优雅,但是: dt <- data.table(ID = c(9, 10, 15, 18, 21, 22, 25)) run_ids <- abs(dt[1:(.N-1), ID] - dt[2:.N, ID]) <= 2 run_ids <- c(run_ids[1], run_

仅在过去两周内,我就遇到过两次这个问题,所以我觉得值得一贴。我试图识别
data.table
中的“运行”,但我想不出一种优雅的方法来实现这一点

例子
set.seed(2016)

dt不知道这是否优雅,但是:

dt <- data.table(ID = c(9, 10, 15, 18, 21, 22, 25))
run_ids <- abs(dt[1:(.N-1), ID] - dt[2:.N, ID]) <= 2
run_ids <- c(run_ids[1], run_ids)
foo <- with(rle(run_ids), rep(cumsum(values) * values, lengths))
foo[foo == 0] = foo[which(foo == 0) + 1]
dt[, RunID := foo]
dt[RunID == 0, RunID := NA]
#    ID RunID
# 1:  9     1
# 2: 10     1
# 3: 15    NA
# 4: 18    NA
# 5: 21     2
# 6: 22     2
# 7: 25    NA

dt我将在创建此运行ID后停止:

dt[, run_id0 := 1L + cumsum(abs(ID - shift(ID, fill=ID[1L])) > 2)]
但要获得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 ]

你想要那些NA在那里吗?或者他们可以算是另一个群体吗?嗯,很难。不妨将它们保留为NA以匹配我当前的工作。好吧,这不完全是您所要求的,但应该可以满足您的需要
dt[,InRun:=rleid(abs(ID shift(ID,type=“lag”))基本上,第二步将<代码> n>代码> s。这就是为什么群组跳转的原因。如果你需要组的顺序更难。迈克,我认为你给的解决方案有一个非常微妙的缺陷。考虑两个连续的,但不同的运行。我认为你的代码会把它们标记为同一个运行。作为一个例子,尝试一下。你对这家伙的解决方案是不对的。前两行应该有相同的RunIDthink修复…虽然如果最后一行是0它可能会失败,但仍然失败。看这个例子-
dt hi,尝试使用向量,我得到
1 NA 2
,这不是你想要的输出吗?No.7在前一个ID的2之内,9,so它们应该具有相同的RunID。请参阅Frank的解决方案输出。仍然不确定这是否正确,因为OP指的是查看当前行的上方和下方。您的要比我的好得多:) nice@JohnSmith谢谢:)非常相似,真的,只是我的使用了
shift
,在完整的T/F向量上使用了
cumsum
,而不是较短的
rle(vec)$values
。顺便说一句,常见的惯例是
foo
dt[, run_id0 := 1L + cumsum(abs(ID - shift(ID, fill=ID[1L])) > 2)]
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 ]