In short
It's easy to scale the rows, or the columns, of a matrix using a diagonal matrix and matrix multiplication.
import numpy as np
M = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
# Pre-multiply by a diagonal matrix to scale rows
C = np.diag([0,1,2]) # Create a diagonal matrix
R = C @ M
# For the related scaling of columns, change the order of the product
# C = np.diag([0,1,2])
# R = M @ C
M, C, R values:
[[1 2 3] [[0 0 0] [[ 0 0 0]
[4 5 6] [0 1 0] [ 4 5 6]
[7 8 9]] [0 0 2]] [14 16 18]]
There are variants involving the product of a vector by a matrix and transpose, but the solution above is as simple to scale the rows, and by inverting the order of the multiplication (R = M @ C), to scale the columns as well, regardless of whether the matrix is square or not.
Explanation
Refresher: The dot product of two vectors is a single number, the sum of the individual element-wise products:
( a b c ) . ( d e f ) = ad + be + cf
Matrix multiplication involves dot products of a row by a column, and the result depends on the order of the matrices (matrix multiplication is not commutative).
| a b | | x y | | ax+bz ay+bt |
| c d | x | z t | = | cx+dz cy+dt |
Note how element (row 2, col 1) of the result is the dot product of row 2 of the first matrix by col 1 of the second matrix.
Thus your problem is to find a matrix of coefficients which performs the correct dot products, and select in which order the matrices must be multiplied.
If you think about the result above, setting elements not on the diagonal to zero in one matrix simplifies the dot products, and results in a scaling of the other matrix either by rows or by columns. E.g
| a 0 | | x y | | ax+0z ay+0t | | ax ay |
| 0 d | x | z t | = | 0x+dz 0y+dt | = | dz dt |
The result is the second matrix rows have been scaled respectively by a and d, which are the values on the diagonal of the first matrix. Similarly:
| x y | | a 0 | | ax+0y 0x+dy | | ax dy |
| z t | x | 0 d | = | az+0t 0z+dt | = | az dt |
The result is the first matrix columns have been scaled by the diagonal elements of the second matrix.
The change in the multiplication order seen above is explained by the fact you can get the same result by pre-multiplying the transpose of the matrix, and taking the transpose of the result, with is linked with your attempt to use transposes. This operation corresponds to R = (C * M.T).T. But on the other hand matrix transpose has this property: (AB).T = (B.T)(A.T). Hence R = M(C.T) which is equal to R = MC, because C is a diagonal matrix, and its transpose is itself.
Thus back to your problem: You want to scale the rows, thus set a diagonal matrix with your coefficients and pre-multiply your matrix by the diagonal matrix:
Diagonal matrix:
coeffs = [0,1,2]
C = np.diag(coeffs)
Pre-multiply:
M = np.array([[1,2,3],
[4,5,6],
[7,8,9]])
R = C @ M # operator @ is a shortcut for matrix multiplication
A * Byou'd have to doA * B[...,None]which transposesBby adding a new axis (None).x = [[1],[2],[3]]or something.