Подтвердить что ты не робот

Max и min, которые аналогичны colMeans

Мне интересно, есть ли функция min и max с высокой скоростью, которая работает на столбцах аналогично colMeans?

Для "max", хотя я могу моделировать поведение с помощью "apply", например, следующее:

colMax <- function (colData) {
    apply(colData, MARGIN=c(2), max)
}

Это кажется намного медленнее, чем colMeans в базовом пакете.

4b9b3361

Ответ 1

pmax ~ 10 раз быстрее, чем apply. Тем не менее, не так быстро, как colMeans.

data = matrix(rnorm(10^6), 100)
data.df = data.frame(t(data))

system.time(apply(data, MARGIN=c(2), max))
system.time(do.call(pmax, data.df))
system.time(colMeans(data))
> system.time(apply(data, MARGIN=c(2), max))
   user  system elapsed 
  0.133   0.006   0.139 
> system.time(do.call(pmax, data.df))
   user  system elapsed 
  0.013   0.000   0.013 
> system.time(colMeans(data))
   user  system elapsed 
  0.003   0.000   0.002

Ответ 2

Всегда можно начинать с профилирования, но ваша догадка кажется правильной:

R> colMax <- function(X) apply(X, 2, max)
R> library(rbenchmark)
R> Z <- matrix(rnorm(100*100), 100, 100)
R> benchmark(colMeans(Z), colMax(Z))
         test replications elapsed relative user.self sys.self user.child 
2   colMax(Z)          100   0.350     87.5      0.12        0          0 
1 colMeans(Z)          100   0.004      1.0      0.00        0          0 
R>

В этом случае вам может потребоваться написать простую функцию C/С++ с помощью inline с базовым C API для R или нашим Rcpp. Это должно получить скорость colMeans -alike.

Изменить: Вот более полный пример. colMeans по-прежнему выигрывает, но мы приближаемся:

R> suppressMessages(library(inline))
R> suppressMessages(library(rbenchmark))
R>
R> colMaxR <- function(X) apply(X, 2, max)
R>
R> colMaxRcpp <- cxxfunction(signature(X_="numeric"), plugin="Rcpp",
+                           body='
+   Rcpp::NumericMatrix X(X_);
+   int n = X.ncol();
+   Rcpp::NumericVector V(n);
+   for (int i=0; i<n; i++) {
+      Rcpp::NumericVector W = X.column(i);
+      V[i] = *std::max_element(W.begin(), W.end());  // from the STL
+   }
+   return(V);
+ ')
R>
R>
R> Z <- matrix(rnorm(100*100), 100, 100)
R> benchmark(colMeans(Z), colMaxR(Z), colMaxRcpp(Z), replications=1000, order="relative")
           test replications elapsed relative user.self sys.self user.child 
1   colMeans(Z)         1000   0.036  1.00000      0.04        0          0 
3 colMaxRcpp(Z)         1000   0.050  1.38889      0.05        0          0 
2    colMaxR(Z)         1000   1.002 27.83333      1.01        0          0 
R>

Ответ 3

Я отправляю ответ только потому, что у меня недостаточно репутации для комментариев или голосования вверх/вниз.

Верхний ответ, что pmax в ~ 10 раз быстрее, чем apply, не всегда корректен. Например, вычислите max для 10 ^ 6 номеров в каждом столбце.

data <- matrix(rnorm(10^8), 10^6)
data.t <- t(data)
data.df <- data.frame(data)
data.t.df = data.frame(data.t)

system.time(a <- apply(data, MARGIN=c(2), max))
system.time(b <- sapply(data.df, max))
system.time(e <- sapply(seq_len(ncol(data)), function(x) max(data[, x])))
system.time(c <- do.call(pmax, data.t.df))
system.time(d <- colMaxs(data))

> system.time(a <- apply(data, MARGIN=c(2), max))
   user  system elapsed 
      2       0       2 
> system.time(b <- sapply(data.df, max))
   user  system elapsed 
   0.25    0.00    0.25 
> system.time(e <- sapply(seq_len(ncol(data)), function(x) max(data[, x])))
   user  system elapsed 
   0.83    0.00    0.83 
> system.time(c <- do.call(pmax, data.t.df))
   user  system elapsed 
  15.94    0.00   15.96 
> system.time(d <- colMaxs(data))
   user  system elapsed 
   0.21    0.00    0.20 

Теперь вычислите max для 100 чисел в каждом столбце.

system.time(a <- apply(data.t, MARGIN=c(2), max))
system.time(b <- sapply(data.t.df, max))
system.time(e <- sapply(seq_len(ncol(data.t)), function(x) max(data.t[, x])))
system.time(c <- do.call(pmax, data.df))
system.time(d <- colMaxs(data.t))

> system.time(a <- apply(data.t, MARGIN=c(2), max))
   user  system elapsed 
   4.41    0.00    4.42 
> system.time(b <- sapply(data.t.df, max))
   user  system elapsed 
   3.23    0.00    3.23 
> system.time(e <- sapply(seq_len(ncol(data.t)), function(x) max(data.t[, x])))
   user  system elapsed 
   3.57    0.00    3.57 
> system.time(c <- do.call(pmax, data.df))
   user  system elapsed 
   1.56    0.00    1.56 
> system.time(d <- colMaxs(data.t))
   user  system elapsed 
   0.25    0.00    0.25 

Кажется, что pmax сравнимо или лучше, чем apply в скорости, когда количество строк невелико (например, 100). Когда число строк велико (например, 10 ^ 6), pmax намного медленнее, чем apply.

В любом случае colMaxs в пакете matrixStats является самым быстрым, и, похоже, это путь.

Ответ 4

Пакет matrixStats имеет множество замечательных функций, включая colMaxs.

Ответ 5

pmin и pmax можно легко использовать для получения строк mins и maxes, но это немного неудобно для столбцов.

# row maxes
do.call("pmax",mtcars)
 [1] 160.0 160.0 108.0 258.0 360.0 225.0 360.0 146.7 140.8 167.6 167.6 275.8
[13] 275.8 275.8 472.0 460.0 440.0  78.7  75.7  71.1 120.1 318.0 304.0 350.0
[25] 400.0  79.0 120.3 113.0 351.0 175.0 335.0 121.0

# col maxes
do.call("pmax",data.frame(t(mtcars)))
 [1]  33.900   8.000 472.000 335.000   4.930   5.424  22.900   1.000   1.000
[10]   5.000   8.000

Другим вариантом является max.col, который также (смущающе) дает максимальные значения строки по умолчанию.

mmtcars <- as.matrix(mtcars)
mmtcars[max.col(t(mmtcars))+(seq(dim(mmtcars)[2])-1)*dim(mmtcars)[1]]
 [1]  33.900   8.000 472.000 335.000   4.930   5.424  22.900   1.000   1.000
[10]   5.000   8.000