我正在寻找一个没有序列号的向量的子集。但是,如果存在两个以上序列号的序列,则仅删除每隔一次的序列号,因为删除该序列号将中断该序列。
例如,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)]有没有其他更快的解决方案呢?
发布于 2021-04-08 05:25:25
使用方便的函数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发布于 2021-04-08 03:39:21
我们可以使用神奇的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 8https://stackoverflow.com/questions/66992786
复制相似问题