【问题标题】:max and min functions that are similar to colMeans类似于 colMeans 的 max 和 min 函数
【发布时间】:2011-10-19 16:45:38
【问题描述】:

我想知道是否有类似于 colMeans 的列上的高速 min 和 max 函数?

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

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

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

【问题讨论】:

  • 在 S-Plus 中,有colMaxscolMedians 和一堆其他类似的功能。不幸的是,R 并没有实现所有这些。

标签: r


【解决方案1】:

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

【讨论】:

  • 矩阵X 的另一个选项是sapply(seq_len(ncol(X)), function(x) max(X[, x]))
  • 当然可以,但是换位不是免费的。我看到system.time(do.call(pmax,data.frame(t(data))))apply 花费相同的时间。
【解决方案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>

在这种情况下,您可能需要考虑使用inline 和R 的基本C API 或我们的Rcpp 包编写一个简单的C/C++ 函数。这应该可以达到您的 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>

【讨论】:

  • PS 我收回它。我花了几分钟在新的parallel 包上闲逛,似乎开销太大了,除非你比我聪明......
  • 这里的一个问题是处理 NA。在计算“colMaxs”之前可以用“0”估算
【解决方案3】:

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

【讨论】:

    【解决方案4】:

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

    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 
    

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

    无论如何,matrixStats 包中的colMaxs 是最快的,而且似乎是要走的路。

    【讨论】:

    【解决方案5】:

    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
    

    【讨论】:

    • 由于mtcars是一个data.frame,你可以使用sapply(mtcars, max)
    猜你喜欢
    • 2017-08-06
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多