我正在寻找一个向量的子集,在那里没有序列号。然而,如果有一个序列包含两个以上的序列号,那么只有每隔一秒的序列号会被删除,因为删除该序列号会破坏序列。
例如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::seqid
和data.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