una - La forma más rápida de multiplicar columnas de matriz con elementos vectoriales en R
operaciones entre columnas en r (5)
Como lo hizo bluegrue, una simple repetición también sería suficiente para realizar la multiplicación de elementos.
El número de multiplicaciones y sumas se reduce en un amplio margen como si se realizara la simple multiplicación de matrices con diag()
, donde para este caso se pueden evitar muchas multiplicaciones por cero.
m = matrix(rnorm(1200000), ncol=6)
v=c(1.5, 3.5, 4.5, 5.5, 6.5, 7.5)
v2 <- rep(v,each=dim(m)[1])
library(microbenchmark)
microbenchmark(m %*% diag(v), t(t(m) * v), m*v2)
Unit: milliseconds
expr min lq mean median uq max neval cld
m %*% diag(v) 11.269890 13.073995 16.424366 16.470435 17.700803 95.78635 100 b
t(t(m) * v) 9.794000 11.226271 14.018568 12.995839 15.010730 88.90111 100 b
m * v2 2.322188 2.559024 3.777874 3.011185 3.410848 67.26368 100 a
Tengo una matriz m
un vector v
. Me gustaría multiplicar la primera columna de la matriz m
por el primer elemento del vector v
, y multiplicar la segunda columna de la matriz m
por el segundo elemento del vector v
, y así sucesivamente. Puedo hacerlo con el siguiente código, pero estoy buscando una forma que no requiera las dos llamadas de transposición. ¿Cómo puedo hacer esto más rápido en R?
m <- matrix(rnorm(120000), ncol=6)
v <- c(1.5, 3.5, 4.5, 5.5, 6.5, 7.5)
system.time(t(t(m) * v))
# user system elapsed
# 0.02 0.00 0.02
Como señala @Arun, no sé si superará su solución en términos de eficiencia de tiempo. En términos de comprensión del código, hay otras opciones aunque:
Una opción:
> mapply("*",as.data.frame(m),v)
V1 V2 V3
[1,] 0.0 0.0 0.0
[2,] 1.5 0.0 0.0
[3,] 1.5 3.5 0.0
[4,] 1.5 3.5 4.5
Y otro:
sapply(1:ncol(m),function(x) m[,x] * v[x] )
En aras de la integridad, agregué sweep
al punto de referencia. A pesar de sus nombres de atributos algo confusos, creo que puede ser más legible que otras alternativas, y también bastante rápido:
n = 1000
M = matrix(rnorm(2 * n * n), nrow = n)
v = rnorm(2 * n)
microbenchmark::microbenchmark(
M * rep(v, rep.int(nrow(M), length(v))),
sweep(M, MARGIN = 2, STATS = v, FUN = `*`),
t(t(M) * v),
M * rep(v, each = nrow(M)),
M %*% diag(v)
)
Unit: milliseconds
expr min lq mean
M * rep(v, rep.int(nrow(M), length(v))) 5.259957 5.535376 9.994405
sweep(M, MARGIN = 2, STATS = v, FUN = `*`) 16.083039 17.260790 22.724433
t(t(M) * v) 19.547392 20.748929 29.868819
M * rep(v, each = nrow(M)) 34.803229 37.088510 41.518962
M %*% diag(v) 1827.301864 1876.806506 2004.140725
median uq max neval
6.158703 7.606777 66.21271 100
20.479928 23.830074 85.24550 100
24.722213 29.222172 92.25538 100
39.920664 42.659752 106.70252 100
1986.152972 2096.172601 2432.88704 100
Si tiene un número mayor de columnas, su solución t (t (m) * v) supera a la solución de multiplicación de matrices por un amplio margen. Sin embargo, hay una solución más rápida, pero viene con un alto costo en el uso de la memoria. Crea una matriz tan grande como m usando rep () y multiplica el elemento. Aquí está la comparación, modificando el ejemplo de mnel:
m = matrix(rnorm(1200000), ncol=600)
v = rep(c(1.5, 3.5, 4.5, 5.5, 6.5, 7.5), length = ncol(m))
library(microbenchmark)
microbenchmark(t(t(m) * v),
m %*% diag(v),
m * rep(v, rep.int(nrow(m),length(v))),
m * rep(v, rep(nrow(m),length(v))),
m * rep(v, each = nrow(m)))
# Unit: milliseconds
# expr min lq mean median uq max neval
# t(t(m) * v) 17.682257 18.807218 20.574513 19.239350 19.818331 62.63947 100
# m %*% diag(v) 415.573110 417.835574 421.226179 419.061019 420.601778 465.43276 100
# m * rep(v, rep.int(nrow(m), ncol(m))) 2.597411 2.794915 5.947318 3.276216 3.873842 48.95579 100
# m * rep(v, rep(nrow(m), ncol(m))) 2.601701 2.785839 3.707153 2.918994 3.855361 47.48697 100
# m * rep(v, each = nrow(m)) 21.766636 21.901935 23.791504 22.351227 23.049006 66.68491 100
Como puede ver, el uso de "each" en rep () sacrifica la velocidad por claridad. La diferencia entre rep.int y rep parece ser despreciable, ambas implementaciones intercambian lugares en series repetidas de microbenchmark (). Tenga en cuenta que ncol (m) == longitud (v).
Usa un poco de álgebra lineal y realiza la multiplicación de matrices, que es bastante rápida en R
p.ej
m %*% diag(v)
algunos puntos de referencia
m = matrix(rnorm(1200000), ncol=6)
v=c(1.5, 3.5, 4.5, 5.5, 6.5, 7.5)
library(microbenchmark)
microbenchmark(m %*% diag(v), t(t(m) * v))
## Unit: milliseconds
## expr min lq median uq max neval
## m %*% diag(v) 16.57174 16.78104 16.86427 23.13121 109.9006 100
## t(t(m) * v) 26.21470 26.59049 32.40829 35.38097 122.9351 100