Instructions to use alm7zm/darscope-rent-model with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Scikit-learn
How to use alm7zm/darscope-rent-model with Scikit-learn:
from huggingface_hub import hf_hub_download import joblib model = joblib.load( hf_hub_download("alm7zm/darscope-rent-model", "sklearn_model.joblib") ) # only load pickle files from sources you trust # read more about it here https://skops.readthedocs.io/en/stable/persistence.html - Notebooks
- Google Colab
- Kaggle
DarScope rent model
A Ridge regression that suggests the yearly rent, in SAR, of a villa or duplex in Riyadh, Jeddah, Dammam or Al Khobar. It learned from 2021 rental ads, so its answer is a suggestion based on the 2021 market, not a valuation.
Made by alm7zm, and used for the rent suggestion in DarScope, a team web app for managing rental houses. Published on Hugging Face and Kaggle.
Results
Measured once, on 304 houses held out from training:
| Model | Average error (MAPE) | Average error (SAR) | Within 15% |
|---|---|---|---|
| This model (Ridge) | 23.1% | 22,998 | 46.1% |
| Ridge and gradient boosting averaged | 23.1% | 22,871 | 46.4% |
| Baseline: city and size only | 38.8% | 34,562 | 24.7% |
Boosting gained nothing over Ridge, so the simpler model was kept: it is one weighted sum that fits in a 10 KB JSON file.
What makes this model different
About 60% of the rows in this dataset are copies of the same ad. With a plain random split, the same houses land in both the training and the test set, so the score measures how well a model remembers houses, not how well it prices new ones. This model was built to avoid that trap and a few others:
| A quick approach | This model | |
|---|---|---|
| Copies | Kept, so copies of one house sit in both train and test | Removed first: 3,718 rows became 1,513 houses |
| Test set | One random 80/20 split | 1 house in 5 held out by a hash of its facts, so copies can never cross sides. Used once, at the very end |
| Choosing settings | By hand, checked on one split | 5-fold grouped cross-validation on the training houses only |
| Bad rows | Only extreme prices, cut by z-score | Six rules found by reading the ads: monthly, daily and weekly prices, apartments and single floors, offices and hotel villas, sale ads, impossible sizes and prices (95 rows) |
| Descriptions | Ignored | Arabic text normalised, then read for an annex and internal stairs, and to find the bad rows |
| Districts | Raw text: spelling variants split one district, and same-named districts in two cities merge | Normalised names, kept apart by city, and target-encoded so a rarely seen district leans towards the average |
| Score | RMSE and R² on the log scale | Error in SAR and in %, and the share within 15%, on houses the model never saw |
| Ready to use | A notebook | A 10 KB JSON with a library-free predict.py, plus the scikit-learn pipeline |
A leaky split would show a better-looking number. This one holds for a house the model has never seen: 23.1% average error, against 38.8% for a guess from city and size alone.
Inputs
City, district, street front, type (Villa or Duplex), size in m², age in years, bedrooms, bathrooms, living rooms, 13 amenities (kitchen, garage, driver's room, maid's room, furnished, AC, roof, pool, front yard, basement, stairs, elevator, fireplace) and the ad's description, from which two words are read: an annex (ملحق) and internal stairs (درج داخلي).
From these come 29 model inputs: the city, front and type one-hot encoded, the district (within its city) target-encoded, and 25 scaled numbers such as log size, size per bedroom and the amenity count. The model predicts the log of the rent.
How to use it
Without any library, from rent-model.json:
from predict import predict
predict("Riyadh", "حي الملقا", "North", "Villa", size=400, age=0, bedrooms=5, bathrooms=5,
livingrooms=2, amenities=["kitchen", "garage", "maid_room", "ac"],
description="فيلا جديدة مع ملحق")
# about 123,468 SAR a year
With scikit-learn 1.7.2, from rent-model.joblib. Its input is a table with the 29 columns that clean.py produces (see Training):
import joblib
import pandas as pd
model = joblib.load("rent-model.joblib") # a pickle: it can run code, so load only files you trust
houses = pd.read_csv("aqar-clean.csv")
model.predict(houses[model.feature_names_in_])
Both give the same rents, to within 0.01%.
Limits
- 2021 asking rents. The data is ads, not signed contracts, and rents have moved since.
- Villas and duplexes in four cities only, 100 to 1,652 m².
predictreturnsNoneoutside that size range. The score holds for yearly rents between 10,000 and 500,000 SAR. - Unknown districts. The model knows 203 districts. For any other one it uses the average district, and its error rises to about 32%.
- Dammam and Al Khobar have far fewer ads than Riyadh and Jeddah, so their districts are learned from fewer houses.
Training
- Data: Saudi Arabia Real Estate (AQAR) on Kaggle: 3,718 rows, of which 1,418 houses remain after cleaning (about 60% of the rows were copies). The data itself is not included here.
clean.pyrebuilds the clean table from the original file: it is on Hugging Face and runs as a Kaggle notebook. - Split: 1 house in 5 is held out by a hash of its facts, so copies of a house never sit on both sides. Every choice was made with 5-fold grouped cross-validation on the other 1,114.
- Model:
TransformedTargetRegressor(log/exp)aroundOneHotEncoder+TargetEncoder+StandardScaler, thenRidge(alpha=1). After the test, the final model was fitted on all 1,418 houses; the scores above are from before that. - The full story, from the first data checks to every model tried and its scores, is in
prediction-model.md. The code isprepare.ipynb, saved without its outputs, which would show rows of the data.
Files
| File | What it is |
|---|---|
rent-model.json |
The weights: a base, one number per city, front, type and district, and 25 input weights |
predict.py |
Turns a house into a rent from the JSON, with no libraries. python predict.py checks it |
rent-model.joblib |
The scikit-learn pipeline (pickle; needs scikit-learn 1.7.2) |
prepare.ipynb |
The notebook that explored and cleaned the data, compared the models, took the test and exported the model |
prediction-model.md |
The write-up of every step, with the numbers each one found |
requirements.txt |
The library versions the notebook ran with |
Licence
The model, code and write-up are under CC BY 4.0: credit alm7zm. They hold no rows of the training data, whose licence reads "Data files © Original Authors".
- Downloads last month
- -