【问题标题】:Removing sequential values from a vector, but not iteratively从向量中删除顺序值,但不是迭代
【发布时间】:2021-04-07 19:17:14
【问题描述】:

我正在寻找将一个向量子集到没有序列号的地方。但是,如果有一个包含两个以上序号的序列,则只会删除每隔一个序号,因为删除该序号会破坏序列。

例如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)]

是否有其他解决方案可以显着加快速度?

【问题讨论】:

    标签: r


    【解决方案1】:

    使用便捷函数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
    

    【讨论】:

      【解决方案2】:

      我们可以使用奇妙的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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-05
        相关资源
        最近更新 更多