E ExamMaster

Machine Learning · Real-World ML Applications

Rent Pricing Application

Rent estimation is a classical regression job on structured housing features — predict a number, explain the error in rupees.

Not every ML job is a yes/no label — pricing tools predict a number. This lesson locks a rent target you can explain in currency units, a linear baseline you can read, and a small housing CSV fit in the browser.

  • Machine Learning
  • Medium level
  • 6 concepts
  • 10 practice questions

1Rent is a number you predict

The ml_core lessons kept returning to one notebook: 200 flats your office has already rented out, each line recording the flat's size in square feet, its distance from the city centre in kilometres, its building age in years — and, on the same line, the monthly rent the tenant actually signed at. This lesson is where that notebook stops being an example and becomes the product. The job: a landlord hands you a new flat, and you must put an advertised price on it. The answer you owe is not a category like spam / not spam — it is an amount of money, some number of rupees per month. A prediction job whose answer is a number on a continuous scale is called regression, and rent pricing is regression in its purest form.

Before touching a model, lock the three framing lines from the Learning Setup lesson. The decision this prediction changes: the advertised price on the new listing. The label: the rent the tenant finally signs at — not the asking price, which is a hope rather than an outcome, and not a rent band someone eyeballed. And the error story: when this tool is wrong it is wrong in rupees, so score it in rupees. Mean absolute error — MAE — is the average of the misses with their signs stripped: predict ₹18,900 for a flat that signs at ₹18,000 and the miss is ₹900; average such misses over many flats and the result reads as "this tool is typically about this many rupees off per month". That is a sentence a landlord can act on. "The R² was 0.62" is not.

One more framing line, easy to skip: say which flats the tool covers — one city, unfurnished, ordinary long leases, for instance — because a model scored on studio flats and a model scored on villas are being scored on different products, and their MAEs cannot be compared.

Figure. The whole pipeline in one line: the facts known the day a flat is listed go into the model, a rupee amount comes out, and that amount sets the advertised price. Every later choice — which error metric, which columns are legal — is judged against this decision, not against a notebook score.

Rent framing
Lock thisFor this tool
DecisionSet the advertised price of a new listing
LabelThe rent the tenant signs at, ₹/month
FeaturesFacts known on listing day: size, distance, age
Error storyMAE — average rupees off per month
Why do operators often prefer mean absolute error to mean squared error for a rent model?
  1. It always comes out smaller, so the model looks better
  2. It reads in rupees per month, the same units as the quantity being predicted
  3. It reacts more strongly to the expensive outliers that matter most
  4. Mean squared error cannot be computed for a regression target

An error an operator can act on is an error they can price. Squared error is in rupees squared, which is a perfectly good thing to optimise and a hard thing to explain in a meeting.

2The number to beat: always guess the median

So what counts as a good MAE — is ₹2,000 a month good? On its own the number is meaningless; it only means something against a benchmark, the score of the simplest guesser you would ever ship. For pricing, that guesser ignores the flat entirely and always predicts the middle rent of the flats it trained on. The middle value of a sorted list is called the median. Take the three notebook flats the Learning Setup lesson tabulated, with rents of ₹18k, ₹30k and ₹11k a month: sorted they read 11, 18, 30, the middle value is 18 — so the median guesser answers ₹18,000 for every flat it is ever shown, big or small, near or far.

Now score it, flat by flat. It gets the ₹18k flat exactly right — a miss of zero, because that flat happens to sit at the median. It calls the ₹30k flat ₹18k, missing by ₹12,000. It calls the ₹11k flat ₹18k, missing by ₹7,000. Strip the signs, average the three misses, and the benchmark's MAE comes out near ₹6,330 a month. That figure is the floor under everything that follows: any model you build gets to exist only if its MAE lands below it. A model that cannot beat always guessing the median is not a model — it is overhead with a fit method.

Figure. The median guesser's misses on the three notebook flats, in thousands of rupees per month: zero on the flat that sits at the median, 12 and 7 on the flats it ignores its way past. The dashed line is their average — an MAE near ₹6,330 — and it is the floor every real model must beat.

The benchmark's rupee error

The always-median guesser trains on the three notebook flats, whose signed rents are ₹18k, ₹30k and ₹11k a month. It therefore predicts the training median for every flat. What is its MAE on those three flats?

  • median of 18, 30, 11 (sorted: 11, 18, 30)18, so it always guesses ₹18k
  • |18 − 18|0
  • |30 − 18|12
  • |11 − 18|7
  • MAE = (0 + 12 + 7) / 3≈ 6.33, i.e. ₹6,330 / month

Pro tip. Compute this number before fitting anything, and report it beside every model score you ever quote — a model MAE means nothing without the no-model MAE next to it.

Why is evaluating a rent prediction model against a naive 'always predict the median' baseline necessary?
  1. It proves that the target distribution follows an exact Gaussian bell curve
  2. It guarantees that the learned linear regression coefficients sum to 1.0
  3. It establishes the performance floor that any trained machine learning model must convincingly outperform
  4. It replaces the need to split data into training and test partitions

A naive benchmark (always predicting median rent) gives the baseline error. A complex ML model is only valuable if it significantly outperforms this simple guess.

3A price list you can read

The Linear Regression lesson built the machine: ordinary least squares takes training rows and returns the weighted sum \hat{y} = w \cdot x + b whose squared misses are smallest. Point it at the 200 notebook flats and suppose it hands back this price list, with rent in thousands of rupees per month: \hat{y} = 9 + 0.018 \cdot \text{size} - 0.9 \cdot \text{distance} - 0.15 \cdot \text{age}. Read it line by line, because being readable is the whole reason to start linear. The 9 is the base: ₹9,000 of rent before the flat's facts say anything. The 0.018 is the size weight: each extra square foot adds 0.018 thousand — ₹18 — so a hundred extra square feet price about ₹1,800 higher. The −0.9 says every kilometre away from the centre costs ₹900 of monthly rent, and the −0.15 says each year of building age shaves off ₹150.

Every weight comes with the same fine print: it is the change in predicted rent when that one feature moves and the others stay put. And each weight is a claim you can argue with — if the distance slope came out positive you would suspect the data or a leaked column, not conclude that tenants pay extra to live far away. That arguability is exactly what a readable baseline buys. A random forest may well score a little better on the same rows, and you may climb to it later; but it buries the rupee story, so it should be made to beat this price list first, not replace it unexamined.

Figure. The price list pricing one new listing: 900 square feet contribute +16.2 thousand, 3 km of distance takes 2.7 back, 8 years of age takes another 1.2, and the base of 9 brings the prediction to about ₹21,300 a month. Every arrow is a rupee amount you can defend to a landlord.

The price list, line by line
TermWeight (₹k / month)Read as
Base9₹9,000 of rent before the flat's facts say anything
size (sqft)+0.018Each extra square foot adds ₹18 — a hundred extra square feet price about ₹1,800 higher
distance (km)−0.9Every kilometre from the centre costs ₹900 of monthly rent
age (years)−0.15Each year of building age shaves off ₹150

Price a new listing

A new flat is listed: 900 sqft, 3.0 km from the centre, 8 years old. Using the fitted price list \hat{y} = 9 + 0.018 \cdot \text{size} - 0.9 \cdot \text{distance} - 0.15 \cdot \text{age} (thousands of ₹/month), what rent does the model advertise?

  • size term: 0.018 × 90016.2
  • distance term: −0.9 × 3.0−2.7
  • age term: −0.15 × 8−1.2
  • ŷ = 9 + 16.2 − 2.7 − 1.221.3 → advertise ≈ ₹21,300 / month

Pro tip. Before trusting any fitted price list, read the signs against the story: bigger should price higher, farther and older should price lower. A slope with an unbelievable sign usually means a data problem, not a market discovery.

Your office swaps the linear price list for a small random forest and the hold-out MAE improves slightly. What did the swap cost?
  1. Nothing — a better score is strictly better
  2. The ability to compute MAE at all
  3. The train/test split, which forests do not support
  4. The per-feature rupee story that let you sanity-check and explain every price

A forest can be scored exactly like the line, but it no longer tells you that a kilometre costs ₹900. Whether a small MAE gain is worth losing the explanation is a product decision — which is why the readable baseline comes first.

4Check the misses, in rupees

A fitted price list is a claim, and residuals are how you audit it. For one flat the residual is y - \hat{y}: the actual signed rent minus the model's prediction — the miss, with its sign kept. Run the price list over the three notebook flats. The 850 sqft flat 4 km out: predicted 18.9 against an actual 18, residual −0.9 — the model guessed ₹900 too high. The 1,100 sqft flat near the centre: predicted 26.7 against 30, residual +3.3 — ₹3,300 too low. The old 600 sqft flat far out: predicted 8.7 against 11, residual +2.3 — ₹2,300 too low. Read the sign as a direction: positive means the model under-priced the flat, negative means it over-priced it.

Strip the signs and average: (0.9 + 3.3 + 2.3) / 3 lands near ₹2,170 of typical miss. Set that beside the median guesser's ₹6,330 and the price list has cut the typical miss to roughly a third of the no-model floor. That pair — model MAE against benchmark MAE — is the sentence to report; R² can ride along, but on its own it cannot say whether the errors are small enough to advertise prices with. One more look before shipping: plot the residuals against size. If they scatter randomly around zero, fine; if they bend — too low at both extremes and too high in the middle, or the reverse — the straight-line shape is wrong even while R² looks respectable, and the fix is a transformed feature, an interaction or a tree, not despair.

Figure. Typical miss per month, in thousands of rupees, on the three notebook flats: about 6.33 for the no-model median guesser against about 2.17 for the fitted price list. The comparison — not either number alone — is what says the model earned its keep.

Does the line beat the benchmark?

Plugging the three notebook flats into the fitted price list — the same plug-in worked for the 900 sqft listing — gives predictions of 18.9, 26.7 and 8.7 (thousands of ₹/month) against actual rents of 18, 30 and 11. Compute the model's MAE and set it against the median guesser's ₹6,330.

  • 850 sqft flat: 18 − 18.9−0.9
  • 1,100 sqft flat: 30 − 26.7+3.3
  • 600 sqft flat: 11 − 8.7+2.3
  • model MAE = (0.9 + 3.3 + 2.3) / 3≈ 2.17, i.e. ₹2,170 / month
  • against the benchmark MAE of 6.33about a third — the line earns its keep

Pro tip. Keep the residuals, not just their average: three numbers with signs tell you which flats the model over-prices and which it under-prices, and that pattern is where the next feature idea comes from.

The residuals of your linear rent model bend downward at both the smallest and the largest flats. What is that telling you?
  1. The model is overfitting the middle of the size range
  2. The true relationship curves, and a straight line cannot follow it at either extreme
  3. The test set is too small to estimate residuals from
  4. The target should be bucketed into bands and classified instead

Structure left in the residuals is structure the model failed to capture. A symmetric bend at both ends is the signature of curvature, and it argues for a transformed feature or a non-linear model.

5Score it the way it will be used

Everything so far scored three flats the model was allowed to study, which was fine for learning the arithmetic and is exactly what a real pipeline must not do. The Train / Test Split contract applies unchanged: cut before fitting, tune on validation, open the test fold once. When the office scales the notebook to 500 listings, that means something like 400 rows to fit and 100 held out — and the two scores are read together. A training MAE of ₹1,800 sitting next to a test MAE of ₹3,200 says the model memorised part of what it studied; the honest number, the one that goes in front of a landlord, is the ₹3,200.

Rent data adds its own way to cheat the cut. Flats repeat their building: if building 12 contributed six listings and a random shuffle drops four into train and two into test, the model meets building 12's price level while fitting and is then "tested" on the same building — the repeat-customer trap from Train / Test Split, wearing an address. The two test flats are not really unseen, so the test MAE flatters the model. When rows share a building, a street or a neighbourhood, keep the whole group on one side of the cut: group-split by building or neighbourhood.

And keep the timing test from Learning Setup running over every column. This tool runs the day a flat is listed, so a legal feature is a fact that exists on that day: size, distance, age, bedrooms all qualify. The discount the tenant eventually negotiated exists only after signing — training on it means partly reading the answer. The asking price is sneakier: the tool exists to set the asking price, so at the moment it runs there is no asking price yet; a column that is filled in by the very decision you are making is leakage of the circular kind. Broker commission, settled at signing, fails the same test.

Figure. A random shuffle of 500 listings put four of building 12's six flats in train and two in test. The model learns that building's price level while fitting, then gets scored on the same building — so the test flats are not truly unseen and the score is optimistic. Group-split by building keeps all six on one side.

Rent-pricing traps
TrapSymptomFix
Same building in both foldsTest MAE flatters the modelGroup-split by building / neighbourhood
Post-signing columns (discount, commission)Lab score collapses in productionKeep only facts known on listing day
Train MAE far below test MAE₹1,800 train vs ₹3,200 testReport the test number; simplify or regularise
Residuals curve with sizeMisses at both size extremesAdd an interaction or move to a tree
Your rent model prints a training MAE of ₹1,800 and a test MAE of ₹3,200. Which number goes in the report, and why?
  1. ₹1,800 — it used more rows, so it is better estimated
  2. The average, ₹2,500 — one number is fairer than two
  3. Neither — MAE cannot be compared across folds
  4. ₹3,200 — it is measured on flats the fit never saw, which is the situation the tool will actually face

Every flat the tool prices in production is one it never trained on. The training score rewards memorisation; the held-out score estimates the miss on genuinely new listings, and the gap between the two is itself a warning worth acting on.

6Lab: price flats end to end

Time to run the whole lesson as one pipeline, in the browser: load a real table of flats, hold out a test fold, score the median benchmark, fit the linear price list, and compare the two in rupees. The dataset is rent_price_v1: 200 flats, like the notebook — though this sample comes from a cheaper market (rents run about ₹1,270 to ₹3,660 a month) and records bedrooms and bathrooms instead of building age. Different city, same job. Its five columns are sqft, bedrooms, bathrooms, distance_km and rent, and the file is mounted for you at /data/rent_price_v1.csv.

Cell 1 loads and looks. pandas is the table library: read_csv pulls the file into a DataFrame — a table object, named df here. df.shape prints (rows, columns) so you can confirm 200 by 5, df.head(3) prints the first three flats so you see real values rather than trusting column names, and the median rent of the whole file — about ₹2,492 — prints for orientation. Nothing is fitted yet.

Cell 2 is the whole contract in one place, and it reuses df from Cell 1 — both cells share one running Python session (the kernel), so run them in order. First the cut: X takes the four feature columns (the double brackets select several columns as a table) and y takes the rent column; train_test_split with test_size=0.25 and random_state=0 locks 150 flats for fitting and 50 away for scoring. Then the benchmark: the training fold's median rent (about ₹2,532) is used as the guess for every test flat, and its MAE prints at about ₹481 — the floor. Then the model: LinearRegression fits on the training fold only, predicts the 50 held-out flats, and its MAE prints at about ₹62. Read the coefficients as rupee stories: about ₹1.1 per square foot (₹110 per extra 100 sqft), ₹200 per bedroom, ₹144 per bathroom, and −₹24 per kilometre from the hub — believable signs, all four.

Cell 3 draws the check that a single number cannot: a scatter of predicted against actual rent for the 50 test flats, with a dashed diagonal marking perfect prediction. A point on the diagonal is a flat priced exactly right; vertical distance from it is that flat's miss in rupees. Points hugging the line evenly is what a healthy fit looks like; a cloud that drifts off the diagonal at the cheap or expensive end is telling you where the straight shape gives out. The cell reuses y_test and pred from Cell 2, so change the title or markers and re-run just this cell — nothing refits.

Two honesty notes to carry out. The model's MAE of ₹62 against a benchmark of ₹481 is a genuine eight-fold cut — but the R² near 0.98 should still raise an eyebrow: this is a synthetic teaching sample, far cleaner than any real market. And the 50 test flats stayed untouched until scoring: the moment a choice depends on the test fold, its number stops being honest.

No diagram — the predicted-versus-actual scatter is drawn by the coding lab plot, with the dashed diagonal marking perfect prediction.

Lab checklist
StepWhy
Split with a pinned seed150 fit / 50 held out, identical on every re-run
Score the median benchmark first≈ ₹481 is the floor the model must beat
Fit, then read MAE in rupees≈ ₹62 against the floor is the honest claim
Plot predicted vs actualShows where the misses live, which MAE cannot

Coding lab. Price flats end to end runs in the app, with checks on your output.

The lab prints a benchmark MAE of about ₹481 and a model MAE of about ₹62. What claim does that pair support?
  1. The model is 481% more accurate than random guessing
  2. The model's typical miss on unseen flats is about ₹62 a month, roughly an eighth of what guessing the median would miss by
  3. About 62% of the rent variance is explained by the features
  4. The benchmark overfitted the training fold

Both numbers are MAEs on the same held-out flats, so they compare directly: the fitted price list cuts the typical rupee miss from about ₹481 to about ₹62. R² is a separate number and 481 is a rupee amount, not a percentage.

Notes

  • Regression for rent bands on a small housing sample.
  • Rent depends on size, rooms and distance to a hub — structured features, continuous target.
  • Start with LinearRegression before trees — coefficients tell a story ("each extra km costs about X") that a forest buries.

Exam traps & shortcuts

  • Keep lab datasets under 2000 rows in the browser runtime.
  • Split train and test before fitting any model that sees labels.

Recap

This lesson in brief:

Predict a number
Rent depends on size, rooms and distance to a hub — structured features, continuous target.
Linear baseline
Start with LinearRegression before trees — coefficients tell a story ("each extra km costs about X") that a forest buries.
Lab: rent regressor
Fit LinearRegression on rent_price_v1 and print the hold-out R² via model.score.

Practise Rent Pricing Application

Reading is free and needs no account. Practice, mocks and progress live in the app.

  • 10 exam-style questions on this topic, with explanations
  • A 5-question practice set that ends the chapter
  • Timed mocks scored with the real marking scheme
  • Readiness tracked per topic, kept on your device
Continue with Google — freeNo card, no trial. Works offline once installed.