Broadcasting
Normalize Rows
Divide every element in a row by that row's sum so each row sums to 1. This is a common pre-processing step: once every row is a probability vector, rows from different datasets become comparable.
By hand
Loop over the 2×3 dataset one row at a time. Compute row_sum with the
built-in sum, then divide each element and collect the result.
naive.py
Replay: real traced execution (multi-file project)
data = [[3, 3, 6], [4, 2, 2]]
result = []
for row in data:
row_sum = sum(row)
norm_row = [v / row_sum for v in row]
result.append(norm_row)
print('RESULT:', [[round(v, 10) for v in row] for row in result])
data ← [[3, 3, 6], [4, 2, 2]]
1data = [[3, 3, 6], [4, 2, 2]]2result = []values this step[[3, 3, 6], [4, 2, 2]]dataresult ← []
1data = [[3, 3, 6], [4, 2, 2]]2result = []3for row in data:values this step[]resultrow ← [3, 3, 6]
2result = []3for row in data:4 row_sum = sum(row)values this step[3, 3, 6]rowrow_sum ← 12
3for row in data:4 row_sum = sum(row)5 norm_row = [v / row_sum for v in row]values this step12row_sumnorm_row ← [0.25, 0.25, 0.5]
4row_sum = sum(row)5norm_row = [v / row_sum for v in row]6result.append(norm_row)values this step[0.25, 0.25, 0.5]norm_rowresult ← [[0.25, 0.25, 0.5]]
5 norm_row = [v / row_sum for v in row]6 result.append(norm_row)7print('RESULT:', [[round(v, 10) for v in row] for row in result])values this step[] → [[0.25, 0.25, 0.5]]resultrow ← [4, 2, 2]
2result = []3for row in data:4 row_sum = sum(row)values this step[3, 3, 6] → [4, 2, 2]rowrow_sum ← 8
3for row in data:4 row_sum = sum(row)5 norm_row = [v / row_sum for v in row]values this step12 → 8row_sumnorm_row ← [0.5, 0.25, 0.25]
4row_sum = sum(row)5norm_row = [v / row_sum for v in row]6result.append(norm_row)values this step[0.25, 0.25, 0.5] → [0.5, 0.25, 0.25]norm_rowresult ← [[0.25, 0.25, 0.5], [0.5, 0.25, 0.25]]
5 norm_row = [v / row_sum for v in row]6 result.append(norm_row)7print('RESULT:', [[round(v, 10) for v in row] for row in result])values this step[[0.25, 0.25, 0.5]] → [[0.25, 0.25, 0.5], [0.5, 0.25, 0.25]]resultfor row in data:
2result = []3for row in data:4 row_sum = sum(row)stdout ← RESULT: [[0.25, 0.25, 0.5], [0.5, 0.25, 0.25]]
6 result.append(norm_row)7print('RESULT:', [[round(v, 10) for v in row] for row in result])values this stepRESULT: [[0.25, 0.25, 0.5], [0.5, 0.25, 0.25]]stdout
With NumPy
np.array stores the matrix in a typed buffer. sum(axis=1, keepdims=True)
produces a (2, 1) column vector of row sums; dividing the (2, 3) matrix by
this (2, 1) vector broadcasts automatically — NumPy aligns the singleton
dimension and repeats the division across all three columns without an explicit
loop. The snapshot shows row_sums and the normalized result.
library.py
import numpy as np
data = np.array([[3, 3, 6], [4, 2, 2]], dtype=float)
row_sums = data.sum(axis=1, keepdims=True)
result = data / row_sums
rv = [[round(v, 10) for v in row] for row in result.tolist()]
print('row_sums: shape:', row_sums.shape, 'dtype:', row_sums.dtype, 'values:', row_sums.tolist())
print('result: shape:', result.shape, 'dtype:', result.dtype)
print('result values:', rv)
print('RESULT:', rv)
row_sums: shape: (2, 1) dtype: float64 values: [[12.0], [8.0]]
result: shape: (2, 3) dtype: float64
result values: [[0.25, 0.25, 0.5], [0.5, 0.25, 0.25]]
RESULT: [[0.25, 0.25, 0.5], [0.5, 0.25, 0.25]]
Implementation notes
keepdims=Truepreserves the reduced axis as a size-1 dimension, giving shape(2, 1)instead of(2,). Without it, broadcasting would fail: a(2,)vector cannot be divided into a(2, 3)matrix along the row axis.- This is the
column-broadcastpattern: the(2, 1)column vector broadcasts across all 3 columns ofa, applying a different divisor to each row. - After normalization, each row sums to 1.0 (within floating-point precision), making each row a probability vector.
- The next step in standardization is z-scoring: subtract the column mean (see
center-columns) and divide by the column standard deviation — that lesson is in the roadmap statistics chapter. - Shape, dtype, and values are shown explicitly here because
ndarray.__repr__output varies with NumPy version and print options.