如何识别条件特定边界内的行并计算差异?

How to identify rows within a certain boundary of a condition and calculate the differences?

假设我有以下数据集:

> dat
       value id
 1: 2.785300  1
 2: 4.164371  1
 3: 4.179532  1
 4: 4.373546  1
 5: 4.378759  1
 6: 4.694612  1
 7: 4.955066  2
 8: 4.983810  2
 9: 5.183643  2
10: 5.329508  2
11: 5.389843  2
12: 5.487429  2
13: 5.575781  3
14: 5.738325  3
15: 5.943836  3
16: 6.124931  3
17: 6.511781  3
18: 6.595281  3

可通过以下方式创建:

set.seed(1)
library(data.table)
dat <- data.table(value=round(rnorm(18, mean = 5, sd = 1),6))[order(value)][,id:=rep(1:3, each=6)]

接下来我做的是创建一个变量,它指示新的 id 首先出现在哪一行,并为该行指定一个特定的 changeid,所有其他行的 NA 值为:

dat[, changeid:=ifelse(+(!(id==shift(id,n=1L,type="lag")))==1,1,NA)
    ][, changeid:=rleid(changeid)[changeid==1]]

给出:

> dat
       value id changeid
 1: 2.785300  1       NA
 2: 4.164371  1       NA
 3: 4.179532  1       NA
 4: 4.373546  1       NA
 5: 4.378759  1       NA
 6: 4.694612  1       NA
 7: 4.955066  2        2
 8: 4.983810  2       NA
 9: 5.183643  2       NA
10: 5.329508  2       NA
11: 5.389843  2       NA
12: 5.487429  2       NA
13: 5.575781  3        4
14: 5.738325  3       NA
15: 5.943836  3       NA
16: 6.124931  3       NA
17: 6.511781  3       NA
18: 6.595281  3       NA

现在我想创建两个新变量:

  1. 一个名为 window 的变量,在 value 的某个边界内(例如:在具有changeid 值)。其他行有 NA
  2. 一个名为 iddif 的变量,与具有 changeid 的行的 value 不同。其他行有 NA

想要的结果:

> dat
       value id changeid window      iddif
 1: 2.785300  1       NA     NA         NA
 2: 4.164371  1       NA     NA         NA
 3: 4.179532  1       NA     NA         NA
 4: 4.373546  1       NA     NA         NA
 5: 4.378759  1       NA     NA         NA
 6: 4.694612  1       NA     NA         NA
 7: 4.955066  2        2      2   0.000000
 8: 4.983810  2       NA      2   0.028744
 9: 5.183643  2       NA     NA         NA
10: 5.329508  2       NA     NA         NA
11: 5.389843  2       NA      4  -0.185938
12: 5.487429  2       NA      4  -0.088352
13: 5.575781  3        4      4   0.000000
14: 5.738325  3       NA      4   0.162544
15: 5.943836  3       NA     NA         NA
16: 6.124931  3       NA     NA         NA
17: 6.511781  3       NA     NA         NA
18: 6.595281  3       NA     NA         NA

有什么想法可以达到这个预期的结果吗?

附加问题:如何让 changeid1 开始,然后随着 1 递增以用于下一次 ID 更改?

如果解决方案也使用 data.table 就好了。

这是一个可能的解决方案,使用 foverlaps

首先,我将创建 changeid 如下(根据奖金)

dat[c(0L, diff(id)) == 1L, changeid := 1:.N]

然后,我将创建一个临时数据集,其中 changeid 不是 NA,键入它,在 dat 和 运行 [=12] 中创建间隔列=] 在他们之上。然后,提取匹配的行并更新原始数据

temp <- dat[!is.na(changeid), .(start = value, end = value)] # temp data
dat[, `:=`(start = value - 0.2, end = value + 0.2)] # set boundries
setkey(temp) # key the smaller data
res <- foverlaps(dat, temp, which = TRUE, nomatch = 0L) # get matched incidents
dat[res$xid, `:=`(window = res$yid, iddif = temp$start[res$yid])] # update values
dat[!is.na(window), iddif := value - iddif] # calculate differences
dat
#        value id changeid    start      end window     iddif
#  1: 2.785300  1       NA 2.585300 2.985300     NA        NA
#  2: 4.164371  1       NA 3.964371 4.364371     NA        NA
#  3: 4.179532  1       NA 3.979532 4.379532     NA        NA
#  4: 4.373546  1       NA 4.173546 4.573546     NA        NA
#  5: 4.378759  1       NA 4.178759 4.578759     NA        NA
#  6: 4.694612  1       NA 4.494612 4.894612     NA        NA
#  7: 4.955066  2        1 4.755066 5.155066      1  0.000000
#  8: 4.983810  2       NA 4.783810 5.183810      1  0.028744
#  9: 5.183643  2       NA 4.983643 5.383643     NA        NA
# 10: 5.329508  2       NA 5.129508 5.529508     NA        NA
# 11: 5.389843  2       NA 5.189843 5.589843      2 -0.185938
# 12: 5.487429  2       NA 5.287429 5.687429      2 -0.088352
# 13: 5.575781  3        2 5.375781 5.775781      2  0.000000
# 14: 5.738325  3       NA 5.538325 5.938325      2  0.162544
# 15: 5.943836  3       NA 5.743836 6.143836     NA        NA
# 16: 6.124931  3       NA 5.924931 6.324931     NA        NA
# 17: 6.511781  3       NA 6.311781 6.711781     NA        NA
# 18: 6.595281  3       NA 6.395281 6.795281     NA        NA

(如果不喜欢可以删除 startend