R data.table从第i个元素到每个剩余元素的距离

vry*_*ryb 4 r distance data.table

假设我有以下数据:

d = data.table( id = 1, x = c(1, 10, 17, 35, 37, 45) )
Run Code Online (Sandbox Code Playgroud)

我想看看x by group id中的每个第i个元素是否有一个比它大30到40之间的元素.因此,对于x中第一个元素组ID(1),我希望看到1之后x中的任何值是否在值31和41之间.答案是肯定的,所以我想创建一个列valid_gap第一个元素为TRUE.最后,我希望得到:

d_final = data.table( id = 1, x = c(1, 10, 17, 35, 37, 45), valid_gap = c(T, T, F, F, F, F ) )
Run Code Online (Sandbox Code Playgroud)

我和一位同事已经考虑过这个问题了一段时间,我们真的试图避免在这里使用循环,但无法弄明白.这可能没有循环吗?

我最好的尝试是这样的:

d[, valid_gap := any(between( rdist(x[ .N - .I ])[,1], left = 30, right = 40 )), by = id]
Run Code Online (Sandbox Code Playgroud)

但我正在考虑问题,因为试图通过x索引,好像在循环中,我怀疑这是错误的想法.

编辑 - "坏"的解决方案:

x = c(1, 10, 17, 35, 37, 45)
valid_gap = c()

for( i in 1:length(x) ) {
  if( i == length(x) ){
    valid_gap = c(valid_gap, F)
  } else {
    valid_gap = c(valid_gap, any(between( rdist( x[ x >= x[i] ] )[,1], left = 30, right = 40 )) )
  }
}
valid_gap
Run Code Online (Sandbox Code Playgroud)

先感谢您!

Fra*_*ank 5

我猜一个非equi连接应该比一个循环更快:

d[, v := 
  d[.(id = id, x0 = x + 30, x1 = x + 40), on=.(id, x >= x0, x <= x1), 
    .N
  , by=.EACHI][, N > 0L]
]

   id  x     v
1:  1  1  TRUE
2:  1 10  TRUE
3:  1 17 FALSE
4:  1 35 FALSE
5:  1 37 FALSE
6:  1 45 FALSE
Run Code Online (Sandbox Code Playgroud)

对于每一行,我们......

  1. 找到感兴趣区间内的所有匹配项;
  2. 算他们(带.N); 然后
  3. 检查计数是否超过0.

第一步可能会略微加快mult="first".