Row-wise division is common in data normalization and scaling operations. NumPy's broadcasting rules require reshaping 1D vectors to column vectors for proper alignment with 2D matrices.
The Problem
When dividing a matrix by a vector, you need each row divided by a corresponding value:
import numpy as np
matrix = np.array([
[10, 20, 30],
[40, 50, 60]
])
divisors = np.array([10, 5]) # Row 0 ÷ 10, Row 1 ÷ 5
try:
result = matrix / divisors
except ValueError as e:
print(f"Error: {e}")Output:
Error: operands could not be broadcast together with shapes (2,3) (2,) The shapes don't align for broadcasting because NumPy tries to match from the right.
The Solution: Using np.newaxis
Reshape the divisor vector to a column vector with [:, np.newaxis]:
import numpy as np
matrix = np.array([
[10, 20, 30],
[40, 50, 60]
])
divisors = np.array([10, 5])
result = matrix / divisors[:, np.newaxis]
print(result)Output:
[[ 1. 2. 3.]
[ 8. 10. 12.]]Step-by-Step Breakdown
import numpy as np
matrix = np.array([[10, 20, 30],
[40, 50, 60]])
divisors = np.array([10, 5])
print(f"Matrix shape: {matrix.shape}") # (2, 3)
print(f"Divisors shape: {divisors.shape}") # (2,)
column_divisors = divisors[:, np.newaxis]
print(f"Column divisors shape: {column_divisors.shape}") # (2, 1)
print(f"Column divisors:\n{column_divisors}")
result = matrix / column_divisors
print(f"Result:\n{result}")Output:
Matrix shape: (2, 3)
Divisors shape: (2,)
Column divisors shape: (2, 1)Understanding Broadcasting
Broadcasting aligns shapes from the right. For row-wise operations, the divisor needs a trailing dimension of 1:
| Array | Shape | Alignment |
|---|---|---|
matrix |
(2, 3) |
2 × 3 |
divisors |
(2,) |
? × 2 ❌ |
divisors[:, np.newaxis] |
(2, 1) |
2 × 1 ✅ |
import numpy as np
matrix = np.array([[10, 20, 30],
[40, 50, 60]])
divisors = np.array([[10], # Broadcasts across row 0
[5]]) # Broadcasts across row 1
print("Matrix:")
print(matrix)
print("\nDivisors:")
print(divisors)
result = matrix / divisors # Broadcasting happens here
print("\nResult:")
print(result)
Output:
Matrix:
[[10 20 30]
[40 50 60]]
Divisors:
[[10]
[ 5]]
Result:
[[ 1. 2. 3.]
[ 8. 10. 12.]]Alternative: Using reshape()
reshape(-1, 1) achieves the same result:
import numpy as np
matrix = np.array([[10, 20, 30],
[40, 50, 60]])
divisors = np.array([10, 5])
result = matrix / divisors.reshape(-1, 1)
print(result)Output:
[[ 1. 2. 3.]
[ 8. 10. 12.]]Alternative: Using None
None is an alias for np.newaxis:
import numpy as np
matrix = np.array([[10, 20, 30],
[40, 50, 60]])
divisors = np.array([10, 5])
result = matrix / divisors[:, None]
print(result)Output:
[[ 1. 2. 3.]
[ 8. 10. 12.]]Row-wise vs Column-wise Operations
Understanding the difference helps avoid confusion:
import numpy as np
matrix = np.array([[10, 20, 30],
[40, 50, 60]])
row_divisors = np.array([10, 5]) # 2 values (one per row)
col_divisors = np.array([10, 20, 30]) # 3 values (one per column)
row_result = matrix / row_divisors[:, np.newaxis]
print("Row-wise division:")
print(row_result)
col_result = matrix / col_divisors # No reshape needed!
print("\nColumn-wise division:")
print(col_result)Output:
Row-wise division:
[[ 1. 2. 3.]
[ 8. 10. 12.]]
Column-wise division:
[[1. 1. 1. ]
[4. 2.5 2. ]]Practical Examples
Normalizing Rows by Their Sum
import numpy as np
data = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])
row_sums = data.sum(axis=1)
print(f"Row sums: {row_sums}")
normalized = data / row_sums[:, np.newaxis]
print("Normalized rows:")
print(normalized)
print(f"Row sums after normalization: {normalized.sum(axis=1)}")Output:
Row sums: [ 6 15 24]
Normalized rows:
[[0.16666667 0.33333333 0.5 ]
[0.26666667 0.33333333 0.4 ]
[0.29166667 0.33333333 0.375 ]]
Row sums after normalization: [1. 1. 1.]Dividing by Row Maximum
import numpy as np
data = np.array([
[10, 20, 30],
[5, 15, 25],
[100, 200, 150]
])
row_max = data.max(axis=1)
print(f"Row max: {row_max}")
scaled = data / row_max[:, np.newaxis]
print("Scaled by row max:")
print(scaled)Output:
Row max: [ 30 25 200]
Scaled by row max:
[[0.33333333 0.66666667 1. ]
[0.2 0.6 1. ]
[0.5 1. 0.75 ]]Z-Score Normalization by Row
import numpy as np
data = np.array([
[10, 20, 30],
[100, 200, 300],
[5, 10, 15]
])
row_means = data.mean(axis=1)
row_stds = data.std(axis=1)
z_scores = (data - row_means[:, np.newaxis]) / row_stds[:, np.newaxis]
print("Z-scores by row:")
print(z_scores)Output:
Z-scores by row:
[[-1.22474487 0. 1.22474487]
[-1.22474487 0. 1.22474487]
[-1.22474487 0. 1.22474487]]Other Row-wise Operations
The same pattern works for other operations:
import numpy as np
matrix = np.array([[10, 20, 30],
[40, 50, 60]])
row_values = np.array([5, 10])
print(matrix + row_values[:, np.newaxis])
print(matrix - row_values[:, np.newaxis])
print(matrix * row_values[:, np.newaxis])Output:
[[15 25 35]
[50 60 70]]
[[ 5 15 25]
[30 40 50]]
[[ 50 100 150]
[400 500 600]]Quick Reference
| Operation | Vector Shape | Code |
|---|---|---|
| Divide each row | (n_rows,) → (n_rows, 1) |
matrix / vec[:, np.newaxis] |
| Divide each column | (n_cols,) |
matrix / vec (no reshape) |
| Scalar division | () |
matrix / scalar |
Summary
Use vector[:, np.newaxis] or vector.reshape(-1, 1) to convert a 1D array into a column vector for row-wise operations.
This aligns the shapes for NumPy broadcasting, allowing each row to be divided (or multiplied, added, etc.) by its corresponding value in the vector.