我遇到了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
我遇到了R的范围函数。它肯定是有用的工具,并且使代码更具可读性,但是通过将其替换为包括min和max的简单单行代码,可以使其速度提高一倍。我做了一些...
这里是range.default
的来源(运行R 3.6.1)