【问题标题】:R: Fastest way to obtain the first and last location each unique value in a vector?R:获取向量中每个唯一值的第一个和最后一个位置的最快方法?
【发布时间】:2017-11-25 04:55:24
【问题描述】:

我有一个包含未知值列表的向量。我想知道 R 中获取每个唯一值的第一个和最后一个索引并返回 n × 2 向量的最快方法。

例如,下面的工作,但我认为对于大型向量可能太慢了。

library(magrittr)
vals <- sample(1:100, 1e7, replace = T)
a = t(sapply(unique(vals), function(uv) {
  w = which(uv == vals)
  c(w[1], w[length(w)])
}))

欢迎使用 Rcpp 解决方案。

【问题讨论】:

  • 我正在删除 rcpp 标签。 SO 不是按订单编码的服务。

标签: r


【解决方案1】:

使用split from base R 可以提高当前解决方案的效率

system.time({
 a <- t(sapply(unique(vals), function(uv) {
  w = which(uv == vals)
  c(w[1], w[length(w)])
}))

})
# user  system elapsed 
#   4.75    1.60    6.39 

system.time({
a1 <- do.call(rbind, lapply(split(seq_along(vals), vals), 
        function(x) x[c(1, length(x))]))[as.character(unique(vals)),]
     })
# user  system elapsed 
#   0.09    0.00    0.09 


all.equal(a, a1, check.attributes = FALSE)
#[1] TRUE

或者另一个选项是match/fmatch,发现它比split

library(fastmatch)
system.time({
 a2 <- cbind(fmatch(unique(vals), vals), length(vals) - fmatch(unique(vals), rev(vals)) + 1)
 })
# user  system elapsed 
#   0.45    0.25    0.70 

all.equal(a, a2, check.attributes = FALSE)
#[1] TRUE

数据

set.seed(24)
vals <- sample(1:100, 1e7, replace = TRUE)

【讨论】:

    【解决方案2】:

    data.table 版本可能类似于

    DT <- data.table(vals)
    DT[, .(first=min(.I), last=max(.I)), by=vals]
    

    或者dplyr可以用

    tibble(vals) %>% mutate(row = row_number()) %>% 
                     group_by(vals) %>% summarise(first=min(row), max=max(row))
    

    不过,时间安排与 @akrun 使用优雅的基本 R split 调用所获得的时间非常相似,因此在那里收获不多。

    【讨论】:

    • 我怀疑DT[ , .(first = .I[1], last = .I[.N]), by = vals] 可能会更快。干杯。
    • @ekstroem 您的解决方案是迄今为止最快的纯 R 解决方案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-04
    • 2016-12-12
    • 1970-01-01
    • 2016-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多