与colMeans类似的max和min函数

时间:2011-10-19 16:45:39

标签: r

我想知道是否存在与colMeans类似的高速min和max函数?

对于'max',虽然我可以使用'apply'模拟行为,如下所示:

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

它似乎比基础包中的colMeans慢很多。

5 个答案:

答案 0 :(得分:11)

pmaxapply快〜10倍。仍然没有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

答案 1 :(得分:7)

总是可以从分析开始,但你的预感似乎是正确的:

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>

在这种情况下,您可能需要考虑使用inline和R的基本C API或我们的Rcpp包编写一个简单的C / C ++函数。这应该得到colMeans - 相似的速度。

编辑:这是一个更完整的例子。 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>

答案 2 :(得分:6)

我发布的答案只是因为我没有足够的声誉来评论或投票/投票。

pmaxapply快10倍的最佳答案并不总是正确的。例如,计算每列中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 

现在计算每列中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 

当行数较小(例如100)时,似乎pmax仅在速度上与apply相当或更好。当行数很大(例如10 ^ 6)时,pmaxapply慢得多。

在任何情况下,colMaxs包中的matrixStats都是最快的,似乎是最佳选择。

答案 3 :(得分:5)

matrixStats包有很多很棒的功能,包括colMaxs

答案 4 :(得分:1)

pminpmax可以轻松地用于获取行分和最大值,但对于列来说有点尴尬。

# 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