R 查找目标号码之间所有号码的最快方法

R 查找目标号码之间所有号码的最快方法,r,R,给定向量中的数字(例如,1 5 10 12),我会在向量中寻找介于我选择的数字范围(例如,c(9,11))之间的数字。我希望在这个小示例中返回vec=c(10) 下面是一个更大的MWE,我使用dplyr::between对相关值进行子集划分……但是,我正在寻找一种更快的方法来实现这一点(不使用并行化作为解决方案)。如果我能解释得更好,请告诉我 # Data set.seed(1) targets <- sort(sample(1:1e8, 1e7, replace=FALSE)) vec

给定向量中的数字(例如,1 5 10 12),我会在向量中寻找介于我选择的数字范围(例如,c(9,11))之间的数字。我希望在这个小示例中返回
vec=c(10)

下面是一个更大的MWE,我使用
dplyr::between
对相关值进行子集划分……但是,我正在寻找一种更快的方法来实现这一点(不使用并行化作为解决方案)。如果我能解释得更好,请告诉我

# Data
set.seed(1)
targets <- sort(sample(1:1e8, 1e7, replace=FALSE))
vec <- c(1345706, 1405938)

# Function
dplyr_between <- function(vec, targets) {
            require(dplyr)
            targets <- targets[dplyr::between(targets, vec[1], vec[2])]
            return(targets)
        }

test <- dplyr_between(vec, targets)
# 1345732 1345761 1345779 1345780 1345797
基准

library(microbenchmark)
microbenchmark(dplyr_between(vec, targets), base_compare(vec, targets), dt_inrange(vec, targets), times=10L)
# Unit: milliseconds
                       # expr      min       lq     mean   median       uq      max
# dplyr_between(vec, targets) 265.5192 283.5998 296.0947 296.7552 309.4403 323.3634
#  base_compare(vec, targets) 303.4629 317.8389 343.6311 343.3765 354.6891 427.1962
#    dt_inrange(vec, targets) 129.3800 131.1634 142.8658 144.4569 149.3728 164.5824
 # neval
    # 10
    # 10
    # 10

谢谢

由于数据已排序,因此可以使用键控数据表。我将数据预排序等同于数据表预键控,因此创建键的时间不是基准的一部分。我还删除了
dt_inrange
中的积垢,以便比较可以集中在手头的任务上

key_dt = data.table(targets, key = "targets")
# note that `targets` does not need to be sorted beforehand
# the key = "targets" will sort it as the table is created.
# You can also use `setkey` to add a key to an existing data table.

dt_inrange <- function(vec, targets) {
            targets[inrange(targets, vec[1], vec[2])]
        }

key_dt_inrange <- function(vec, target_dt) {
  target_dt[inrange(targets, vec[1], vec[2]), targets]
}
print(microbenchmark(
  dt_inrange(vec, targets),
  key_dt_inrange(vec, key_dt),
  times = 10
), signif = 3, order = "mean")
# Unit: milliseconds
#                         expr  min   lq     mean median    uq   max neval cld
#  key_dt_inrange(vec, key_dt) 47.5 47.9 54.75557   50.4  52.2  98.6    10   a
#     dt_inrange(vec, targets) 48.8 49.8 99.18932   60.4 185.0 219.0    10   a
key\u dt=data.table(targets,key=“targets”)
#请注意,“目标”不需要事先排序
#key=“targets”将在创建表时对其进行排序。
#您还可以使用“setkey”向现有数据表添加键。

dt_范围简单Rcpp实现:

在temp.cpp中的C++代码”


@不幸的是,这在我的笔记本电脑上更快:
library(data.table);targets[inrange(targets,vec[1],vec[2])
@docendodiscimus是的,非常快,谢谢!我仍然会等待其他解决方案,以防出现更快的解决方案。您是否愿意作为潜在的解决方案发布…如果您的解决方案仍然是最快的,我很乐意接受作为答案。顺便说一句,如果您也省略了return语句,则不需要在函数内部重新分配和返回。Pl我们,在比较时,不需要每次都加载包。此外,我相信目前为止没有任何解决方案使用
目标
已排序的事实。如果使用keyed data.table,速度肯定会更快。否则在rcpp中,很容易利用这一点(如果它确实是一个可靠的属性)。您只需找到第一个
target[i]>vec[1]
,然后一直找到第一个
target[j]>vec[2]
然后你可以停下来。以微秒衡量,我赢了吗?:PNice one!你赢了,除非有雄心勃勃的人使用二进制搜索rcpp解决方案来查找最小值和最大值:)是的,我怀疑我的查找速度会比这快。我现在将尝试为我的案例实现你的代码。顺便说一句,你可以做到:
示例(1e8,1e7,replace=F)
生成MWE的速度大约快30%。此外,如果您的真实数据没有预先排序,则不对数据进行排序并使用不采用排序的实现会更快。您能解释键控数据表的概念吗?我不理解这两种方法之间的区别。我可以给您一个指向data.table vignette的链接。
library(microbenchmark)
microbenchmark(dplyr_between(vec, targets), base_compare(vec, targets), dt_inrange(vec, targets), times=10L)
# Unit: milliseconds
                       # expr      min       lq     mean   median       uq      max
# dplyr_between(vec, targets) 265.5192 283.5998 296.0947 296.7552 309.4403 323.3634
#  base_compare(vec, targets) 303.4629 317.8389 343.6311 343.3765 354.6891 427.1962
#    dt_inrange(vec, targets) 129.3800 131.1634 142.8658 144.4569 149.3728 164.5824
 # neval
    # 10
    # 10
    # 10
key_dt = data.table(targets, key = "targets")
# note that `targets` does not need to be sorted beforehand
# the key = "targets" will sort it as the table is created.
# You can also use `setkey` to add a key to an existing data table.

dt_inrange <- function(vec, targets) {
            targets[inrange(targets, vec[1], vec[2])]
        }

key_dt_inrange <- function(vec, target_dt) {
  target_dt[inrange(targets, vec[1], vec[2]), targets]
}
print(microbenchmark(
  dt_inrange(vec, targets),
  key_dt_inrange(vec, key_dt),
  times = 10
), signif = 3, order = "mean")
# Unit: milliseconds
#                         expr  min   lq     mean median    uq   max neval cld
#  key_dt_inrange(vec, key_dt) 47.5 47.9 54.75557   50.4  52.2  98.6    10   a
#     dt_inrange(vec, targets) 48.8 49.8 99.18932   60.4 185.0 219.0    10   a
microbenchmark(db = {
    x = findInterval(vec, targets)
    targets[(x[1]+1):x[2]]
},
dplyr_between(vec, targets))
#Unit: milliseconds
#                        expr       min        lq      mean    median        uq      max neval cld
#                          db  51.02101  58.43651  78.81237  70.51761  79.58609 410.3919   100  a 
# dplyr_between(vec, targets) 127.03341 148.65899 177.43284 156.37937 170.22009 431.5442   100   b


identical({x = findInterval(vec, targets)
          targets[(x[1]+1):x[2]]}, test)
#[1] TRUE
#include <Rcpp.h>
#include <vector>

using namespace Rcpp;
// [[Rcpp::plugins(cpp11)]]
// [[Rcpp::export]]
std::vector<int> betweenRcpp(IntegerVector vec, int lower, int upper) {
  std::vector<int> ret;
  for(int i=0; i<vec.size(); i++) {
    if((vec[i] > lower) & (vec[i] < upper)) {
      ret.push_back(vec[i]);
    } else if(vec[i] >= upper) {
      break;
    }
  }
  return ret;
}
library(Rcpp)
library(microbenchmark)
setwd("~/Desktop")
# Data
set.seed(1)
targets <- sort(sample(1:1e8, 1e7, replace=FALSE))
vec <- c(1345706, 1405938)

# Function
dplyr_between <- function(vec, targets) {
  require(dplyr)
  targets <- targets[dplyr::between(targets, vec[1], vec[2])]
  return(targets)
}

sourceCpp("temp.cpp")

test <- dplyr_between(vec, targets)
test2 <- betweenRcpp(targets, vec[1], vec[2])

microbenchmark(dplyr_between(vec, targets), betweenRcpp(targets, vec[1], vec[2]), times=10)


Unit: microseconds
                                 expr       min        lq        mean      median        uq        max neval cld
          dplyr_between(vec, targets) 72066.027 77809.681 108023.3793 103723.4075 125280.89 173892.552    10   b
 betweenRcpp(targets, vec[1], vec[2])   439.124   464.475    502.7439    481.8025    543.12    594.578    10  a 
all(test == test2)