Max и min, которые аналогичны colMeans
Мне интересно, есть ли функция min и max с высокой скоростью, которая работает на столбцах аналогично colMeans?
Для "max", хотя я могу моделировать поведение с помощью "apply", например, следующее:
colMax <- function (colData) {
apply(colData, MARGIN=c(2), max)
}
Это кажется намного медленнее, чем colMeans в базовом пакете.
Ответы
Ответ 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