Если ваша цель просто сделать один проход, что довольно просто писать в Rcpp, даже если у вас нет большого опыта работы с C++:
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::LogicalVector single_pass(Rcpp::CharacterVector x, Rcpp::String a, Rcpp::String b) {
R_xlen_t i = 0, n = x.size();
Rcpp::LogicalVector result(n);
for (; i < n; i++) {
result[i] = (x[i] == a || x[i] == b);
}
return result;
}
Для такой небольшой объект как используемый в вашем примере, с небольшим накладных .Call
(предположительно) маскирует скорость версии Rcpp,
r_fun <- function(X) X == "A" | X == "B"
##
cpp_fun <- function(X) single_pass(X, "A", "B")
##
all.equal(r_fun(x), cpp_fun(x))
#[1] TRUE
microbenchmark::microbenchmark(
r_fun(x), cpp_fun(x), times = 1000L)
#Unit: microseconds
#expr min lq mean median uq max neval
#r_fun(x) 1.499 1.584 1.974156 1.6795 1.8535 37.903 1000
#cpp_fun(x) 1.860 2.334 3.042671 2.7450 3.1140 51.870 1000
Но для больших векторов (я предполагаю, что это у наше реальное намерение), это значительно быстрее:
x2 <- sample(LETTERS, 10E5, replace = TRUE)
##
all.equal(r_fun(x2), cpp_fun(x2))
# [1] TRUE
microbenchmark::microbenchmark(
r_fun(x2), cpp_fun(x2), times = 200L)
#Unit: milliseconds
#expr min lq mean median uq max neval
#r_fun(x2) 78.044518 79.344465 83.741901 80.999538 86.368627 149.5106 200
#cpp_fun(x2) 7.104929 7.201296 7.797983 7.605039 8.184628 10.7250 200
Вот quick attempt на обобщая выше, если у вас есть какие-либо использовать для этого.
Как насчет: 'x% in% c (" A "," B ")' – MrFlick
@MrFlick Я играл с этими двумя вариантами, и на самом деле я не вижу большой разницы. И масштаб все на наносекундах, даже когда я делаю все это больше, поэтому я немного потерял. – joran
@joran Да, я не представляю, что вы увидите большой прирост скорости (и я очень сомневаюсь, что это где-то узкое место производительности), но это просто синтаксическая альтернатива. – MrFlick