J'ai une matrice m
et un vecteur v
. Je voudrais multiplier la première colonne de la matrice m
par le premier élément du vecteur v
et multiplier la deuxième colonne de la matrice m
par le deuxième élément du vecteur v
et ainsi de suite. Je peux le faire avec le code suivant, mais je cherche un moyen qui n'exige pas les deux appels de transposition. Comment puis-je faire cela plus vite dans 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
Si vous avez un plus grand nombre de colonnes, votre solution t(t(m) * v) surpasse largement la solution de multiplication de matrice. Cependant, il existe une solution plus rapide, mais elle entraîne un coût élevé d’utilisation de la mémoire. Vous créez une matrice aussi grande que m en utilisant rep () et multipliez élément par élément. Voici la comparaison, modifiant l'exemple 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
Comme vous pouvez le constater, utiliser "each" dans rep () sacrifie la vitesse pour plus de clarté. La différence entre rep.int et rep semble être négligeable, les deux implémentations échangent leurs places sur des exécutions répétées de microbenchmark (). N'oubliez pas que ncol (m) == longueur (v).
Comme @Arun le souligne, je ne pense pas que vous allez battre votre solution en termes de gain de temps. En termes de compréhensibilité du code, il existe cependant d'autres options:
Une option:
> 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
Et un autre:
sapply(1:ncol(m),function(x) m[,x] * v[x] )
Par souci d’exhaustivité, j’ai ajouté sweep
au repère. Malgré ses noms d'attributs quelque peu trompeurs, je pense qu'il peut être plus lisible que d'autres alternatives, et aussi assez rapide:
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
Comme le fait Bluegrue, un simple représentant suffirait également pour effectuer la multiplication élément par élément.
Le nombre de multiplications et de sommations est considérablement réduit, comme si une simple multiplication de matrice avec diag()
était effectuée, ce qui permet d'éviter beaucoup de multiplications nulles.
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