Polynomial Regression › Implementation in Scikit-learn

Michael BrenndoerferJune 9, 20258 min read
Machine Learning from ScratchAll chapters
Part 4 of 9Regression Models
Chapter 32Polynomial Regression › Implementation in Scikit-learn
Reading section 5 of 8 · Implementation in Scikit-learn · 8 minSection 5 of 8 · 8 min

Book contents

Section 5 of 8 · 8 min read

Polynomial Regression › Implementation in Scikit-learnOne section · Sections in this chapter5 / 8 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Scikit-learn provides excellent tools for implementing polynomial regression through the PolynomialFeatures transformer and LinearRegression estimator. Let's walk through a complete implementation that demonstrates how to fit and evaluate polynomial regression models.

Setting Up the Data

We'll start by generating synthetic data with a known cubic relationship, which will allow us to see how well polynomial regression can recover the true underlying function.

In[6]:
Code
import numpy as np
from sklearn.model_selection import train_test_split

# Generate synthetic data with cubic relationship
np.random.seed(42)
n_samples = 100
x = np.linspace(-2, 2, n_samples)
y_true = 2 * x**3 - 3 * x**2 + x + 1
noise = np.random.normal(0, 0.5, n_samples)
y = y_true + noise

# Split into training and test sets
X_train, X_test, y_train, y_test = train_test_split(
    x.reshape(-1, 1), y, test_size=0.3, random_state=42
)

The data follows a cubic polynomial with added Gaussian noise. By splitting into training (70%) and test (30%) sets, we can evaluate how well the model generalizes to unseen data.

Building a Polynomial Regression Pipeline

The most efficient way to implement polynomial regression in scikit-learn is using a Pipeline that combines the PolynomialFeatures transformer with LinearRegression. This ensures that the same polynomial transformation is consistently applied to both training and test data.

In[7]:
Code
from sklearn.metrics import mean_squared_error

# Create pipeline with degree-3 polynomial features
poly_reg = Pipeline(
    [
        ("poly", PolynomialFeatures(degree=3, include_bias=True)),
        ("linear", LinearRegression()),
    ]
)

# Train the model
poly_reg.fit(X_train, y_train)

# Make predictions
y_pred = poly_reg.predict(X_test)

# Calculate performance metrics
mse = mean_squared_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
Out[8]:
Console
Model Performance:
Mean Squared Error: 0.1395
R² Score: 0.9980

The low MSE and high R² score (close to 1.0) indicate excellent model performance. Since our data was generated from a cubic function and we used a degree-3 polynomial, the model successfully captures the true underlying relationship. The R² score tells us that the model explains nearly all the variance in the test data.

Out[9]:
Console

Model Coefficients:
Intercept: 0.8867
Coefficients: [ 0.          1.2487505  -2.96269465  1.90648781]

The coefficients show the contribution of each polynomial term. Comparing these to our true function (2x3−3x2+x+12x^3 - 3x^2 + x + 1), we can see the model has successfully recovered values close to the true parameters, despite the added noise.

Comparing Different Polynomial Degrees

A critical question in polynomial regression is choosing the right degree. Let's compare models with different degrees to understand the bias-variance trade-off.

In[10]:
Code
# Compare polynomial degrees from 1 to 5
degrees = [1, 2, 3, 4, 5]
results = []

for degree in degrees:
    # Create and fit model
    model = Pipeline(
        [
            ("poly", PolynomialFeatures(degree=degree, include_bias=True)),
            ("linear", LinearRegression()),
        ]
    )

    model.fit(X_train, y_train)
    y_pred_deg = model.predict(X_test)

    # Calculate metrics
    mse_deg = mean_squared_error(y_test, y_pred_deg)
    r2_deg = r2_score(y_test, y_pred_deg)
    n_features = model.named_steps["poly"].n_output_features_

    results.append(
        {
            "degree": degree,
            "mse": mse_deg,
            "r2": r2_deg,
            "n_features": n_features,
        }
    )
Out[11]:
Console
Comparison of Polynomial Degrees:

Degree   MSE          R²           Features  
---------------------------------------------
1        21.7172      0.6895       2         
2        6.3839       0.9087       3         
3        0.1395       0.9980       4         
4        0.1366       0.9980       5         
5        0.1388       0.9980       6         

Best degree: 4 (MSE = 0.1366)

The comparison reveals important insights about model selection:

  • Degree 1 (Linear): High MSE and low R² indicate underfitting. A straight line cannot capture the cubic relationship.
  • Degree 2 (Quadratic): Improved performance but still underfits the true cubic function.
  • Degree 3 (Cubic): Optimal performance with the lowest MSE. This matches the true data-generating process.
  • Degrees 4-5: Similar or slightly worse performance than degree 3, suggesting potential overfitting to noise in the training data.

The degree-3 model achieves the best balance between bias and variance, as expected since the true relationship is cubic. Higher degrees don't improve performance and risk overfitting, especially with limited training data.

Visualizing Model Predictions

Let's visualize how different polynomial degrees fit the data to better understand their behavior.

Out[12]:
Visualization
Degree 1 polynomial predictions with training data, test data, and test R-squared.
Degree 1 model predictions on the training and test data show underfitting from a high-bias linear model.
Degree 2 polynomial predictions with training data, test data, and test R-squared.
Degree 2 model predictions improve the fit but still underfit the true cubic relationship.
Out[13]:
Visualization
Degree 3 polynomial predictions with training data, test data, and test R-squared.
Degree 3 model predictions capture the underlying cubic trend and achieve the strongest test fit.
Degree 5 polynomial predictions with training data, test data, and test R-squared.
Degree 5 model predictions add flexibility and begin to show the variance associated with overfitting.

The visualizations clearly show the progression from underfitting (degree 1) to optimal fit (degree 3) to potential overfitting (degree 5). The degree-3 model smoothly captures the underlying cubic trend, while the degree-5 model shows slight oscillations that fit noise rather than the true pattern.

Key Parameters

Below are the main parameters that control polynomial regression behavior and performance.

PolynomialFeatures Parameters:

  • degree: The maximum degree of polynomial features to generate (default: 2). This is the most critical parameter. Start with low values (2-3) and increase only if needed. Higher degrees capture more complex patterns but risk overfitting.
  • include_bias: Whether to include the intercept column of ones (default: True). Typically set to True when using with LinearRegression, which expects the bias term in the feature matrix.
  • interaction_only: If True, only interaction features are produced, not powers (default: False). Use this when you want to model interactions between variables without including squared or higher-power terms.

LinearRegression Parameters:

  • fit_intercept: Whether to calculate the intercept (default: True). When using PolynomialFeatures with include_bias=True, this is typically set to False to avoid redundancy, though scikit-learn handles this automatically.
  • copy_X: Whether to copy the input data (default: True). Set to False to save memory if you don't need the original data preserved.

Pipeline Benefits:

  • Automatically applies the same polynomial transformation to training and test data
  • Simplifies cross-validation and hyperparameter tuning
  • Ensures reproducible preprocessing steps
  • Makes code more maintainable and less error-prone

Key Methods

The following methods are used to train and apply polynomial regression models.

  • fit(X, y): Trains the polynomial regression model on input features X and target values y. This applies the polynomial transformation and fits the linear regression coefficients.
  • predict(X): Returns predicted values for input data X. The polynomial transformation is automatically applied before making predictions.
  • score(X, y): Returns the R² score (coefficient of determination) on the given test data. Values closer to 1.0 indicate better fit.
  • get_params(): Returns the parameters of the pipeline components. Useful for inspecting or modifying the model configuration.
  • set_params(**params): Sets the parameters of the pipeline. Commonly used with grid search for hyperparameter tuning.