Linear Regression: Building a House-Price Prediction Engine
Statistics
Regression
Machine Learning
An end-to-end regression case study: price modeling, least squares, multivariable regression, validation, interpretation, model persistence and an interactive pricing desk.
Author
MLStation
Published
October 3, 2026
Real-estate pricing lab
🏠 A homeowner wants to list a house tomorrow. What price should the platform recommend?
Imagine a home-listing company building an internal pricing engine. A new property arrives with 2,150 sq ft, 3 bedrooms, 2.5 bathrooms, age 8 years, and a strong neighborhood score.
The analyst’s task is not to classify the house. It is to estimate a continuous quantity:
What sale price should we expect, given the characteristics of this home?
This is a regression problem.
The goal of this chapter is to build the solution the way a data scientist would actually build it:
BUSINESS QUESTION → DATA → BASELINE → SIMPLE MODEL → MULTIVARIABLE MODEL → VALIDATION → INTERPRETATION → SAVE → PREDICT
TipBy the end, you should be able to
identify a continuous-target regression problem;
explain a fitted line using slope, intercept and residuals;
derive the least-squares objective and understand optimization;
move from one predictor to multiple predictors;
separate training from validation/test data;
interpret R^2, adjusted R^2, MSE, RMSE and MAPE;
inspect residuals and diagnose obvious model problems;
interpret coefficients conditionally;
save and reload a trained model;
turn a fitted regression model into a simple prediction product.
1. Frame the Business Problem Before the Equation
Suppose the platform has historical sales.
For each house, we observe:
living area;
bedrooms;
bathrooms;
age;
neighborhood quality;
distance to downtown;
actual sale price.
Our target is
Y=\text{sale price}.
Our predictors are
X=(x_1,x_2,\ldots,x_p).
Unlike fraud classification, Y is not a class such as 0/1. It is a continuous number such as
If MAPE is 8%, a rough interpretation is that predictions differ from actual values by about 8% on average in absolute percentage terms.
MAPE can behave poorly when actual values are zero or very close to zero. House prices are positive and far from zero, so it is more interpretable here.
import plotly.graph_objects as gofig = go.Figure()fig.add_trace(go.Indicator( mode="number", value=r2, number={"valueformat":".3f"}, title={"text":"Holdout R²"}, domain={"row":0,"column":0}))fig.add_trace(go.Indicator( mode="number", value=adjusted_r2, number={"valueformat":".3f"}, title={"text":"Adjusted R²"}, domain={"row":0,"column":1}))fig.add_trace(go.Indicator( mode="number", value=rmse, number={"prefix":"$","valueformat":",.0f"}, title={"text":"RMSE"}, domain={"row":1,"column":0}))fig.add_trace(go.Indicator( mode="number", value=mape, number={"suffix":"%","valueformat":".1f"}, title={"text":"MAPE"}, domain={"row":1,"column":1}))fig.update_layout( grid={"rows":2,"columns":2,"pattern":"independent"}, title="Validation Dashboard — Homes the Model Did Not Train On", height=500)fig.show()
A data scientist should report metrics in language the decision maker can understand.
For example:
“On unseen homes, typical prediction error is on the order of the reported RMSE, while MAPE expresses the error relative to house price. R^2 summarizes how much of the variation is captured relative to a mean-price baseline.”
14. Actual vs Predicted: Does the Model Track the Market?
Metrics compress performance into numbers. A plot can reveal structure the summary misses.
Data Simulator
View Validation Data
import pandas as pdprediction_check = pd.DataFrame({"actual_price":y_test.to_numpy(),"predicted_price":test_prediction})prediction_check["residual"] = ( prediction_check["actual_price"]- prediction_check["predicted_price"])
Plot Code
View Plot Code
import plotly.express as pxfig = px.scatter( prediction_check, x="actual_price", y="predicted_price", hover_data={"residual":":$,.0f"}, title="Holdout Homes: Actual Price vs Predicted Price")low = prediction_check[ ["actual_price","predicted_price"]].min().min()high = prediction_check[ ["actual_price","predicted_price"]].max().max()fig.add_shape(type="line", x0=low,y0=low,x1=high,y1=high, line={"dash":"dash"})fig.update_layout( xaxis_title="Actual sale price ($)", yaxis_title="Predicted sale price ($)", height=480)fig.show()
Points close to the diagonal are well predicted.
Systematic curvature, widening error, or clusters would suggest the model is missing structure.
15. Residuals Are a Model-Debugging Tool
Residual:
e_i=y_i-\hat y_i.
A useful residual plot should look roughly like an unstructured cloud around zero.
Data Simulator
View Residual Data
residual_data = prediction_check.copy()
Plot Code
View Plot Code
import plotly.express as pxfig = px.scatter( residual_data, x="predicted_price", y="residual", title="Residual Diagnostic: What Is the Model Still Missing?")fig.add_hline(y=0,line_dash="dash")fig.update_layout( xaxis_title="Predicted price ($)", yaxis_title="Residual = actual − predicted ($)", height=450)fig.show()
Look for:
curved pattern → missing nonlinearity
funnel shape → changing error variance
separate clusters → missing segments / interactions
extreme residuals → unusual homes or data problems
Residual analysis turns “the metric looks okay” into actual model diagnosis.
16. Cross-Validation: Do Not Depend on One Lucky Split
A single train/test split can be unusually easy or difficult.
If performance varies wildly across folds, investigate before deployment.
17. Interpret the Multivariable Model
The fitted model is
\hat y
=
\hat\beta_0
+\hat\beta_1x_1+\cdots+\hat\beta_px_p.
For multiple regression, a coefficient is interpreted holding the other included predictors constant.
For example, if the fitted sqft coefficient were 185:
Holding bedrooms, bathrooms, age, neighborhood score and distance constant, one additional square foot is associated with about $185 higher predicted sale price.