Some data curves — and a straight line through a curve is like wearing the wrong prescription glasses.
Save
EXERCISE
1Some data curves — speed drops in the morning, bottoms out at noon, then rises again in the evening. No straight line can capture that.
Save
EXERCISE
2NumPy gives you two functions that work as a team: polyfit finds the curve, and poly1d turns it into a callable prediction function.
Save
EXERCISE
3Polynomial regression has the same trap as linear — if there is no pattern, fitting a curve just makes your mistakes fancier.
Save
Complete lesson & earn 250 PX
Fitting a straight line through curved data is like wearing the wrong prescription glasses. Everything is blurry because the tool does not match the shape. Polynomial fits a curve instead of a line.
The problem — data that curves:
import matplotlib.pyplot as plt
x = [1,2,3,5,6,7,8,9,10,12,13,14,15,16,18,19,21,22]
y = [100,90,80,60,60,55,60,65,70,70,75,76,78,79,90,99,99,100]
plt.scatter(x, y)
plt.title("This data clearly curves — a line won't fit")
plt.show()
# Output: A U-shaped scatter pattern
The solution — polynomial regression:
import numpy
import matplotlib.pyplot as plt
x = [1,2,3,5,6,7,8,9,10,12,13,14,15,16,18,19,21,22]
y = [100,90,80,60,60,55,60,65,70,70,75,76,78,79,90,99,99,100]
mymodel = numpy.poly1d(numpy.polyfit(x, y, 3))
myline = numpy.linspace(1, 22, 100)
plt.scatter(x, y)
plt.plot(myline, mymodel(myline), color="red")
plt.title("Polynomial fit (degree 3)")
plt.show()
# Output: A smooth curve passing through the U-shaped data
The key difference:
| Type | Equation | Shape |
|---|---|---|
| Linear | y = mx + b | Straight line |
| Polynomial (degree 2) | y = ax² + bx + c | Parabola (U or ∩) |
| Polynomial (degree 3) | y = ax³ + bx² + cx + d | S-curve or wavy |
> 💡 Key Insight: The "degree" of the polynomial controls how many curves the line can make. Degree 1 = straight line. Degree 2 = one curve. Degree 3 = two curves. Higher degrees fit more complex shapes, but beware: too high a degree overfits your noise instead of your signal.
Think of polyfit as a tailor measuring your data, and poly1d as the finished suit built from those measurements. One measures, the other wears.
How they work together:
import numpy
x = [1,2,3,5,6,7,8,9,10,12,13,14,15,16,18,19,21,22]
y = [100,90,80,60,60,55,60,65,70,70,75,76,78,79,90,99,99,100]
# polyfit: finds the coefficients of the polynomial
coeffs = numpy.polyfit(x, y, 3)
print(f"Coefficients: {[round(c, 4) for c in coeffs]}")
# Output: Coefficients: [0.0427, -1.5267, 16.3287, 47.272]
# poly1d: turns coefficients into a callable function
mymodel = numpy.poly1d(coeffs)
print(mymodel)
# Output: 0.04269 x³ - 1.527 x² + 16.33 x + 47.27
Using the model to predict:
import numpy
x = [1,2,3,5,6,7,8,9,10,12,13,14,15,16,18,19,21,22]
y = [100,90,80,60,60,55,60,65,70,70,75,76,78,79,90,99,99,100]
mymodel = numpy.poly1d(numpy.polyfit(x, y, 3))
# Predict speed at hour 17
print(f"Hour 17: {round(mymodel(17), 2)} km/h")
# Output: Hour 17: 88.87 km/h
# Check R-squared
from sklearn.metrics import r2_score
print(f"R²: {round(r2_score(y, mymodel(x)), 4)}")
# Output: R²: 0.9433
# 94% of variation explained — excellent fit!
> 💡 Key Insight: The number 3 in polyfit(x, y, 3) is the polynomial degree — the single most important choice you make. Too low and the curve cannot match the data shape. Too high and it overfits (memorises noise). Try degrees 2, 3, and 4, compare R² values, and pick the simplest one that fits well.
A beautifully curved line through random noise is art, not science. Always check R² before trusting a polynomial model.
Good fit — clear pattern:
import numpy
from sklearn.metrics import r2_score
x = [1,2,3,5,6,7,8,9,10,12,13,14,15,16,18,19,21,22]
y = [100,90,80,60,60,55,60,65,70,70,75,76,78,79,90,99,99,100]
mymodel = numpy.poly1d(numpy.polyfit(x, y, 3))
print(f"R²: {round(r2_score(y, mymodel(x)), 4)}")
# Output: R²: 0.9433
# 94% explained → excellent, use this model ✅
Bad fit — random data:
import numpy
from sklearn.metrics import r2_score
x = [89,43,36,36,95,10,66,34,38,20,26,29,48,64,6,5,36,66,72,40]
y = [21,46,3,35,67,95,53,72,58,10,26,34,90,33,38,20,56,2,47,15]
mymodel = numpy.poly1d(numpy.polyfit(x, y, 3))
print(f"R²: {round(r2_score(y, mymodel(x)), 4)}")
# Output: R²: 0.0100
# 1% explained → useless, do NOT use this model ❌
R² reference table:
| R² Value | Quality | Verdict |
|---|---|---|
| > 0.90 | Excellent | Ship it |
| 0.70 – 0.90 | Good | Useful with caveats |
| 0.40 – 0.70 | Moderate | Investigate other approaches |
| < 0.40 | Poor | This model is not helpful |
> 💡 Key Insight: A high R² does not automatically mean a good model. If you increase the polynomial degree enough, R² will approach 1.0 — but the model will be memorising noise (). The test: does the model predict NEW data well, or only the data it trained on? That question leads directly to train/test splitting, which you will learn in Unit 7.
Polynomial regression fits a curved line through data using NumPy's polyfit(). R-squared tells you how well the curve fits.