Lesson 12 · Statistics for data analysts
Multiple Regression & Model Diagnostics | Statistics #12
Video twelve of the 15-part series: multiple real predictors at once, and the diagnostics that catch when they're fighting each other. Real mtcars data,…
- CourseStatistics for data analysts
- Lesson12 of 15
- Video13 min
- FormatJupyter notebook · 10 code cells
- Data1 dataset
What you'll learn
Datasets used in this lesson
Save these next to the notebook. In Google Colab, upload them with the 📁 icon on the left first.
- mtcars.csv1.7 KB
📓 Full notebook
Download .ipynbStatistics for Data Analysts, Video 12: Multiple Regression and Diagnostics#
- Video twelve of the 15-part series: multiple real predictors at once, and the diagnostics that catch when they're fighting each other.
- Real mtcars data, extended with statsmodels for a full regression summary and multicollinearity checks.
- Let's get into it.
Before You Start#
- Open a new Jupyter Notebook in VS Code and select your Python interpreter as the kernel.
- Install statsmodels if you don't have it yet:
pip install statsmodels. - Place mtcars.csv in the same folder as this notebook.
import pandas as pd
import numpy as np
import statsmodels.api as sm
import statsmodels.formula.api as smf
from statsmodels.stats.outliers_influence import variance_inflation_factor
from statsmodels.stats.diagnostic import het_breuschpagan
mtcars = pd.read_csv('mtcars.csv')
print(mtcars[['model', 'mpg', 'wt', 'hp', 'disp']].head())
Part 1: A Three-Predictor Model#
model_full = smf.ols('mpg ~ wt + hp + disp', data=mtcars).fit()
print(model_full.summary())
Real R-squared jumps to about 0.827, up from 0.753 with weight alone, so the fuller model explains more real variance. But look closer: the real coefficient on disp has a p-value of about 0.93, nowhere near significant, even though disp is plausibly related to mpg on its own. That's the first hint something is off, and the summary's own footnote agrees: 'condition number is large... this might indicate strong multicollinearity.'
Part 2: Diagnosing Multicollinearity with VIF#
X = mtcars[['wt', 'hp', 'disp']]
X_const = sm.add_constant(X)
vif_data = pd.DataFrame()
vif_data['feature'] = X_const.columns
vif_data['VIF'] = [variance_inflation_factor(X_const.values, i) for i in range(X_const.shape[1])]
print(vif_data)
print(X.corr().round(3))
Part 3: Fixing It - Dropping the Redundant Predictor#
model_reduced = smf.ols('mpg ~ wt + hp', data=mtcars).fit()
print(model_reduced.summary())
print(f'Full model: R2={model_full.rsquared:.4f}, Adj R2={model_full.rsquared_adj:.4f}, AIC={model_full.aic:.2f}, BIC={model_full.bic:.2f}')
print(f'Reduced model: R2={model_reduced.rsquared:.4f}, Adj R2={model_reduced.rsquared_adj:.4f}, AIC={model_reduced.aic:.2f}, BIC={model_reduced.bic:.2f}')
X2 = mtcars[['wt', 'hp']]
X2_const = sm.add_constant(X2)
vif2 = pd.DataFrame()
vif2['feature'] = X2_const.columns
vif2['VIF'] = [variance_inflation_factor(X2_const.values, i) for i in range(X2_const.shape[1])]
print(vif2)
Part 4: Checking Residual Assumptions#
bp_stat, bp_pvalue, bp_fstat, bp_fpvalue = het_breuschpagan(model_reduced.resid, model_reduced.model.exog)
print(f'Real Breusch-Pagan statistic: {bp_stat:.4f}')
print(f'Real Breusch-Pagan p-value: {bp_pvalue:.4f}')
import matplotlib.pyplot as plt
plt.figure(figsize=(8, 4))
plt.scatter(model_reduced.fittedvalues, model_reduced.resid, color='steelblue')
plt.axhline(0, color='darkred', linestyle='--')
plt.title('Real Residuals vs. Fitted Values (Reduced Model)')
plt.xlabel('Fitted mpg')
plt.ylabel('Residual')
plt.show()
Part 5: Interpreting the Final Model#
wt_coef = model_reduced.params['wt']
hp_coef = model_reduced.params['hp']
print(f'Holding horsepower constant, each additional 1,000 lbs of real weight predicts {abs(wt_coef):.2f} fewer real mpg')
print(f'Holding weight constant, each additional real horsepower predicts {abs(hp_coef):.4f} fewer real mpg')
print(f'Real 100-horsepower difference, weight held constant: {abs(hp_coef) * 100:.2f} fewer real mpg')
Wrap-Up: What You Learned#
- Fitting a multiple regression with statsmodels and reading the full real summary table.
- Diagnosing multicollinearity with VIF and a real correlation matrix, catching a predictor whose coefficient looked meaningless because it was redundant, not because it was irrelevant.
- Comparing real models with adjusted R-squared, AIC, and BIC, which properly reward simplicity, not just raw fit.
- The Breusch-Pagan test for constant residual variance, alongside the residual plot.
- Interpreting multiple regression coefficients correctly, each one holding the others constant.
- Video thirteen turns to categorical data specifically: a deeper chi-square treatment, odds ratios, and a first look at logistic regression. Subscribe so it lands automatically see you there.
Found this useful?
All lessons, notebooks and datasets here are free. If they helped you, a coffee keeps new lessons coming.



