Regression analysis and residual plots. Fit a line, then look at what's left over — the residuals. Their pattern tells you whether the model is right. Switch the data shape and watch the residual plot give the verdict.
For every point, the model predicts a value on the line. The vertical gap between the real point and the line is the residual.
Least squares finds the line that makes the sum of squared residuals as small as possible.
The scatter plot shows how good the fit is. The residual plot shows what's wrong with it. A healthy residual plot is a shapeless cloud centred on zero. Any structure is the data telling you the model is missing something.
Pick a data shape. The left plot fits the regression line (sky blue) and draws each residual (orange). The right plot is the residual plot. Tap the left plot to add your own point and watch both update. Read the diagnosis at the bottom.
Three shapes to recognise. Only the first one means "all good".
Two clear explainers from StatQuest with Josh Starmer covering least-squares fitting, residuals and R² — the foundations of this experiment.
Videos are embedded from YouTube and belong to their creators. If a frame is blank, your network may block YouTube — search the titles on youtube.com.
Fit the model, then produce the residual plot and the metrics. Swap in any CSV with one predictor and one target.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score, mean_squared_error
df = pd.read_csv("data.csv") # columns: x, y
X = df[["x"]].values
y = df["y"].values
model = LinearRegression().fit(X, y)
y_pred = model.predict(X)
residuals = y - y_pred
print("slope:", model.coef_[0], "intercept:", model.intercept_)
print("R2 :", r2_score(y, y_pred))
print("RMSE:", np.sqrt(mean_squared_error(y, y_pred)))
# Residual plot: residual vs fitted value
plt.figure(figsize=(6,4))
plt.scatter(y_pred, residuals, color="#f0743f", edgecolor="k", alpha=0.7)
plt.axhline(0, color="#2b7fb5", linestyle="--") # the zero line
plt.xlabel("Fitted value (ŷ)"); plt.ylabel("Residual")
plt.title("Residual Plot"); plt.tight_layout(); plt.show()
# Quick one-liner with seaborn:
# import seaborn as sns; sns.residplot(x=y_pred, y=y)
import statsmodels.api as sm
Xc = sm.add_constant(X) # add intercept term
ols = sm.OLS(y, Xc).fit()
print(ols.summary()) # R2, coefficients, p-values
# residuals vs fitted, with a Q-Q plot for normality
sm.qqplot(ols.resid, line="s"); plt.show()
A regression model was fitted to the dataset and its residual plot was produced. The model quality was reported using R² and RMSE, and the residual plot was used to check the regression assumptions, demonstrating CO3.