给出向量中的数字(例如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
编辑使用x < max & x > min
根据评论添加功能(自删除后)
# More Functions
base_compare <- function(vec, targets) {
targets <- targets[targets < vec[2] & targets > vec[1]]
return(targets)
}
base_compare(vec, targets)
# 1345732 1345761 1345779 1345780 1345797
使用@docendo 中的data.table::inrange
编辑
# inrange function
dt_inrange <- function(vec, targets) {
require(data.table)
targets <- targets[inrange(targets, vec[1], vec[2])]
return(targets)
}
dt_inrange(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
谢谢!
答案 0 :(得分:2)
简单的Rcpp实现:
temp.cpp中的C ++代码“
#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;
}
R代码:
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)
答案 1 :(得分:1)
由于您的数据已排序,您可以使用键控数据表。我将预先排序数据等同于预先键入数据表,因此创建密钥的时间不是基准测试的一部分。我还从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
无论出于何种原因,看起来unkeyed方法有一些正确的偏斜,平均值比中位数大50%,但这在键控数据表方法中被阻止了。
答案 2 :(得分:1)
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