2011-06-14 23 views
16

He visto esta pregunta varias veces en la lista de correo de R, pero todavía no he podido encontrar una respuesta satisfactoria.Equivalente a rowMeans() para min()

Supongamos que una matriz m

m <- matrix(rnorm(10000000), ncol=10) 

puedo conseguir la media de cada fila por:

system.time(rowMeans(m)) 
    user system elapsed 
    0.100 0.000 0.097 

Pero obtener el valor mínimo de cada fila por

system.time(apply(m,1,min)) 
    user system elapsed 
16.157 0.400 17.029 

toma más de 100 veces más larga, ¿hay alguna manera de acelerar esto?

Respuesta

15

Usted podría utilizar pmin, pero Tendría que obtener cada columna de su matriz en un vector separado. Una forma de hacerlo es convertirlo a data.frame y luego llamar al pmin a través de do.call (ya que data.frames son listas).

system.time(do.call(pmin, as.data.frame(m))) 
# user system elapsed 
# 0.940 0.000 0.949 
system.time(apply(m,1,min)) 
# user system elapsed 
# 16.84 0.00 16.95 
+0

Me gusta el uso de 'do.call'.Pensé en 'pmin', pero no pensé en una forma astuta de incorporarlo. Todos los chicos geniales parecen ser capaces de usar 'do.call' para lograr sus objetivos ... Tengo que leer un poco sobre esto. – Chase

+0

'do.call' es útil cuando se quiere poder crear argumentos de funciones dinámicamente (generalmente cuando se desconoce el número de argumentos pasados ​​por' ... '). –

+1

¡Buena respuesta, gracias! con pmin.int() fue incluso un poco más rápido – johannes

5
library("sos") 
findFn("rowMin") 

obtiene un hit en el paquete Biobase, desde Bioconductor ...

source("http://bioconductor.org/biocLite.R") 
biocLite("Biobase") 

m <- matrix(rnorm(10000000), ncol=10) 
system.time(rowMeans(m)) 
## user system elapsed 
## 0.132 0.148 0.279 
system.time(apply(m,1,min)) 
## user system elapsed 
## 11.825 1.688 13.603 
library(Biobase) 
system.time(rowMin(m)) 
## user system elapsed 
## 0.688 0.172 0.864 

no tan rápido como rowMeans, pero mucho más rápido que apply(...,1,min)

+0

gracias, no estaba al tanto del paquete sos y rowMin también resuelve mi problema. – johannes

+0

¿Desea cronometrar la solución 'do.call' también? –

5

he tenido la intención de probar el nuevo paquete compiler en I 2.13.0. Esto esencialmente sigue la publicación delineada por Dirk here.

library(compiler) 
library(rbenchmark) 
rowMin <- function(x, ind) apply(x, ind, min) 
crowMin <- cmpfun(rowMin) 

benchmark(
     rowMin(m,1) 
    , crowMin(m,1) 
    , columns=c("test", "replications","elapsed","relative") 
    , order="relative" 
    , replications=10) 
) 

Y los resultados:

  test replications elapsed relative 
2 crowMin(m, 1)   10 120.091 1.0000 
1 rowMin(m, 1)   10 122.745 1.0221 

anticlimática por decir lo menos, aunque parece que se han conseguido algunas otras buenas opciones.

+0

gracias por su respuesta, tendré que buscar más profundamente en su respuesta, ese es el nuevo terreno para yo :) – johannes

+1

El compilador mejora la optimización de los bucles explícitos. Pruebe por ejemplo: 'rowMin <- function (x) {n <- nrow (x); r <- numeric (n); for (i en 1: n) r [i] <- min (x [i,]) ; r} ' – Marek

+3

+1 para evitar 'sesgo de publicación' –

2

No particularmente R-idiosincrásica, pero sin duda el método más rápido es sólo para usar pmin y lazo sobre columnas:

x <- m[,1] 
for (i in 2:ncol(m)) x <- pmin(x, m[,i]) 

En mi máquina que toma sólo 3 veces más largo que rowMeans para la matriz 1e + 07x10, y es ligeramente más rápido que el método do.call a través del data.frame.

+0

Y otra ganancia de velocidad por' pmin (m [, 1], m [, 2], m [, 3], m [, 4], m [, 5 ], m [, 6], m [, 7], m [, 8], m [, 9], m [, 10]) '. Joshua 'as.data.frame' consume mucho tiempo. – Marek

+1

no es rápido para escribir sin embargo, o general para diferentes entradas :) – mdsumner

+0

Agrego una solución más general en el comentario a la respuesta de Joshua. – Marek

8

Si usted quiere meter a paquetes CRAN, entonces tanto los matrixStats y los fBasics paquetes tienen la [nota la s que no está en la función Biobase] función rowMins y una variedad de otras estadísticas de fila y columna.

10

Bastante tarde para la fiesta, pero como el autor de matrixStats y en caso de que alguien vea esto, tenga en cuenta que matrixStats::rowMins() es muy rápido en estos días, p.

library(microbenchmark) 
library(Biobase)  # rowMin() 
library(matrixStats) # rowMins() 
options(digits=3) 

m <- matrix(rnorm(10000000), ncol=10) 

stats <- microbenchmark(
    rowMeans(m), ## A benchmark by OP 
    rowMins(m), 
    rowMin(m), 
    do.call(pmin, as.data.frame(m)), 
    apply(m, MARGIN=1L, FUN=min), 
    times=10 
) 

> stats 
Unit: milliseconds 
          expr min  lq mean median  uq max 
         rowMeans(m) 77.7 82.7 85.7 84.4 90.3 98.2 
         rowMins(m) 72.9 74.1 88.0 79.0 90.2 147.4 
         rowMin(m) 341.1 347.1 395.9 383.4 395.1 607.7 
    do.call(pmin, as.data.frame(m)) 326.4 357.0 435.4 401.0 437.6 657.9 
apply(m, MARGIN = 1L, FUN = min) 3761.9 3963.8 4120.6 4109.8 4198.7 4567.4 
+0

@HenirkB sería genial si matrixStats rowMins también trabajara en data.frames, (sin la necesidad de transformarlo en matriz primero) – skan

+1

@skan, desafortunadamente no es obvio que esto pertenece a matrixStats por varias razones, por favor vea https://github.com/HenrikBengtsson/matrixStats/issues/18 – HenrikB