Is there a vectorized parallel max() and min()?

后端 未结 4 1517
滥情空心
滥情空心 2020-12-01 11:49

I have a data.frame with columns \"a\" and \"b\". I want to add columns called \"high\" and \"low\" that contain the highest and the lowest among columns a and

相关标签:
4条回答
  • 2020-12-01 12:17

    Sounds like you're looking for pmax and pmin ("parallel" max/min):

    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).
    
    0 讨论(0)
  • 2020-12-01 12:28

    Another possible solution:

    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)
    
    0 讨论(0)
  • 2020-12-01 12:39

    Here's a version I implemented using Rcpp. I compared pmin with my version, and my version is roughly 3 times faster.

    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))
    

    The microbenchmark function output for 100,000 elements is:

    > 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
    

    And for 500,000 elements:

    > 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
    

    So you can see the Rcpp version is faster.

    You could make it better by adding some error checking in the function, for instance: check that both vectors are the same length, or that they are comparable (not character vs. numeric, or boolean vs. numeric).

    0 讨论(0)
  • 2020-12-01 12:40

    If your data.frame name is dat.

    dat$pmin <- do.call(pmin,dat[c("a","b")])
    dat$pmax <- do.call(pmax,dat[c("a","b")])
    
    0 讨论(0)
提交回复
热议问题