Есть ли векторизованная параллель max () и min ()? - PullRequest
31 голосов
/ 08 апреля 2011

У меня есть data.frame со столбцами «а» и «б».Я хочу добавить столбцы с именем "high" и "low", которые содержат самые высокие и самые низкие значения среди столбцов a и b.

Есть ли способ сделать это без циклического перебора строк в кадре данных?

edit: это для данных OHLC, поэтому столбец high и low должен содержать самый высокий и самый низкий элемент между a и b в одной строке, а не среди целых столбцов.извините, если это плохо сформулировано.

Ответы [ 4 ]

35 голосов
/ 08 апреля 2011

Звучит так, будто вы ищете pmax и pmin ("параллельный" макс / мин):

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).
3 голосов
/ 26 октября 2016

Вот версия, которую я реализовал, используя 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))

Выход функции microbenchmark для 100 000 элементов:

> 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 голосов
/ 08 апреля 2011

Другое возможное решение:

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 голосов
/ 08 апреля 2011

Если ваше имя data.frame dat.

dat$pmin <- do.call(pmin,dat[c("a","b")])
dat$pmax <- do.call(pmax,dat[c("a","b")])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...