Compute R² = 1 − SS_res/SS_tot where SS_res = Σ(yᵢ−ŷᵢ)² (residual sum of squares) and SS_tot = Σ(yᵢ−ȳ)² (total sum of squares). One loop for the mean, one loop accumulating both SS_res and SS_tot together. Library: scipy.stats.linregress(x, y).rvalue**2 (R² = r² in simple linear regression). RESULT: R² (rounded).

By hand

slope=0.8, intercept=1.6, x=[1,2,3,4,5], y=[2,4,4,4,6], mean_y=4.0. SS_res=1.6 (SSE from residuals-and-sse). SS_tot=(2−4)²+0+0+0+(6−4)²=8. R²=1−1.6/8=0.8.

naive.py
Replay: real traced execution (multi-file project)
slope = 0.8
intercept = 1.6
x = [1, 2, 3, 4, 5]
y = [2, 4, 4, 4, 6]
n = len(x)
total_y = 0.0
for v in y:
    total_y = total_y + v
mean_y = total_y / n
ss_res = 0.0
ss_tot = 0.0
for i in range(n):
    resid = y[i] - (slope * x[i] + intercept)
    ss_res = ss_res + resid * resid
    ss_tot = ss_tot + (y[i] - mean_y) ** 2
r2 = 1 - ss_res / ss_tot
print('RESULT:', round(r2, 4))
  1. slope ← 0.8

    1slope = 0.82intercept = 1.6
    values this step0.8slope
  2. intercept ← 1.6

    1slope = 0.82intercept = 1.63x = [1, 2, 3, 4, 5]
    values this step1.6intercept
  3. x ← [1, 2, 3, 4, 5]

    2intercept = 1.63x = [1, 2, 3, 4, 5]4y = [2, 4, 4, 4, 6]
    values this step[1, 2, 3, 4, 5]x
  4. y ← [2, 4, 4, 4, 6]

    3x = [1, 2, 3, 4, 5]4y = [2, 4, 4, 4, 6]5n = len(x)
    values this step[2, 4, 4, 4, 6]y
  5. n ← 5

    4y = [2, 4, 4, 4, 6]5n = len(x)6total_y = 0.0
    values this step5n
  6. total_y ← 0.0

    5n = len(x)6total_y = 0.07for v in y:
    values this step0.0total_y
  7. v ← 2, total_y ← 2.0

    pass 1 of 5
    6total_y = 0.07for v in y:8    total_y = total_y + v9mean_y = total_y / n
    values this step2v0.0 2.0total_y
    All 5 passes — pass 1 is the card above
    passvtotal_y
    120.0 2.0
    22 42.0 6.0
    36.0 10.0
    410.0 14.0
    54 614.0 20.0
  8. for v in y:

    6total_y = 0.07for v in y:8    total_y = total_y + v
  9. mean_y ← 4.0

    8    total_y = total_y + v9mean_y = total_y / n10ss_res = 0.0
    values this step4.0mean_y
  10. ss_res ← 0.0

    9mean_y = total_y / n10ss_res = 0.011ss_tot = 0.0
    values this step0.0ss_res
  11. ss_tot ← 0.0

    10ss_res = 0.011ss_tot = 0.012for i in range(n):
    values this step0.0ss_tot
  12. i ← 0, resid ← -0.40000000000000036, ss_res ← 0.16000000000000028

    pass 1 of 5
    11ss_tot = 0.012for i in range(n):13    resid = y[i] - (slope * x[i] + intercept)14    ss_res = ss_res + resid * resid15    ss_tot = ss_tot + (y[i] - mean_y) ** 216r2 = 1 - ss_res / ss_tot
    values this step0i-0.40000000000000036resid0.0 0.16000000000000028ss_res0.0 4.0ss_tot
    All 5 passes — pass 1 is the card above
    passiresidss_resss_tot
    10-0.400000000000000360.0 0.160000000000000280.0 4.0
    20 1-0.40000000000000036 0.79999999999999980.16000000000000028 0.7999999999999999
    31 20.7999999999999998 0.0
    42 30.0 -0.80000000000000070.7999999999999999 1.440000000000001
    53 4-0.8000000000000007 0.400000000000000361.440000000000001 1.60000000000000144.0 8.0
  13. for i in range(n):

    11ss_tot = 0.012for i in range(n):13    resid = y[i] - (slope * x[i] + intercept)
  14. r2 ← 0.7999999999999998

    15    ss_tot = ss_tot + (y[i] - mean_y) ** 216r2 = 1 - ss_res / ss_tot17print('RESULT:', round(r2, 4))
    values this step0.7999999999999998r2
  15. stdout ← RESULT: 0.8

    16r2 = 1 - ss_res / ss_tot17print('RESULT:', round(r2, 4))
    values this stepRESULT: 0.8stdout

With the library

scipy.stats.linregress(x, y).rvalue**2 gives R² directly (r=2/√5, r²=4/5=0.8). The snapshot also shows r for comparison with ch04.

library.py
from scipy import stats
from dalib.display import set_display
set_display()

x = [1, 2, 3, 4, 5]
y = [2, 4, 4, 4, 6]
fit = stats.linregress(x, y)
r2 = float(fit.rvalue ** 2)
print('r:', round(float(fit.rvalue), 4))
print('r_squared:', round(r2, 4))
print('RESULT:', round(r2, 4))
r: 0.8944
r_squared: 0.8
RESULT: 0.8

Honesty

This lesson shows the computation of R² exactly, on a tiny pinned sample. The value is arithmetically correct and reproducible, but it measures only how well the line fits these specific in-sample points — on so few points a high R² overstates fit and says nothing about out-of-sample or population performance. Treat it as "how the formula is computed," not as evidence the model generalizes; real evaluation needs held-out data and an adequate sample size.

Implementation notes

  • R²=r² holds only for simple (one-predictor) linear regression; in multiple regression R² ≠ Pearson r².
  • R²=0.8 means the line explains 80% of the variance in y.
  • SS_tot = SS_res + SS_reg (regression sum of squares); R² = SS_reg/SS_tot.
  • Cross-reference: residuals-and-sse (this chapter) for SS_res; pearson-correlation (ch04) for r whose square gives R² here.