def f_b_v2(M):
arySum = M.sum(0)
return M / arySum.reshape((1, M.shape[1]))
arySum = M.sum(0)
M.sum(0)
sums up the elements of the array M
along axis 0, i.e., column-wise.
- If
M
has shape $(n, m)$, the result of M.sum(0)
will be a 1D array of length $m$, containing the sum of each column.
- We store this in
arySum
. For example, if M
is the example 3 x 4 matrix, arySum
would be a 1D array of size 4, each element being the sum of a column in M
.
arySum.reshape((1, M.shape[1]))
- Since
M.shape[1]
is the number of columns $m$, arySum.reshape((1, m))
converts the 1D array of length $m$ into a 2D array with shape $(1, m$).
- This reshaping is crucial for broadcasting to work correctly in the next step. In numpy, broadcasting allows operations between arrays of compatible shapes. Here, we want each element in row $i$ of
M
to be divided by the appropriate column sum.
- By reshaping into $(1, m)$, we align shapes so that
M
(which is $(n, m)$) can be divided column-by-column by the 2D array $(1, m)$.
return M / arySum.reshape((1, M.shape[1]))
- This performs an element-wise division of
M
by the reshaped arySum
.
- Because
arySum.reshape((1, m))
matches the columns of M
, each column in M
is divided by its corresponding sum.
- The result is a new array with the same shape as
M
, in which the sum of each column is now 1.
Why This Version is More Concise
- Vectorized Operations: Instead of manually looping over rows and columns, we use
M.sum(0)
to directly obtain the column sums and then rely on broadcasting to divide each element by the right column sum.
- Fewer Lines of Code: There is no need to initialise intermediate arrays or use nested loops, because numpy handles all of that internally.