J'ai un matrix
numérique avec 25 colonnes et 23 lignes, et un vecteur de longueur 25. Comment puis-je multiplier chaque ligne de la matrice par le vecteur sans utiliser une boucle for
?
Le résultat doit être une matrice 25x23 (la même taille que l'entrée), mais chaque ligne a été multipliée par le vecteur.
Exemple reproductible ajouté de la réponse de @ hatmatrix:
matrix <- matrix(rep(1:3,each=5),nrow=3,ncol=5,byrow=TRUE)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
vector <- 1:5
sortie souhaitée:
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 2 4 6 8 10
[3,] 3 6 9 12 15
Je pense que vous recherchez sweep()
.
# Create example data and vector
mat <- matrix(rep(1:3,each=5),nrow=3,ncol=5,byrow=TRUE)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
vec <- 1:5
# Use sweep to apply the vector with the multiply (`*`) function
# across columns (See ?apply for an explanation of MARGIN)
sweep(mat, MARGIN=2, vec, `*`)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 2 4 6 8 10
[3,] 3 6 9 12 15
C'est l'une des fonctions principales de R, bien que des améliorations y aient été apportées au fil des ans.
> MyMatrix <- matrix(c(1,2,3, 11,12,13), nrow = 2, ncol=3, byrow=TRUE)
> MyMatrix
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 11 12 13
> MyVector <- c(1:3)
> MyVector
[1] 1 2 3
Vous pouvez utiliser soit:
> t(t(MyMatrix) * MyVector)
[,1] [,2] [,3]
[1,] 1 4 9
[2,] 11 24 39
ou:
> MyMatrix %*% diag(MyVector)
[,1] [,2] [,3]
[1,] 1 4 9
[2,] 11 24 39
En fait, sweep
n'est pas l'option la plus rapide sur mon ordinateur:
MyMatrix <- matrix(c(1:1e6), ncol=1e4, byrow=TRUE)
MyVector <- c(1:1e4)
Rprof(tmp <- tempfile(),interval = 0.001)
t(t(MyMatrix) * MyVector) # first option
Rprof()
MyTimerTranspose=summaryRprof(tmp)$sampling.time
unlink(tmp)
Rprof(tmp <- tempfile(),interval = 0.001)
MyMatrix %*% diag(MyVector) # second option
Rprof()
MyTimerDiag=summaryRprof(tmp)$sampling.time
unlink(tmp)
Rprof(tmp <- tempfile(),interval = 0.001)
sweep(MyMatrix ,MARGIN=2,MyVector,`*`) # third option
Rprof()
MyTimerSweep=summaryRprof(tmp)$sampling.time
unlink(tmp)
Rprof(tmp <- tempfile(),interval = 0.001)
t(t(MyMatrix) * MyVector) # first option again, to check order
Rprof()
MyTimerTransposeAgain=summaryRprof(tmp)$sampling.time
unlink(tmp)
MyTimerTranspose
MyTimerDiag
MyTimerSweep
MyTimerTransposeAgain
Cela donne:
> MyTimerTranspose
[1] 0.04
> MyTimerDiag
[1] 40.722
> MyTimerSweep
[1] 33.774
> MyTimerTransposeAgain
[1] 0.043
En plus d'être l'option la plus lente, la deuxième option atteint la limite de mémoire (2046 Mo). Cependant, compte tenu des options restantes, la double transposition semble bien meilleure que sweep
à mon avis.
Modifier
Il suffit d'essayer de plus petites données plusieurs fois:
MyMatrix <- matrix(c(1:1e3), ncol=1e1, byrow=TRUE)
MyVector <- c(1:1e1)
n=100000
[...]
for(i in 1:n){
# your option
}
[...]
> MyTimerTranspose
[1] 5.383
> MyTimerDiag
[1] 6.404
> MyTimerSweep
[1] 12.843
> MyTimerTransposeAgain
[1] 5.428
Pour la vitesse, on peut créer une matrice à partir du vecteur avant de multiplier
mat <- matrix(rnorm(1e6), ncol=1e4)
vec <- c(1:1e4)
mat * matrix(vec, dim(mat)[1], length(vec))
library(microbenchmark)
microbenchmark(
transpose = t(t(mat) * vec),
make_matrix = mat * matrix(vec, dim(mat)[1], length(vec), byrow = TRUE),
sweep = sweep(mat,MARGIN=2,vec,`*`))
#Unit: milliseconds
# expr min lq mean median uq max neval cld
# transpose 9.940555 10.480306 14.39822 11.210735 16.19555 77.67995 100 b
#make_matrix 5.556848 6.053933 9.48699 6.662592 10.74121 74.14429 100 a
# sweep 8.033019 8.500464 13.45724 12.331015 14.14869 77.00371 100 b