Я столкнулся с функцией R range
.Это, безусловно, полезный инструмент, который делает код более читабельным, но его скорость можно удвоить, заменив его простым однострочником, включающим min
и max
.
. Я сделал несколько тестов и 'Плохое выполнение функции дальности меня удивило.Для сравнения я написал функцию с именем range2
, которая использует min и max (см. Код).За исключением скорости, есть ли причины, по которым эта функция существует, если ее можно превзойти с помощью простого однострочного текста, который также легко читается?
require(microbenchmark)
range2 <- function(x) c(min(x),max(x))
n <- 1000000
x <- rnorm(n)
microbenchmark(range(x), range2(x))
#Unit: milliseconds
# expr min lq mean median uq max neval cld
# range(x) 4.696101 4.734751 5.321603 4.796301 4.814751 23.0646 100 b
#range2(x) 2.477602 2.516101 2.542540 2.535051 2.544052 3.7636 100 a
n <- 10000000
x <- rnorm(n)
microbenchmark(range(x), range2(x))
# Unit: milliseconds
# expr min lq mean median uq max neval cld
# range(x) 47.3246 47.9498 58.27992 55.25795 61.98205 146.5100 100 b
#range2(x) 24.7063 25.5021 25.59192 25.55245 25.63515 27.1088 100 a
Наверняка это будет не первое узкое место, которое нужночтобы избавиться, так как мы говорим о миллисекундах на векторе с 10 000 000 записей, но я ожидал, что range
будет быстрее.Моя простая интуиция заключалась в следующем:
range
просматривает данные один раз и ищет минимум и максимум одновременно, тогда как моя функция range2
просматривает данные два раза: Один раз, чтобы найтиминимум и один раз, чтобы найти максимум.
Может быть, кто-то может дать некоторые сведения о реализации.Может быть, причина в том, что min
и max
реализованы в C, а range
нет?
Добавление: я уже говорил об этом с моим другом, и он просто сделал эту функцию быстреереализовав его в C ++ с помощью:
#include <Rcpp.h>
#include <float.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector range3(NumericVector x) {
int xs = x.size();
double minValue = FLT_MAX;
double maxValue = FLT_MIN;
for (int i =0; i < xs; i++) {
if (x[i] < minValue) minValue = x[i];
if (x[i] > maxValue) maxValue = x[i];
}
Rcpp::NumericVector result(2);
result[0] = minValue;
result[1] = maxValue;
return result;
}
, и это дает следующие тесты:
n <- 10000000
x <- rnorm(n)
microbenchmark(range(x), range2(x) ,range3(x))
#Unit: milliseconds
# expr min lq mean median uq max neval cld
# range(x) 47.8583 48.30355 58.12575 55.3135 62.10295 149.9648 100 c
# range2(x) 24.8211 25.53615 25.90920 25.6176 25.79175 42.4659 100 b
# range3(x) 13.2458 13.30385 13.47175 13.3797 13.65410 14.3487 100 a