SPB Git forge

spb/wp4_uqo

Public
3commits 1branches 1releases
5.4 MBsize
maindefault branch
25 min agolast push
Python 64.6% TeX 23.3% HTML 11.6% Makefile 0.5%
7.7 KB

# 🛏️ Hedonic Pricing of Short-Term Rental Properties

UQO Working Paper No. 4 — A Multi-Method Analysis of Airbnb Listing Prices in Quebec

Paper Python Data Reproducible Institution Author

TL;DR — What determines the nightly price of an Airbnb listing in Quebec? On 5,000 Inside Airbnb listings (3,412 with valid prices) we layer nine nested OLS hedonic specifications (R² from 0.052 structural-only to 0.274 with reputation, amenities, text and spatial controls), quantile regressions at five quantiles, four gradient-boosting / forest learners with SHAP (best: XGBoost, R² = 0.285, MAPE 14.3%), and spatial lag / error / Durbin models. Bedrooms, room type, review scores, location and amenity indices dominate, with weights that shift across the price distribution and across sub-markets.


# 📌 Status

Item Value
Version 1.0 (May 2026)
SSRN not yet submitted
Journal —
Code & data reproducible from scripts/ + src/; raw Inside Airbnb sample not committed (see data/raw/README.md)

# 🎯 What this paper does

Short-term rental prices are set by hosts, not by a market index, so the implicit prices of a listing's characteristics are the natural object of study. Following Rosen (1974) and Lancaster (1966), the nightly price is decomposed into structural characteristics, amenity bundles, host attributes, reputation signals, locational factors and text-derived features:

text
ln P_i = α + S_i'β + A_i'γ + H_i'δ + R_i'ζ + L_i'η + T_i'θ + ε_i

Each block is added in turn (M1 … M9), then the full specification is re-estimated by quantile regression, by machine learning with SHAP decomposition, and by spatial econometric models to check robustness to spatial dependence.

# 🏆 Headline results

Object Estimate
Structural-only OLS (M1) R² = 0.052
+ amenity indices (M2) R² = 0.098
+ reputation / reviews (M4) R² = 0.187 (largest single gain)
Full specification with spatial controls (M9), N = 1,906 R² = 0.274, adj. R² = 0.254, RMSE 1.169 (−15.3% vs M1)
Best learner (XGBoost) R² = 0.285, RMSE 1.159, MAPE 14.3%
CatBoost / LightGBM / Random Forest R² = 0.258 / 0.244 / 0.243
Dominant price determinants bedrooms, room type, review score, distance to centre, amenity indices

# 🗂 Repository layout

text
airbnb-listing-prices-hedonic/
├── data/
│   ├── raw/                  # cleaned_dataset_sample.csv (see data/raw/README.md) — not committed
│   ├── interim/ processed/ duckdb/
├── src/                      # package: config, data_loader, cleaning, feature_engineering, amenities,
│                             #   geospatial, nlp_features, hedonic_models, quantile_models, spatial_models,
│                             #   ml_models, shap_analysis, robustness, tables, figures, report
├── scripts/
│   ├── run_analysis.py       # master pipeline (features → models → figures → tables)
│   └── app.py                # Streamlit dashboard
├── results/
│   ├── tables/               # model_comparison, ml_comparison, price_premiums, quantile_coefficients, …
│   ├── figures/              # 01–08 publication figures (PNG + PDF)
│   └── models/               # model keys (fitted objects not committed)
├── Makefile                  # make all | features | models | figures | tables | paper | dashboard
└── paper/                    # main.tex + sections/ + figures/ + references.bib → main.pdf

# 🚀 Quick start

bash
python3 -m pip install -r requirements.txt
# place cleaned_dataset_sample.csv in data/raw/, then:
make models        # python3 scripts/run_analysis.py --data-file data/raw/cleaned_dataset_sample.csv
make figures
make paper         # cd paper && make (latexmk → main.pdf)
make dashboard     # streamlit run scripts/app.py

Runtime ≈ 10 minutes on an Apple-silicon laptop (SHAP and spatial models dominate).

# 🗃 Data

5,000 Inside Airbnb listings for Quebec (May 2026 extract, 19 raw variables). Prices below CAD 10 (17 obs.) or above CAD 25,000 (27 obs.) are dropped; 810 listings lack a price and 3,412 remain. Amenity strings are parsed into indices (family comfort, luxury, cleanliness), review scores are rescaled to 0–5, titles and descriptions are embedded into text features, and distances to the city centre are computed from coordinates. See data/raw/README.md.

# 🔬 Methodology

  1. Cleaning & features — src/cleaning.py, src/feature_engineering.py, src/amenities.py, src/nlp_features.py, src/geospatial.py.
  2. Nested OLS hedonic models M1–M9 with HC3 standard errors — src/hedonic_models.py.
  3. Quantile regression at τ ∈ {.10, .25, .50, .75, .90} — src/quantile_models.py.
  4. Machine learning (XGBoost, CatBoost, LightGBM, Random Forest, Gradient Boosting, GAM, ElasticNet) with SHAP — src/ml_models.py, src/shap_analysis.py.
  5. Spatial econometrics (SAR, SEM, SDM, k-nearest-neighbour weights) — src/spatial_models.py.
  6. Robustness (sub-markets, trimming, alternative amenity indices) and price decomposition — src/robustness.py, src/report.py.

# 🖼 Figures & tables inventory

Figure Content
01_price_distribution, 02_log_price_distribution nightly price distributions
03_price_map spatial distribution of prices
04_price_by_neighbourhood, 05_price_by_room_type price by neighbourhood / room type
07_review_score_premium reputation premium
08_distance_to_center_gradient price gradient with distance to centre

Tables (results/tables/*.tex|csv): model comparison (M1–M9), ML comparison, price premiums, quantile coefficients, robustness summary, price decomposition, price-associated words.

# ⚠️ Limitations

  • Listed (asking) nightly prices, not realized bookings; no occupancy data.
  • Cross-sectional snapshot; seasonality is not identified.
  • 5,000-listing sample; full-specification N = 1,906 after requiring reviews and location.
  • Text features are embedding-based and not individually interpretable.

# 📝 Citation

bibtex
@techreport{boucher2026airbnbhedonic,
  author      = {Boucher, Simon-Pierre},
  title       = {Hedonic Pricing of Short-Term Rental Properties: A Multi-Method Analysis of Airbnb Listing Prices in Quebec},
  institution = {Universit\'e du Qu\'ebec en Outaouais, D\'epartement des sciences administratives},
  type        = {Working Paper},
  number      = {4},
  year        = {2026},
  month       = {May}
}

# 👤 Author & contact

Simon-Pierre Boucher — Département des sciences administratives, Université du Québec en Outaouais (UQO), Gatineau, QC. 📧 simon-pierre.boucher@uqo.ca

# 🗒 Notes

  • Harmonised 2026-10-17: wp4/ → paper/, outputs/ → results/, run_analysis.py/app.py → scripts/; paths updated in src/config.py, src/figures.py, src/tables.py, scripts/app.py and the root Makefile.
  • Bibliography switched from apalike to aer (natbib authoryear,round,semicolon); compiles without warnings.