1D with 2D: Per-Column
Rule 2 from class: a 1D array whose length matches the number of columns broadcasts across every row — one value per match (column).
Suppose every match was played on a different pitch, and the analyst gives each match a pitch difficulty multiplier — one number per match. You want to apply that multiplier to every player's score in that match. The squad table is 2D, the multipliers are 1D. This is the most common useful broadcast: 1D with 2D.
Definition
When a 1D array of length n is combined with a 2D array of shape (rows, n), NumPy treats the 1D array as shape (1, n) and repeats it down every row. Each value of the 1D array is applied to one column of the 2D array.
- Length n must equal the number of columns (the last dimension) — because shapes are aligned from the right.
- (1, n) — the missing leading dimension becomes 1, which then stretches to
rows. - One value per column — in our squad table, columns are matches, so this gives a per-match adjustment.
Picture it
text
squad_scores (5, 6) <- 5 players, 6 matches
pitch_multiplier (6,) <- one value per match
Conceptually pitch_multiplier becomes:
[[m1, m2, m3, m4, m5, m6], <- reused for Virat
[m1, m2, m3, m4, m5, m6], <- reused for Rohit
[m1, m2, m3, m4, m5, m6], <- reused for Hardik
[m1, m2, m3, m4, m5, m6], <- reused for Shubman
[m1, m2, m3, m4, m5, m6]] <- reused for ShreyasNothing is actually copied — NumPy re-reads the same 6 numbers for each row.
Syntax
python
result = array_2d <op> array_1d # array_1d.shape == (array_2d.shape[1],)| Piece | Meaning | Requirement |
|---|---|---|
array_2d | the big table, shape (rows, cols) | — |
array_1d | one value per column, shape (cols,) | length must equal cols |
<op> | any element-wise operator: + - * / ** > == … | — |
| result | shape (rows, cols) | — |
Example — per-match pitch multiplier
python
import numpy as np
squad_scores = np.array([
[72, 45, 88, 31, 64, 0], # Virat
[56, 0, 74, 88, 32, 45], # Rohit
[45, 32, 0, 67, 18, 54], # Hardik
[33, 61, 45, 0, 77, 83], # Shubman
[88, 14, 57, 72, 0, 38], # Shreyas
])
pitch_multiplier = np.array([1.0, 1.2, 0.9, 1.1, 1.0, 1.3])
print("squad_scores shape: ", squad_scores.shape)
print("pitch_multiplier shape:", pitch_multiplier.shape)
adjusted = squad_scores * pitch_multiplier
print(adjusted.round(1))
print(adjusted.shape)text
squad_scores shape: (5, 6)
pitch_multiplier shape: (6,)
[[ 72. 54. 79.2 34.1 64. 0. ]
[ 56. 0. 66.6 96.8 32. 58.5]
[ 45. 38.4 0. 73.7 18. 70.2]
[ 33. 73.2 40.5 0. 77. 107.9]
[ 88. 16.8 51.3 79.2 0. 49.4]]
(5, 6)How it works: right-aligned, 6 vs 6 match; the missing dimension (1) stretches to 5. So column 2 (match 2, multiplier 1.2) is multiplied by 1.2 for every player: Virat 45 → 54.0, Shubman 61 → 73.2.
Example — marks as a percentage of each subject's maximum
From class: 4 students × 3 subjects (science, maths, English), each subject has a different maximum.
python
marks = np.array([[10, 11, 15],
[11, 14, 12],
[ 9, 17, 13],
[12, 18, 14]])
max_marks = np.array([15, 20, 15])
print((marks / max_marks * 100).round(1))text
[[ 66.7 55. 100. ]
[ 73.3 70. 80. ]
[ 60. 85. 86.7]
[ 80. 90. 93.3]]How it works: (4, 3) with (3,) → each column is divided by its own maximum. Science /15, maths /20, English /15 — for all 4 students at once.
Example — compare each score with the match average
A very common pattern is aggregate, then broadcast back. mean(axis=0) gives one value per column, shape (6,) — exactly the shape that broadcasts across rows.
python
match_avg = squad_scores.mean(axis=0)
print(match_avg.round(1))
print((squad_scores - match_avg).round(1))text
[58.8 30.4 52.8 51.6 38.2 44. ]
[[ 13.2 14.6 35.2 -20.6 25.8 -44. ]
[ -2.8 -30.4 21.2 36.4 -6.2 1. ]
[-13.8 1.6 -52.8 15.4 -20.2 10. ]
[-25.8 30.6 -7.8 -51.6 38.8 39. ]
[ 29.2 -16.4 4.2 20.4 -38.2 -6. ]]How it works: positive numbers = scored above that match's average, negative = below. Virat's 88 in match 3 is +35.2 above the average of 52.8.
Comparison — which 1D shape goes where?
| 2D shape | 1D length | Broadcasts? | Applied per… |
|---|---|---|---|
(5, 6) | 6 | ✅ | column (match) |
(5, 6) | 5 | ❌ ValueError | — reshape to (5, 1) (next topic) |
(5, 6) | 1 | ✅ | every element (like a scalar) |
(6, 6) | 6 | ✅ | column — even if you meant row! |
Common mistakes
- ❌ Using a 1D array whose length equals the number of rows. ✅ Plain 1D always matches the last dimension (columns). For rows, see the next topic.
- ❌ Forgetting that
mean(axis=0)gives per-column values andmean(axis=1)per-row values. ✅ Per-column results broadcast back directly; per-row results needreshape(-1, 1)orkeepdims=True. - ❌ On a square table, assuming a 1D array was applied per row because there was no error. ✅ It was applied per column — check with a tiny example.
Interview tip
Q: You have X of shape (1000, 4) (1000 rows, 4 features). How do you standardise every feature column in one line?
A: (X - X.mean(axis=0)) / X.std(axis=0) — both statistics have shape (4,), which broadcasts across all 1000 rows.
Key points to remember
- A 1D array of length n broadcasts with a 2D array of shape (rows, n) — it is treated as (1, n).
- The 1D values are applied per column: one value per match in the squad table.
- The 1D length must equal the LAST dimension (number of columns), not the number of rows.
- Aggregating with axis=0 gives a per-column array that broadcasts straight back: X - X.mean(axis=0).
- On a square array a 1D array silently applies per column — there is no error to warn you.
- The result always has the 2D array's shape (rows, n).
Try it yourself
Per-match pitch multiplier
Above or below the match average
Practice: marks to percentages
Revision Flashcards
Tap a card to flip it and see the answer.
