P2-15.1 A Small Procedure for Translating Formulas into Code¶
Section ID:
P2-15.1Version:v2026.09.15
Symbols and Computation Order¶
Distinguish symbols representing one input value from those representing collections. Separate calculations applied to each value from operations that combine the whole collection.
To summarize errors for three predictions, first pair each prediction with the actual value for the same sample. Compute the difference and square for each pair, then sum and average across samples. Making this compressed procedure explicit in code helps reveal mismatched values or missing operations.
flowchart TD
A["Match symbols to inputs"]
B["Check sample order and shape"]
C["Subtract and square per sample"]
D["Sum and average"]
E["Inspect values and plot"]
A --> B --> C --> D --> E
Mean Squared Error¶
Mean squared error (MSE) averages the squared differences between predicted and actual values.
The symbols refer to the following quantities.
| Symbol | Meaning |
|---|---|
| \(n\) | Number of data points |
| \(y_i\) | Actual value for sample i |
| \(\hat{y}_i\) | Predicted value for sample i |
| \(y_i - \hat{y}_i\) | Error for sample i |
| \((y_i - \hat{y}_i)^2\) | Squared error |
| \(\sum\) | Sum across all samples |
| \(\frac{1}{n}\) | Divide the sum by the sample count |
Read the formula as “calculate each sample’s error, square it, add the squares, and divide by the count.”
Here each sample has one actual and one predicted value, and every sample has equal weight. \(n\) counts sample pairs, not features, and must be positive. The formula’s first sample, \(i=1\), corresponds to Python index 0. The name y_hat spells out the hat over the predicted value \(\hat y\).
Computing with a Loop¶
Pair actual values [3.0, 5.0, 7.0] with predictions [2.5, 5.5, 8.0] at matching positions. Errors are [0.5, -0.5, -1.0], and squared errors are [0.25, 0.25, 1.0]. Their sum, 1.5, divided by 3 gives MSE 0.5.
The code follows the parts of the formula directly.
| Part of the Formula | Part of the Code |
|---|---|
| \(y_i\), \(\hat{y}_i\) | y, y_hat |
| \(y_i - \hat{y}_i\) | error = y - y_hat |
| \((y_i - \hat{y}_i)^2\) | error ** 2 |
| \(\sum\) | sum(squared_errors) |
| \(\frac{1}{n}\) | / len(squared_errors) |
Both lists must be nonempty and have the same length and sample order. By default, zip stops at the shorter list, so a length mismatch can silently omit values.
The if check stops computation for unequal lengths or empty lists. Remove 8.0 from the prediction list to trigger ValueError. Without the check, only the first two pairs produce MSE 0.25, making missing data look like an improvement. This exercise assumes lists of finite real values.
Computing with NumPy Arrays¶
Subtracting, squaring, and averaging the same inputs with NumPy also gives 0.5.
Both arrays have shape (3,), so subtraction pairs values at matching positions. Vectorization expresses the same operation across an array.
ndim counts axes, shape gives each axis length, and size counts all elements. np.isfinite checks that each value is neither NaN nor infinity; .all() checks that every element passes. Whoever constructs the inputs must still verify sample correspondence, which these checks cannot determine.
Errors and Squared Errors¶
MSE becomes one number. Print the intermediate values in the same session after executing the NumPy block above.
The output is as follows.
Errors have direction: their sign changes with underprediction or overprediction. Squared errors are never negative, allowing MSE to summarize error size without sign cancellation.
MSE is specifically the mean of squared errors. If actual values are measured in score points, its unit is points². Taking the square root gives RMSE in the original unit: here, \(\sqrt{0.5}\approx0.707\). Doubling an error multiplies its square by four, increasing the influence of large errors.
np.mean(errors ** 2) also differs from np.mean(errors) ** 2. The first is 0.5; the second is approximately 0.111. The latter allows opposite signs to cancel before squaring, so it is not MSE.
Differences by Sample¶
Compare the vertical distance between actual and predicted values at each sample position. The first two gaps are 0.5; the last is 1.0. Use points and vertical segments without connecting samples to avoid suggesting continuous change between them. This code uses actual, predicted, and np from the NumPy block above.
The image shows the actual–predicted gaps for each sample.
The reference source runs the loop calculation, NumPy calculation, and plot saving together. It localizes the code’s English labels for the published figures while preserving point positions and calculated values.
MSE calculation and chart-generation code
Run from the repository root in a Python environment with NumPy and Matplotlib installed. Matching the published font requires Noto Sans CJK JP; select another font with --font-family if needed.
The script prints loop mse, errors, squared errors, and numpy mse, then saves three language-specific SVGs in the chosen folder. The default final prediction is 8.0. Add --last-prediction 7 or --last-prediction 9 to reproduce the numerical and visual changes below.
The graph does not calculate MSE for you. It reveals the differences before they are compressed into a single number.
Case 1. Changing Only the Final Prediction¶
Changing the final prediction from 8.0 to the actual value, 7.0, produces squared errors [0.25, 0.25, 0.0]. MSE falls to 0.5 / 3, approximately 0.167, and the final two points overlap.
Changing that prediction to 9.0 instead makes its error −2 and its squared error 4. MSE becomes (0.25 + 0.25 + 4) / 3 = 1.5. Doubling this sample’s error magnitude from 1 to 2 quadruples its squared error from 1 to 4.
Changing the inputs in both the loop and NumPy versions should yield the same result. If not, check order, length, shape, and the averaging axis. In particular, changing a (3,) array to (3, 1) can broadcast subtraction across all combinations instead of computing the original paired-sample MSE.
Code That Runs but Calculates Something Else¶
Without the input checks, actual.reshape(3, 1) - predicted produces shape (3, 3). Each actual value is compared with all three predictions, creating nine differences. Its first row is [0.5, -2.5, -5.0], mixing in predictions for other samples.
| Calculation | Values Being Averaged | Result |
|---|---|---|
| Three matching pairs | 3 squared errors | 0.5 |
Subtracting (3,) from (3, 1) | 9 squared errors from all combinations | About 7.833 |
| Reversing only prediction order | 3 incorrectly paired squared errors | About 15.167 |
Shape checks prevent the second error but not the third, whose shapes still match. Check sample identifiers such as student IDs as well. Without an axis argument, np.mean averages every element, compressing even an incorrectly expanded array into one number.
Predict whether adding 10 to both actual and predicted values changes MSE, then run it. Differences remain unchanged, so MSE stays at 0.5. Multiplying both arrays by 10 multiplies differences by 10 and squared errors by 100, producing MSE 50. Interpreting magnitudes requires matching units, samples, and calculation rules.
Checklist¶
- Can you separate symbols, data shape, and calculation steps before writing code?
- Can you explain \(y_i\), \(\hat{y}_i\), \(n\), and \(\sum\) in the MSE formula?
- Can you translate summation into a loop or array calculation?
- Can you write the same calculation with a Python loop and NumPy arrays?
- Can you explain why actual and predicted values need matching order, length, and shape?
- Can you distinguish
errors,squared_errors, andmse? - Can you explain why intermediate values help verify a calculation?
- Can you explain how a plot supports interpretation without replacing calculation?
- Can you distinguish the mean of squares from the square of the mean, and the units of MSE from RMSE?
- Can you explain why incorrect sample order changes results even when shapes match?
Sources and References¶
- Python Software Foundation, Built-in Functions: zip Checked on: 2026-09-15. Pairing and the default stop at the shorter input.
- NumPy Developers, numpy.mean Checked on: 2026-09-15. Averaging all elements when no axis is specified.
- NumPy Developers, Broadcasting Checked on: 2026-09-15. Operations between arrays with different shapes.
- scikit-learn developers, Regression metrics Checked on: 2026-09-15. Definitions and interpretation of MSE, RMSE, and MAE.
- Matplotlib Developers, Axes.scatter Checked on: 2026-09-15. Displaying actual and predicted values by sample.