Почему функция range () медленнее, чем комбинация min и max? - PullRequest
10 голосов
/ 03 апреля 2019

Я столкнулся с функцией 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
...