从向量中移除连续值,但不能迭代

  • 本文关键字:但不能 迭代 连续 向量 r
  • 更新时间 :
  • 英文 :


我正在寻找一个向量的子集,在那里没有序列号。然而,如果有一个序列包含两个以上的序列号,那么只有每隔一秒的序列号会被删除,因为删除该序列号会破坏序列。

例如1,2,4,6,7会产生1,4,6

例如6,7,8,9将给出6,8

这很容易迭代,但迭代超过10M以上的元素非常慢:

x <- c(1,2,4,6,7,8,9) # Ideal output is c(1,4,6,8)

for (i in 2:length(x)) {
if (!is.na(x[i-1])) {
if (x[i] == x[i-1]+1) {x[i] <- NA_integer_}
}
} 

x[!is.na(x)]

有没有其他解决方案可以显著加快速度?

使用方便函数collapse::seqiddata.table::rowid:

library(collapse)
library(data.table)
x[rowid(seqid(x)) %% 2 == 1]
# [1] 1 4 6 8

在较长的矢量上看起来更快:

x = rep(c(1,2,4,6,7,8,9), 1e7)
system.time({
seq_id = data.table::rleid(x - seq_along(x))
obs_id = unlist(lapply(split(seq_id, seq_id), seq_along))
r1 = x[obs_id %% 2 == 1]
})  
#   user  system elapsed 
# 112.77   55.99  177.11 
system.time({
r2 = x[rowid(seqid(x)) %% 2 == 1]
})
#   user  system elapsed 
#   8.03    5.97   10.23 
all.equal(r1, r2)
# [1] TRUE

我们可以使用奇妙的data.table::rleid为每个序列生成一个ID,然后只保留序列中的奇数元素。这应该是相当快的,尽管更多的优化当然是可能的。

disrupt_seqs = function(x) {
seq_id = data.table::rleid(x - seq_along(x))
obs_id = unlist(lapply(split(seq_id, seq_id), seq_along))
x[obs_id %% 2 == 1]
}
x <- c(1,2,4,6,7,8,9)
disrupt_seqs(x)  
# [1] 1 4 6 8

最新更新