SPB Git forge

spb/wp4_uqo

Public
3commits 1branches 1releases
5.4 MBsize
maindefault branch
1 h agolast push
Python 64.6% TeX 23.3% HTML 11.6% Makefile 0.5%
9.9 KB · 167 lines markdown
Rendered Raw Blame History
1<!-- Author: Simon-Pierre Boucher — simon-pierre.boucher@uqo.ca -->2# 🛏️ Hedonic Pricing of Short-Term Rental Properties34**UQO Working Paper No. 4** — *A Multi-Method Analysis of Airbnb Listing Prices in Quebec*56[![Paper](https://img.shields.io/badge/paper-PDF-b31b1b?logo=latex&logoColor=white)](paper/main.pdf)7[![Python](https://img.shields.io/badge/python-3.11%2B-3776AB?logo=python&logoColor=white)](requirements.txt)8[![Data](https://img.shields.io/badge/data-3%2C456%20priced%20Airbnb%20cards%20·%20parquet-4051b5)](data/raw/README.md)9[![Reproducible](https://img.shields.io/badge/reproducible-one%20script%2C%20%E2%89%88%2010%20min-2e7d32)](scripts/)10[![Institution](https://img.shields.io/badge/UQO-D%C3%A9pt.%20des%20sciences%20administratives-16365c)](https://uqo.ca)11[![Author](https://img.shields.io/badge/author-Simon--Pierre%20Boucher-16365c)](mailto:simon-pierre.boucher@uqo.ca)1213> **TL;DR** — What determines the displayed nightly price of an Airbnb listing in Quebec? A province-wide scrape of 5,00014> listing cards (3,456 priced) first has to be cleaned of a measurement defect: 26.5 % of "nightly" prices are multi-night15> stay totals (≈ 23 nights), detected and removed with a two-regime mixture of hedonic regressions (N = 2,480 nightly16> prices). On that sample a semi-log hedonic model with city fixed effects explains 51 % of log-price variance: capacity17> (guests, bathrooms, bedrooms), a shared bathroom (−32 %), photos, rating (+3.4 % per 0.1 point) and local density are the18> priced attributes; Superhost and Guest Favourite badges carry no premium. Implicit prices of rooms rise and those of19> reputation fall along the price distribution; spatial lag ρ̂ ≈ 0.20; gradient boosting adds ≈ 0.08 of out-of-sample R²20> (0.56 vs 0.47), with every model losing ≈ 0.07 when whole areas are held out.2122---2324## 📌 Status2526| Item | Value |27|---|---|28| Version | 1.1 (October 2026) — revised 2026-10-17 by the editorial-board review; v1.0 (May 2026) is tagged `pre-revision-20261017` |29| SSRN | not yet submitted |30| Journal | — |31| Code & data | fully reproducible from `data/processed/airbnb_clean_wp5.parquet` + `scripts/10_revision_reanalysis.py` (≈ 10 min on an Apple-silicon laptop) |3233## 🎯 What this paper does3435A listing card is a bundle of characteristics priced by its host. Following Rosen (1974) and Lancaster (1966), the paper36estimates the hedonic price function3738```39ln p_i = α + β_S' S_i + β_A' A_i + β_H' H_i + β_L' L_i + μ_c(i) + ε_i40```4142(structural, presentation, host/reputation and location blocks plus city / spatial-cell fixed effects) by nested OLS with43HC3 and clustered standard errors, re-estimates it at five quantiles, in spatial lag / error / Durbin form (ML, LeSage–Pace44impacts) and against five machine-learning models under random and spatially blocked cross-validation (SHAP for the best).45Before any of this, it diagnoses and models the stay-price contamination of the displayed price field.4647## 🏆 Headline results (v1.1, N = 2,480 nightly-regime listings)4849| Object | Estimate |50|---|---|51| Stay-price regime (mixture of regressions) | 976 of 3,456 priced listings (28 %); δ̂ = 3.15 log points ≈ 23 nights; 7 ambiguous listings |52| Structural-only OLS (M1) | R² = 0.443 |53| Full hedonic model with city / cell FE (M5) | R² = 0.509 (adj. 0.495), RMSE 0.475 |54| Elasticities (M5, HC3 SE) | guests 0.331 (0.037); ln(1+bathrooms) 0.437 (0.070); bedrooms 0.160 (0.042) |55| Shared bathroom | −32 % (Kennedy-corrected) |56| Rating (rated listings) | +0.337 per point (0.068) ≈ +3.4 % per 0.1 |57| Superhost / Guest Favourite | 0.023 (0.025) / −0.035 (0.027), not significant |58| Quantiles | bedroom elasticity 0.01 (τ=0.10) → 0.19 (τ=0.90); ln reviews +0.042 → −0.042; pseudo-R² 0.28 → 0.41 |59| Spatial | Moran's I significant; ρ̂ = 0.200 (SAR), 0.261 (SDM); λ̂ = 0.284 (SEM); SAR multiplier 1.25 |60| ML, random 5-fold CV | XGBoost R² 0.559 / MdAPE 26.4 % vs OLS-M5 0.473 / 28.5 % |61| ML, spatially blocked CV | XGBoost 0.483 vs OLS-M5 0.407 |6263## 🗂 Repository layout6465```66airbnb-listing-prices-hedonic/67├── data/68│   ├── raw/README.md                 # provenance; raw CSV not available69│   └── processed/airbnb_clean_wp5.parquet   # committed input (3,456 priced cards, from WP 5)70│       analysis_sample.csv           # written by the script (2,480 nightly-regime listings)71├── scripts/72│   ├── 10_revision_reanalysis.py     # ALL results of v1.1 (tables, figures, key numbers)73│   ├── 11_vif_table.py               # VIF appendix table from rev_key_numbers.json74│   ├── run_analysis.py, app.py       # v1.0 pipeline and dashboard (kept for the record; not used by v1.1)75├── src/                              # v1.0 package (kept for the record)76├── results/tables/rev_*.tex|json     # generated tables and key numbers (v1.1); other files = v1.0 artefacts77├── results/figures/, paper/figures/  # rev_fig_*.pdf (v1.1); 01–08 = v1.0 artefacts78├── docs/                             # REVIEW-REPORT.md, CHANGELOG-REVISION.md, main_pre-revision-20261017.pdf79└── paper/                            # main.tex + sections/ + references.bib → main.pdf80```8182## 🚀 Quick start8384```bash85python3 -m pip install -r requirements.txt86python3 scripts/10_revision_reanalysis.py     # ≈ 10 min; writes results/tables/rev_* and paper/figures/rev_*87python3 scripts/11_vif_table.py88cd paper && make                               # latexmk → main.pdf89```9091## 🗃 Data9293Scrape of Airbnb search-result cards for Quebec, early 2026: 5,000 cards, 19 fields (title, city, property-type label,94displayed price, rating, bedrooms, bathrooms, guests, amenity count, photos, reviews, Superhost, Guest Favourite, pets,95coordinates). No room type, host ID, amenity list, cleaning fee or minimum stay. 1,544 cards have no price. The committed96parquet is the WP 5 cleaned version of the 3,456 priced cards; the script parses the card title to recover the displayed97star rating (456 unrated, 37 truncated), repairs 465 bathroom and 63 bedroom counts, recodes 161 studios, and classifies98each card into the nightly or stay-price regime. See `data/raw/README.md`.99100## 🔬 Methodology1011021. **Price-regime diagnosis** — marginal normal mixture of ln p; two-regime mixture of hedonic regressions (EM, common slopes,103   regime-specific intercept shift and variance, logistic regime equation); posterior < 0.5 defines the analysis sample.1042. **Nested OLS M1–M5** with HC3 and FE-group-clustered SEs; Kennedy (1981) premia; VIF; block F-tests.1053. **Quantile regression** at τ ∈ {.10, .25, .50, .75, .90} with FE; paired bootstrap (B = 100) for τ=.90 − τ=.10 differences.1064. **Spatial econometrics** — KNN (k = 5, 10) W on projected km; Moran's I; SAR/SEM/SDM by ML; LR test; LeSage–Pace impacts107   with simulated SEs.1085. **Machine learning** — OLS, elastic net, random forest, gradient boosting, XGBoost, LightGBM; 5-fold random vs spatially109   blocked CV (20 blocks); R², RMSE, MAE (log), MdAPE (price); exact TreeSHAP for XGBoost.1106. **Robustness** — regime cut-offs, $600/$1,000 rules, full sample, weighting by 1 − p̂, hotels excluded, rated only,111   Montreal vs outside, trimming, 60-cell FE.112113## 🖼 Figures & tables inventory114115| File | Content |116|---|---|117| `rev_fig_logprice_mixture` | log-price histogram with the two mixture components |118| `rev_fig_price_by_category` | price by title category (box plots) |119| `rev_fig_map` | map of the analysis sample |120| `rev_fig_partials` | binned partial residuals: distance to centre, rating |121| `rev_fig_quantile` | quantile coefficients with 95 % bands |122| `rev_fig_shap` | SHAP summary plot (XGBoost) |123124Tables (`results/tables/rev_*.tex`): price regimes, mixture, stay-regime logit, summary statistics, price by category,125nested OLS, quantile, spatial models, impacts, ML cross-validation, SHAP importance, robustness, VIF. Key numbers quoted in126the text: `rev_key_numbers.json`.127128## ⚠️ Limitations129130- Displayed asking prices on one day, not transaction prices; cleaning fee unobserved; stay-regime listings cannot be131  converted to nightly prices (no stay length).132- Single cross-section: no seasonality, no within-listing variation; estimates are conditional associations, not marginal133  willingness to pay.134- No room type, host identifier or amenity list; the shared-bathroom flag and title category are the available proxies.135- Scrape coverage reflects the platform's search on the collection dates; denser in urban and resort areas.136137## 📝 Citation138139```bibtex140@techreport{boucher2026airbnbhedonic,141  author      = {Boucher, Simon-Pierre},142  title       = {Hedonic Pricing of Short-Term Rental Properties: A Multi-Method Analysis of Airbnb Listing Prices in Quebec},143  institution = {Universit\'e du Qu\'ebec en Outaouais, D\'epartement des sciences administratives},144  type        = {Working Paper},145  number      = {4},146  year        = {2026},147  month       = {October},148  note        = {Version 1.1}149}150```151152## 👤 Author & contact153154**Simon-Pierre Boucher** — Département des sciences administratives,155Université du Québec en Outaouais (UQO), Gatineau, QC.156📧 [simon-pierre.boucher@uqo.ca](mailto:simon-pierre.boucher@uqo.ca)157158## 🗒 Notes159160- **Revision 2026-10-17 (v1.0 → v1.1):** complete scientific revision by the editorial-board procedure; see161  `docs/REVIEW-REPORT.md` (diagnosis, verdicts, literature, maturity) and `docs/CHANGELOG-REVISION.md` (every change,162  old → new numbers, scripts, references). All v1.0 results were affected by a contaminated price field and several163  fabricated or mislabelled regressors; none is retained. The v1.0 PDF is `docs/main_pre-revision-20261017.pdf`.164- Harmonised 2026-10-17: `wp4/` → `paper/`, `outputs/` → `results/`, scripts moved to `scripts/`; bibliography style `aer`.165- Deviation from the standard layout: `data/processed/airbnb_clean_wp5.parquet` (227 KB) is committed because the raw CSV166  no longer exists anywhere; `.gitignore` carries the exception.167