Linear Regression
Normal Equation (1D)
Fit a line y=slope·x+intercept using the closed-form 1D normal equation:
slope = Σ(xᵢ−x̄)(yᵢ−ȳ) / Σ(xᵢ−x̄)², intercept = ȳ−slope·x̄. A single loop
accumulates numerator and denominator simultaneously. Library:
sklearn.linear_model.LinearRegression().fit(X, y) with X as a 2D column.
RESULT: (slope, intercept) rounded.
By hand
x=[1,2,3,4,5], y=[2,4,4,4,6]. x̄=3, ȳ=4. Numerator: (−2)(−2)+(−1)(0)+(0)(0)+(1)(0)+(2)(2)=8. Denominator: 4+1+0+1+4=10. slope=0.8, intercept=4−0.8·3=1.6.
x = [1, 2, 3, 4, 5]
y = [2, 4, 4, 4, 6]
n = len(x)
mx = sum(x) / n
my = sum(y) / n
num = 0.0
den = 0.0
for i in range(n):
dx = x[i] - mx
num = num + dx * (y[i] - my)
den = den + dx * dx
slope = num / den
intercept = my - slope * mx
print('RESULT:', (round(slope, 4), round(intercept, 4)))
x ← [1, 2, 3, 4, 5]
1x = [1, 2, 3, 4, 5]2y = [2, 4, 4, 4, 6]values this step[1, 2, 3, 4, 5]xy ← [2, 4, 4, 4, 6]
1x = [1, 2, 3, 4, 5]2y = [2, 4, 4, 4, 6]3n = len(x)values this step[2, 4, 4, 4, 6]yn ← 5
2y = [2, 4, 4, 4, 6]3n = len(x)4mx = sum(x) / nvalues this step5nmx ← 3.0
3n = len(x)4mx = sum(x) / n5my = sum(y) / nvalues this step3.0mxmy ← 4.0
4mx = sum(x) / n5my = sum(y) / n6num = 0.0values this step4.0mynum ← 0.0
5my = sum(y) / n6num = 0.07den = 0.0values this step0.0numden ← 0.0
6num = 0.07den = 0.08for i in range(n):values this step0.0deni ← 0, dx ← -2.0, num ← 4.0, den ← 4.0
pass 1 of 57den = 0.08for i in range(n):9 dx = x[i] - mx10 num = num + dx * (y[i] - my)11 den = den + dx * dx12slope = num / denvalues this step0i-2.0dx0.0 → 4.0num0.0 → 4.0denAll 5 passes — pass 1 is the card above pass idxnumden1 0 -2.0 0.0 → 4.0 0.0 → 4.0 2 0 → 1 -2.0 → -1.0 — 4.0 → 5.0 3 1 → 2 -1.0 → 0.0 — — 4 2 → 3 0.0 → 1.0 — 5.0 → 6.0 5 3 → 4 1.0 → 2.0 4.0 → 8.0 6.0 → 10.0 for i in range(n):
7den = 0.08for i in range(n):9 dx = x[i] - mxslope ← 0.8
11 den = den + dx * dx12slope = num / den13intercept = my - slope * mxvalues this step0.8slopeintercept ← 1.5999999999999996
12slope = num / den13intercept = my - slope * mx14print('RESULT:', (round(slope, 4), round(intercept, 4)))values this step1.5999999999999996interceptstdout ← RESULT: (0.8, 1.6)
13intercept = my - slope * mx14print('RESULT:', (round(slope, 4), round(intercept, 4)))values this stepRESULT: (0.8, 1.6)stdout
With scikit-learn
LinearRegression().fit(X, y) requires X as a 2D array — one column per
feature. coef_[0] is the slope; intercept_ is the intercept.
from sklearn.linear_model import LinearRegression
from dalib.display import set_display
set_display()
x = [1, 2, 3, 4, 5]
y = [2, 4, 4, 4, 6]
X = [[v] for v in x]
model = LinearRegression()
model.fit(X, y)
slope = round(float(model.coef_[0]), 4)
intercept = round(float(model.intercept_), 4)
print('coef_:', slope)
print('intercept_:', intercept)
print('RESULT:', (slope, intercept))
coef_: 0.8
intercept_: 1.6
RESULT: (0.8, 1.6)
Honesty
This lesson shows the closed-form fit computed exactly, on a tiny pinned sample. The slope and intercept are arithmetically correct and reproducible, but a fit to a handful of points is a mechanism demo, not a predictive model — it is not a statistical finding. Extrapolating the line beyond the observed x-range, or reading significance into the slope, is unwarranted at this sample size; real inference needs an adequate sample and assumption checks.
Implementation notes
- The closed-form normal equation finds the exact least-squares solution in one pass — no gradient descent or iteration needed.
- Cross-reference:
least-squares-line(python-stats ch08) derives the same formulas by hand; this lesson wraps them in the sklearn API. - LinearRegression expects X as a 2D array (rows=samples, columns=features); a flat 1D list raises a ValueError.
- RESULT tuple
(slope, intercept)matchescoef_[0]andintercept_exactly (both rounded to 4 d.p.). - Same data as python-stats ch08 intentionally: slope=0.8, intercept=1.6 confirms consistency across both books.