Two more possibilities: sweep and scale (the latter works only on columns and seems a bit hacked to me).
coef <- c(1.5,2.4,3.9,4.4) y <- matrix(c(seq(1,17,by=4), seq(2,18,by=4), c(12,7,2,15,39, 45,8,12,45,7)), ncol=4) t(t(y)*coef) t(apply(y,1,"*",coef)) sweep(y,2,coef,"*") scale(y,center=FALSE,scale=1/coef) library(rbenchmark) benchmark(t(t(y)*coef), y %*% diag(coef), t(apply(y,1,"*",coef)), sweep(y,2,coef,"*"), scale(y,center=FALSE,scale=1/coef), replications=1e4) test replications elapsed relative 5 scale(y, center = FALSE, scale = 1/coef) 10000 0.990 4.342105 4 sweep(y, 2, coef, "*") 10000 0.846 3.710526 3 t(apply(y, 1, "*", coef)) 10000 1.537 6.741228 1 t(t(y) * coef) 10000 0.228 1.000000 2 y %*% diag(coef) 10000 0.365 1.600877
edit : added y %*% diag(coef) from @baptiste [not faster, although it could be for a big problem with a fairly optimized BLAS package ...] [and it was faster in another test, so I might just not have stable evaluation]
edit : typo fixed in t(t(y)*coef) [thanks Timur Shtatland] (but failed to update the timings, so they can be turned off a bit ...)
I also tried library(Matrix); y %*% Diagonal(x=coef) library(Matrix); y %*% Diagonal(x=coef) , which is very slow for this example, but can be fast for a large matrix (??). (I also tried to build the diagonal matrix only once, but even in this example, even multiplying by a predefined matrix was slow (25 times slower than the best, versus 47 times slower when defining the matrix on the fly.)
I have a soft sweep preference as I think it most clearly expresses the operation being performed ("multiply columns by coef elements")