有向量化并行的max()和min()函数吗?(针对IT技术问题)

43

我有一个包含列"a"和"b"的data.frame。我想添加名为"high"和"low"的列,它们包含a和b列中最高值和最低值。

是否有一种方法可以在不循环数据框行的情况下完成这个任务?

编辑:这是针对OHLC数据的,因此高低列应该包含在同一行上a和b之间的最高和最低元素,而不是整个列中的最高和最低值。如果措辞不当,请原谅。

4个回答

54

看起来你正在寻找 pmaxpmin(并行的最大值/最小值):

Extremes                 package:base                  R Documentation

Maxima and Minima

Description:

     Returns the (parallel) maxima and minima of the input values.

Usage:

     max(..., na.rm = FALSE)
     min(..., na.rm = FALSE)

     pmax(..., na.rm = FALSE)
     pmin(..., na.rm = FALSE)

     pmax.int(..., na.rm = FALSE)
     pmin.int(..., na.rm = FALSE)

Arguments:

     ...: numeric or character arguments (see Note).

   na.rm: a logical indicating whether missing values should be
          removed.

Details:

     ‘pmax’ and ‘pmin’ take one or more vectors (or matrices) as
     arguments and return a single vector giving the ‘parallel’ maxima
     (or minima) of the vectors.  The first element of the result is
     the maximum (minimum) of the first elements of all the arguments,
     the second element of the result is the maximum (minimum) of the
     second elements of all the arguments and so on.  Shorter inputs
     are recycled if necessary.  ‘attributes’ (such as ‘names’ or
     ‘dim’) are transferred from the first argument (if applicable).

4

这是我使用Rcpp实现的版本。我将pmin与我的版本进行了比较,我的版本大约快了3倍。

library(Rcpp)

cppFunction("
  NumericVector min_vec(NumericVector vec1, NumericVector vec2) {
    int n = vec1.size();
    if(n != vec2.size()) return 0;
    else {
      NumericVector out(n);
      for(int i = 0; i < n; i++) {
        out[i] = std::min(vec1[i], vec2[i]);
      }
      return out;
    }
  }
")

x1 <- rnorm(100000)
y1 <- rnorm(100000)

microbenchmark::microbenchmark(min_vec(x1, y1))
microbenchmark::microbenchmark(pmin(x1, y1))

x2 <- rnorm(500000)
y2 <- rnorm(500000)

microbenchmark::microbenchmark(min_vec(x2, y2))
microbenchmark::microbenchmark(pmin(x2, y2))

当处理100,000个元素时,microbenchmark函数的输出结果如下:

> microbenchmark::microbenchmark(min_vec(x1, y1))
Unit: microseconds
            expr     min       lq     mean  median       uq
 min_vec(x1, y1) 215.731 222.3705 230.7018 224.484 228.1115
     max neval
 284.631   100
> microbenchmark::microbenchmark(pmin(x1, y1))
Unit: microseconds
         expr     min       lq     mean  median      uq      max
 pmin(x1, y1) 891.486 904.7365 943.5884 922.899 954.873 1098.259
 neval
   100

对于500,000个元素:

> microbenchmark::microbenchmark(min_vec(x2, y2))
Unit: milliseconds
            expr      min       lq     mean   median       uq
 min_vec(x2, y2) 1.493136 2.008122 2.109541 2.140318 2.300022
     max neval
 2.97674   100
> microbenchmark::microbenchmark(pmin(x2, y2))
Unit: milliseconds
         expr      min       lq     mean   median       uq
 pmin(x2, y2) 4.652925 5.146819 5.286951 5.264451 5.445638
      max neval
 6.639985   100

所以你可以看到Rcpp版本更快。

你可以通过在函数中添加一些错误检查来使其更好,例如:检查两个向量是否具有相同的长度,或者它们是否可比较(不是字符与数字,或布尔值与数字)。


0
如果你的数据框名称是dat。
dat$pmin <- do.call(pmin,dat[c("a","b")])
dat$pmax <- do.call(pmax,dat[c("a","b")])

0

另一个可能的解决方案:

set.seed(21)
Data <- data.frame(a=runif(10),b=runif(10))
Data$low <- apply(Data[,c("a","b")], 1, min)
Data$high <- apply(Data[,c("a","b")], 1, max)

这仍然是顺序的。 - raygozag

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接