当前位置: 首页 > 知识库问答 >
问题:

为什么范围()函数比最小和最大的组合慢?

段溪叠
2023-03-14

我碰到了R的< code>range函数。它确实是一个有用的工具,并使代码更具可读性,但是如果用一个简单的包含< code>min和< code>max的一行程序来代替它,它的速度可以提高一倍。

我做了一些基准测试,range函数的“糟糕”性能让我吃惊。为了进行比较,我编写了一个名为< code>range2的函数,它使用了min和max(参见代码)。除了速度之外,如果一个简单的一行html" target="_blank">程序可以胜过这个函数,并且它也很容易阅读,那么它还有存在的理由吗?

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

当然,这并不是人们想要摆脱的第一个瓶颈,因为我们谈论的是一个有10000000个条目的向量上的毫秒,但我希望<code>范围</code>更快。我的简单直觉是:

range遍历数据一次,同时搜索最小值和最大值,而我的range2函数遍历数据两次:一次查找最小值,一次查找最大值。

也许有人可以给出一些关于实现的背景。也许原因是minmax是用C实现的,而范围不是?

补充:我已经和我的一个朋友谈过了,他只是通过用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

共有1个答案

汲灿
2023-03-14

这是range.default的源代码(运行R 3.6.1)

 > range.default
function (..., na.rm = FALSE, finite = FALSE) 
{
    x <- c(..., recursive = TRUE)
    if (is.numeric(x)) {
        if (finite) 
            x <- x[is.finite(x)]
        else if (na.rm) 
            x <- x[!is.na(x)]
        c(min(x), max(x))
    }
    else {
        if (finite) 
            na.rm <- TRUE
        c(min(x, na.rm = na.rm), max(x, na.rm = na.rm))
    }
}

你可以看到它在调用c(min(x),max(x))本身之前做了一些额外的检查。它没有针对速度进行优化。这只是一个用户友好的功能。这些毫秒差异似乎不太可能成为性能瓶颈的根源。

 类似资料:
  • 问题内容: 最近在一次采访中有人问我这个问题。 给定以下代码,静态整数的最小和最大可能值是多少? 我告诉他们,最大值将为25(在没有竞争条件的情况下),而最小值将为5(在每次迭代时所有线程之间的竞争条件的情况下)。 但是面试官说,最小值甚至可以低于5。这 怎么可能? 问题答案: 我声称最小值可能是2。 这样做的关键是的非原子性,即它是读和写,它们之间可能有其他操作。 调用线程T1..T5: T1读

  • 具有以下矩阵: 我想只得到每行的最小范围在2到30之间的行。 每行的最小范围: 所以我们只得到[2]和[3] 每行的最大范围在0到160之间: 最后我们只得到满足这两个条件的[2]。你能提供一个R语言函数来生成这个结果吗? 问候迪米特里斯

  • 问题内容: 我正在学习Java 8文档。我知道最大数组大小定义为均值2 ^ 31 – 8 = 2147483639 。然后,我集中讨论了为什么要减去8 或减去? 有些人根据文档给出了一些逻辑。因此,对于标题字,减去8。但是在这种情况下,如果标题字需要大于8,那么答案是什么? 请在此基础上澄清我。预先感谢您的合作。 问题答案: 阅读上述有关Java内存管理的文章,其中清楚指出 我认为这适用于Arra

  • 我在让范围过滤器更具动态性方面遇到了问题。 过滤代码: 而不是硬编码的最小值0和最大值100,我想得到字段verkoopprijs的最小值和最大值。 搜索结果如下所示: 然而我不知道如何得到最小值和最大值。

  • null 请在此基础上向我澄清。谢谢你的合作。

  • 如果我运行此代码,我会收到错误RangeError:超出最大调用堆栈大小。但为什么呢?当我用9调用它时就发生了,斐波那契在这么小的数字下应该不是问题。