P2-11.3 Broadcasting and Vectorization¶
Section ID:
P2-11.3Version:v2026.09.15
Scalars and Arrays¶
NumPy describes broadcasting as the rules for arithmetic on arrays with different shapes. A smaller array is treated as having a shape compatible with the larger one for the calculation.
Broadcasting applies a common calculation rule across arrays of different shapes.
Add 10 to or multiply by 2 each score in [82, 75, 45]. The results are [92, 85, 55] and [164, 150, 90].
Output:
10 and 2 are scalars. NumPy applies each scalar at every array position.
The diagram shows a scalar applied across an array. This is a calculation rule, not a requirement to physically copy the scalar many times.
flowchart TD
a["scores = [82, 75, 45]<br/>shape = (3,)"]
a --> b["scores + 10<br/>Add 10 to every element"]
b --> c["[92, 85, 55]<br/>shape = (3,)"]
Adding Feature Offsets¶
Broadcasting cannot force arbitrary arrays to fit. Their shapes must be compatible.
Put four samples with three features each into a matrix and add [0.1, 0.2, 0.3] by feature. The first sample changes from [1.0, 0.2, 7.0] to [1.1, 0.4, 7.3].
Output:
Here rows are samples and columns are features, so (4, 3) means four samples and three features.
feature_offset has shape (3,): one value to add to each feature.
NumPy applies the (3,) array to each row, adding the same three offsets to every sample.
The diagram shows a (3,) vector applied row by row to a (4, 3) matrix.
flowchart TD
a["features = [[1.0, 0.2, 7.0],<br/>[0.8, 0.4, 6.5],<br/>[0.3, 0.9, 8.1],<br/>[0.5, 0.1, 5.8]]<br/>shape = (4, 3)"]
b["feature_offset = [0.1, 0.2, 0.3]<br/>shape = (3,)"]
a --> c["features + feature_offset<br/>Add to the matching column in every row"]
b --> c
c --> d["[[1.1, 0.4, 7.3],<br/>[0.9, 0.6, 6.8],<br/>[0.4, 1.1, 8.4],<br/>[0.6, 0.3, 6.1]]<br/>shape = (4, 3)"]
Shape Compatibility¶
Adding a length-four vector to this matrix raises ValueError. Four rows do not help: the trailing dimension has three columns.
This code raises an error:
features has shape (4, 3) with three features per row. bad_offset has shape (4,). Its length matches the row count, but not the three columns within each row.
| Calculation | Reading | Result |
|---|---|---|
(4, 3) + scalar | Apply one value everywhere | Valid |
(4, 3) + (3,) | Apply a length-three vector to every row | Valid |
(4, 3) + (4,) | Length four does not match three columns | Error |
Broadcasting compares dimensions from the end. Corresponding sizes must be equal or one must be 1; absent leading dimensions count as 1. (4, 3) and (3,) match at the end, while (4, 3) and (4,) conflict at sizes 3 and 4.
Loops and Array Operations¶
Vectorization expresses calculation through array operations instead of explicit loops in the code.
For example, a Python loop can add 10 to every score:
The loop prints [92, 85, 55]. With a NumPy array, scores + 10 calculates the same three values.
Both add 10 per score; their expressions differ.
| Method | Visible code structure | Interpretation |
|---|---|---|
| Python loop | Retrieve and process values individually | Write the procedure explicitly |
| NumPy vectorization | Apply an operation to the array | Express the calculation at array level |
NumPy's documentation explains that broadcasting supports vectorization with looping at the C level instead of Python. Vectorization does not mean that repetition disappears.
This diagram compares the loop and array expressions for the same calculation.
flowchart TD
a["Python loop<br/>adjusted = []<br/>for score in scores:<br/>adjusted.append(score + 10)"]
a --> b["Same calculation"]
b --> c["NumPy vectorization<br/>adjusted = scores + 10"]
Subtracting Feature Means¶
Subtracting each feature's mean is common in AI data processing. It is a starting point for centering features near zero.
The four samples have column means [0.65, 0.4, 6.85]. Subtracting them from each row makes the first row [0.35, -0.2, 0.15].
The output is approximately:
features.mean(axis=0) computes one mean per column, with shape (3,). The original features has shape (4, 3).
features - column_mean subtracts (3,) from (4, 3), applying the mean vector to every row.
| Code | Shape | Meaning |
|---|---|---|
features | (4, 3) | Four samples, three features |
features.mean(axis=0) | (3,) | Feature means |
features - column_mean | (4, 3) | Feature means subtracted from every sample |
The centered column means are zero within floating-point error. Switching to axis=1 produces four row means of shape (4,), making this subtraction fail.
Row Means and keepdims¶
To subtract each student's mean from that student's subjects, retain row means as (students, 1). keepdims=True keeps reduced axes with length 1 rather than removing them.
Without keepdims, means have shape (2,) and cannot be subtracted directly from (2, 3). For a three-by-three square array, subtracting (3,) may succeed but aligns those values with columns, not rows. Successful execution does not establish the intended axis semantics. For row centering, also check that resulting row means are near zero.
Intermediate Arrays and Memory¶
Broadcasting can avoid repeating input data, but result arrays still need memory. Adding (10000, 1) and (1, 10000) produces (10000, 10000). Its 100 million float64 elements alone require about 800 MB. Check the output shape as well as input sizes.
Example Code File¶
The examples are also available here:
Locally, run from the project root:
In Colab, paste the file into a code cell.
Outputs cover scalar broadcasting, row-vector broadcasting, a shape mismatch, and subtraction of feature means.
Case: Subject and Student Adjustments¶
Two students score [80, 70, 90] and [60, 90, 75] in Korean, mathematics, and English. To add 5, 10, and 0 by subject, use a length-three vector. Results are [85, 80, 90] and [65, 100, 75].
To add 5 to the first student's subjects and 10 to the second student's, use shape (2, 1). Each row's adjustment applies to all three subjects. Writing [5, 10] instead gives (2,), incompatible with the trailing dimension 3.
Changing the second subject_bonus from 10 to 0 restores only mathematics scores to 70 and 90 in the first output. Changing the second student_bonus to 0 restores every score of the second student in the second output. Placement determines what the addition affects.
Checklist¶
- Explain scalar–array arithmetic through broadcasting.
- Explain why
(4, 3) + (3,)works. - Explain why
(4, 3) + (4,)fails. - Distinguish Python loops from NumPy vectorized expressions.
- Explain the shape of
features.mean(axis=0). - Identify broadcasting when subtracting feature means.
- Explain why broadcasting requires attention to shapes and memory.
- Can you explain why row centering uses
keepdims=Trueand how to check the result?
Sources and References¶
- NumPy Developers, Broadcasting, NumPy Manual, checked on 2026-07-20. Used as the core basis for broadcasting rules, dimension comparison, and shape mismatch errors.
- NumPy Developers, NumPy quickstart, NumPy Manual, checked on 2026-07-20. Used to confirm array arithmetic, universal functions, and basic axis-calculation examples.
- NumPy Developers, NumPy: the absolute basics for beginners, NumPy Manual, checked on 2026-07-20. Used as the basis for the beginner-level flow of reading array-level computation instead of Python loops and checking shape first.
- NumPy Developers, numpy.mean, NumPy Manual, accessed: 2026-09-15. axis reduction and axis preservation with keepdims.