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%

révision scientifique complète (editorial board, 2026-10-17)

- Diagnostic et modélisation du champ prix bimodal (prix de séjour ≈ 23 nuits pour 28 % des annonces) : mélange de régressions hédoniques (EM), échantillon nocturne N = 2 480
- Retrait des régresseurs fabriqués (indices d'aménités bruités, faux types de chambre, hôte multi-annonces) ; titre structuré parsé (note, salles de bain, studios, catégorie)
- OLS M1–M5 avec effets fixes ville/cellule, HC3 + grappes ; quantiles + bootstrap ; SAR/SEM/SDM (ML) + impacts LeSage–Pace ; CV aléatoire vs blocs spatiaux ; TreeSHAP
- Bibliographie 21 → 50 références vérifiées (Crossref/RePEc) ; v1.1, October 2026 ; docs/REVIEW-REPORT.md + docs/CHANGELOG-REVISION.md

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed 1 h ago (Oct 18, 2026) parent f51c462

46 changed files +5,616 −1,259

modified .gitignore +1 −0
@@ -3,6 +3,7 @@ data/raw/*
3 3 !data/raw/README.md
4 4 data/processed/*
5 5 !data/processed/.gitkeep
6 +!data/processed/airbnb_clean_wp5.parquet
6 7
7 8 # Python
8 9 __pycache__/
modified Makefile +6 −1
@@ -7,7 +7,7 @@ DATA_FILE = data/raw/cleaned_dataset_sample.csv
7 7 OUTPUT_DIR = results
8 8 PAPER_DIR = paper
9 9
10 −.PHONY: all clean download features models figures tables paper dashboard help
10 +.PHONY: all clean download features models figures tables paper dashboard help revision
11 11
12 12 help:
13 13 @echo "Airbnb Hedonic Pricing Analysis"
@@ -62,6 +62,11 @@ tables:
62 62 @echo "Tables generated during model estimation"
63 63 @ls -la $(OUTPUT_DIR)/tables/ 2>/dev/null || echo "Run 'make models' first"
64 64
65 +revision:
66 + $(PYTHON) scripts/10_revision_reanalysis.py
67 + $(PYTHON) scripts/11_vif_table.py
68 + @echo "v1.1 tables and figures regenerated (results/tables/rev_*, paper/figures/rev_*)"
69 +
65 70 paper:
66 71 cd $(PAPER_DIR) && make
67 72 @echo "Paper compiled: $(PAPER_DIR)/main.pdf"
modified README.md +87 −72
@@ -3,19 +3,21 @@
3 3
4 4 **UQO Working Paper No. 4** — *A Multi-Method Analysis of Airbnb Listing Prices in Quebec*
5 5
6 −[![Paper](https://img.shields.io/badge/paper-PDF%20(28%20p.)-b31b1b?logo=latex&logoColor=white)](paper/main.pdf)
6 +[![Paper](https://img.shields.io/badge/paper-PDF-b31b1b?logo=latex&logoColor=white)](paper/main.pdf)
7 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-5%2C000%20Inside%20Airbnb%20listings%20·%20CSV-4051b5)](data/raw/README.md)
9 −[![Reproducible](https://img.shields.io/badge/reproducible-end--to--end%20pipeline-2e7d32)](scripts/)
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 10 [![Institution](https://img.shields.io/badge/UQO-D%C3%A9pt.%20des%20sciences%20administratives-16365c)](https://uqo.ca)
11 11 [![Author](https://img.shields.io/badge/author-Simon--Pierre%20Boucher-16365c)](mailto:simon-pierre.boucher@uqo.ca)
12 12
13 −> **TL;DR** — What determines the nightly price of an Airbnb listing in Quebec? On 5,000 Inside Airbnb listings
14 −> (3,412 with valid prices) we layer nine nested OLS hedonic specifications (R² from 0.052 structural-only to 0.274 with
15 −> reputation, amenities, text and spatial controls), quantile regressions at five quantiles, four gradient-boosting /
16 −> forest learners with SHAP (best: XGBoost, R² = 0.285, MAPE 14.3%), and spatial lag / error / Durbin models. Bedrooms,
17 −> room type, review scores, location and amenity indices dominate, with weights that shift across the price distribution
18 −> and across sub-markets.
13 +> **TL;DR** — What determines the displayed nightly price of an Airbnb listing in Quebec? A province-wide scrape of 5,000
14 +> listing cards (3,456 priced) first has to be cleaned of a measurement defect: 26.5 % of "nightly" prices are multi-night
15 +> stay totals (≈ 23 nights), detected and removed with a two-regime mixture of hedonic regressions (N = 2,480 nightly
16 +> prices). On that sample a semi-log hedonic model with city fixed effects explains 51 % of log-price variance: capacity
17 +> (guests, bathrooms, bedrooms), a shared bathroom (−32 %), photos, rating (+3.4 % per 0.1 point) and local density are the
18 +> priced attributes; Superhost and Guest Favourite badges carry no premium. Implicit prices of rooms rise and those of
19 +> 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.
19 21
20 22 ---
21 23
@@ -23,106 +25,114 @@
23 25
24 26 | Item | Value |
25 27 |---|---|
26 −| Version | 1.0 (May 2026) |
28 +| Version | 1.1 (October 2026) — revised 2026-10-17 by the editorial-board review; v1.0 (May 2026) is tagged `pre-revision-20261017` |
27 29 | SSRN | not yet submitted |
28 30 | Journal | — |
29 −| Code & data | reproducible from `scripts/` + `src/`; raw Inside Airbnb sample not committed (see `data/raw/README.md`) |
31 +| Code & data | fully reproducible from `data/processed/airbnb_clean_wp5.parquet` + `scripts/10_revision_reanalysis.py` (≈ 10 min on an Apple-silicon laptop) |
30 32
31 33 ## 🎯 What this paper does
32 34
33 −Short-term rental prices are set by hosts, not by a market index, so the implicit prices of a listing's characteristics
34 −are the natural object of study. Following Rosen (1974) and Lancaster (1966), the nightly price is decomposed into
35 −structural characteristics, amenity bundles, host attributes, reputation signals, locational factors and text-derived
36 −features:
35 +A listing card is a bundle of characteristics priced by its host. Following Rosen (1974) and Lancaster (1966), the paper
36 +estimates the hedonic price function
37 37
38 38 ```
39 −ln P_i = α + S_i'β + A_i'γ + H_i'δ + R_i'ζ + L_i'η + T_i'θ + ε_i
39 +ln p_i = α + β_S' S_i + β_A' A_i + β_H' H_i + β_L' L_i + μ_c(i) + ε_i
40 40 ```
41 41
42 −Each block is added in turn (M1 … M9), then the full specification is re-estimated by quantile regression, by machine
43 −learning with SHAP decomposition, and by spatial econometric models to check robustness to spatial dependence.
42 +(structural, presentation, host/reputation and location blocks plus city / spatial-cell fixed effects) by nested OLS with
43 +HC3 and clustered standard errors, re-estimates it at five quantiles, in spatial lag / error / Durbin form (ML, LeSage–Pace
44 +impacts) and against five machine-learning models under random and spatially blocked cross-validation (SHAP for the best).
45 +Before any of this, it diagnoses and models the stay-price contamination of the displayed price field.
44 46
45 −## 🏆 Headline results
47 +## 🏆 Headline results (v1.1, N = 2,480 nightly-regime listings)
46 48
47 49 | Object | Estimate |
48 50 |---|---|
49 −| Structural-only OLS (M1) | R² = 0.052 |
50 −| + amenity indices (M2) | R² = 0.098 |
51 −| + reputation / reviews (M4) | R² = 0.187 (largest single gain) |
52 −| Full specification with spatial controls (M9), N = 1,906 | R² = 0.274, adj. R² = 0.254, RMSE 1.169 (−15.3% vs M1) |
53 −| Best learner (XGBoost) | R² = 0.285, RMSE 1.159, MAPE 14.3% |
54 −| CatBoost / LightGBM / Random Forest | R² = 0.258 / 0.244 / 0.243 |
55 −| Dominant price determinants | bedrooms, room type, review score, distance to centre, amenity indices |
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 |
56 62
57 63 ## 🗂 Repository layout
58 64
59 65 ```
60 66 airbnb-listing-prices-hedonic/
61 67 ├── data/
62 −│ ├── raw/ # cleaned_dataset_sample.csv (see data/raw/README.md) — not committed
63 −│ ├── interim/ processed/ duckdb/
64 −├── src/ # package: config, data_loader, cleaning, feature_engineering, amenities,
65 −│ # geospatial, nlp_features, hedonic_models, quantile_models, spatial_models,
66 −│ # ml_models, shap_analysis, robustness, tables, figures, report
68 +│ ├── raw/README.md # provenance; raw CSV not available
69 +│ └── 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)
67 71 ├── scripts/
68 −│ ├── run_analysis.py # master pipeline (features → models → figures → tables)
69 −│ └── app.py # Streamlit dashboard
70 −├── results/
71 −│ ├── tables/ # model_comparison, ml_comparison, price_premiums, quantile_coefficients, …
72 −│ ├── figures/ # 01–08 publication figures (PNG + PDF)
73 −│ └── models/ # model keys (fitted objects not committed)
74 −├── Makefile # make all | features | models | figures | tables | paper | dashboard
75 −└── paper/ # main.tex + sections/ + figures/ + references.bib → main.pdf
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.json
74 +│ ├── 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 artefacts
77 +├── results/figures/, paper/figures/ # rev_fig_*.pdf (v1.1); 01–08 = v1.0 artefacts
78 +├── docs/ # REVIEW-REPORT.md, CHANGELOG-REVISION.md, main_pre-revision-20261017.pdf
79 +└── paper/ # main.tex + sections/ + references.bib → main.pdf
76 80 ```
77 81
78 82 ## 🚀 Quick start
79 83
80 84 ```bash
81 85 python3 -m pip install -r requirements.txt
82 −# place cleaned_dataset_sample.csv in data/raw/, then:
83 −make models # python3 scripts/run_analysis.py --data-file data/raw/cleaned_dataset_sample.csv
84 −make figures
85 −make paper # cd paper && make (latexmk → main.pdf)
86 −make dashboard # streamlit run scripts/app.py
86 +python3 scripts/10_revision_reanalysis.py # ≈ 10 min; writes results/tables/rev_* and paper/figures/rev_*
87 +python3 scripts/11_vif_table.py
88 +cd paper && make # latexmk → main.pdf
87 89 ```
88 90
89 −Runtime ≈ 10 minutes on an Apple-silicon laptop (SHAP and spatial models dominate).
90 −
91 91 ## 🗃 Data
92 92
93 −5,000 Inside Airbnb listings for Quebec (May 2026 extract, 19 raw variables). Prices below CAD 10 (17 obs.) or above
94 −CAD 25,000 (27 obs.) are dropped; 810 listings lack a price and 3,412 remain. Amenity strings are parsed into indices
95 −(family comfort, luxury, cleanliness), review scores are rescaled to 0–5, titles and descriptions are embedded into
96 −text features, and distances to the city centre are computed from coordinates. See `data/raw/README.md`.
93 +Scrape of Airbnb search-result cards for Quebec, early 2026: 5,000 cards, 19 fields (title, city, property-type label,
94 +displayed price, rating, bedrooms, bathrooms, guests, amenity count, photos, reviews, Superhost, Guest Favourite, pets,
95 +coordinates). No room type, host ID, amenity list, cleaning fee or minimum stay. 1,544 cards have no price. The committed
96 +parquet is the WP 5 cleaned version of the 3,456 priced cards; the script parses the card title to recover the displayed
97 +star rating (456 unrated, 37 truncated), repairs 465 bathroom and 63 bedroom counts, recodes 161 studios, and classifies
98 +each card into the nightly or stay-price regime. See `data/raw/README.md`.
97 99
98 100 ## 🔬 Methodology
99 101
100 −1. **Cleaning & features** — `src/cleaning.py`, `src/feature_engineering.py`, `src/amenities.py`, `src/nlp_features.py`, `src/geospatial.py`.
101 −2. **Nested OLS hedonic models** M1–M9 with HC3 standard errors — `src/hedonic_models.py`.
102 −3. **Quantile regression** at τ ∈ {.10, .25, .50, .75, .90} — `src/quantile_models.py`.
103 −4. **Machine learning** (XGBoost, CatBoost, LightGBM, Random Forest, Gradient Boosting, GAM, ElasticNet) with SHAP — `src/ml_models.py`, `src/shap_analysis.py`.
104 −5. **Spatial econometrics** (SAR, SEM, SDM, k-nearest-neighbour weights) — `src/spatial_models.py`.
105 −6. **Robustness** (sub-markets, trimming, alternative amenity indices) and price decomposition — `src/robustness.py`, `src/report.py`.
102 +1. **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.
104 +2. **Nested OLS M1–M5** with HC3 and FE-group-clustered SEs; Kennedy (1981) premia; VIF; block F-tests.
105 +3. **Quantile regression** at τ ∈ {.10, .25, .50, .75, .90} with FE; paired bootstrap (B = 100) for τ=.90 − τ=.10 differences.
106 +4. **Spatial econometrics** — KNN (k = 5, 10) W on projected km; Moran's I; SAR/SEM/SDM by ML; LR test; LeSage–Pace impacts
107 + with simulated SEs.
108 +5. **Machine learning** — OLS, elastic net, random forest, gradient boosting, XGBoost, LightGBM; 5-fold random vs spatially
109 + blocked CV (20 blocks); R², RMSE, MAE (log), MdAPE (price); exact TreeSHAP for XGBoost.
110 +6. **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.
106 112
107 113 ## 🖼 Figures & tables inventory
108 114
109 −| Figure | Content |
115 +| File | Content |
110 116 |---|---|
111 −| `01_price_distribution`, `02_log_price_distribution` | nightly price distributions |
112 −| `03_price_map` | spatial distribution of prices |
113 −| `04_price_by_neighbourhood`, `05_price_by_room_type` | price by neighbourhood / room type |
114 −| `07_review_score_premium` | reputation premium |
115 −| `08_distance_to_center_gradient` | price gradient with distance to centre |
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) |
116 123
117 −Tables (`results/tables/*.tex|csv`): model comparison (M1–M9), ML comparison, price premiums, quantile coefficients,
118 −robustness summary, price decomposition, price-associated words.
124 +Tables (`results/tables/rev_*.tex`): price regimes, mixture, stay-regime logit, summary statistics, price by category,
125 +nested OLS, quantile, spatial models, impacts, ML cross-validation, SHAP importance, robustness, VIF. Key numbers quoted in
126 +the text: `rev_key_numbers.json`.
119 127
120 128 ## ⚠️ Limitations
121 129
122 −- Listed (asking) nightly prices, not realized bookings; no occupancy data.
123 −- Cross-sectional snapshot; seasonality is not identified.
124 −- 5,000-listing sample; full-specification N = 1,906 after requiring reviews and location.
125 −- Text features are embedding-based and not individually interpretable.
130 +- Displayed asking prices on one day, not transaction prices; cleaning fee unobserved; stay-regime listings cannot be
131 + converted to nightly prices (no stay length).
132 +- Single cross-section: no seasonality, no within-listing variation; estimates are conditional associations, not marginal
133 + 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.
126 136
127 137 ## 📝 Citation
128 138
@@ -134,7 +144,8 @@ robustness summary, price decomposition, price-associated words.
134 144 type = {Working Paper},
135 145 number = {4},
136 146 year = {2026},
137 − month = {May}
147 + month = {October},
148 + note = {Version 1.1}
138 149 }
139 150 ```
140 151
@@ -146,6 +157,10 @@ Université du Québec en Outaouais (UQO), Gatineau, QC.
146 157
147 158 ## 🗒 Notes
148 159
149 −- Harmonised 2026-10-17: `wp4/` → `paper/`, `outputs/` → `results/`, `run_analysis.py`/`app.py` → `scripts/`;
150 − paths updated in `src/config.py`, `src/figures.py`, `src/tables.py`, `scripts/app.py` and the root `Makefile`.
151 −- Bibliography switched from `apalike` to `aer` (natbib `authoryear,round,semicolon`); compiles without warnings.
160 +- **Revision 2026-10-17 (v1.0 → v1.1):** complete scientific revision by the editorial-board procedure; see
161 + `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 several
163 + 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 CSV
166 + no longer exists anywhere; `.gitignore` carries the exception.
added data/processed/airbnb_clean_wp5.parquet +0 −0

Binary file not shown.

modified data/raw/README.md +8 −7
@@ -1,10 +1,11 @@
1 −# Raw data — Inside Airbnb, Quebec
1 +# Raw data — Airbnb search-result cards, Quebec
2 2
3 3 | Item | Value |
4 4 |---|---|
5 −| Source | Inside Airbnb public extracts (listings.csv) for Quebec markets, cleaned sample |
6 −| File expected here | `cleaned_dataset_sample.csv` — 5,000 listings × 19 variables |
7 −| Retained after cleaning | 3,412 listings with a valid nightly price (CAD 10 – 25,000), 1,906 in the full specification with reviews and location |
8 −| Fields | nightly price, room/property type, bedrooms, bathrooms, guests, amenities list, host attributes, review counts and scores, latitude/longitude, neighbourhood, listing title/description |
9 −| Extraction | May 2026 |
10 −| Access | Inside Airbnb data are released under CC BY 4.0; the cleaned sample is not committed here — download the Quebec `listings.csv` files from insideairbnb.com and run `make download` after placing the file in this folder. |
5 +| Source | Scrape of Airbnb's public search pages for the province of Quebec (listing cards). **Not** an Inside Airbnb extract: no room type, host ID, amenity list, cleaning fee, minimum stay or calendar. |
6 +| Raw file | `cleaned_dataset_sample.csv` (5,000 cards × 19 fields: name, city, property_type, price_numeric, price_category, rating, rating_category, bedrooms, bathrooms, guests_count, amenities_count, num_images, num_reviews, quality_score, is_superhost, is_guest_favorite, pets_allowed, lat, long). The raw file is **not available** (absent from this repository, from the laptop and from the cluster as of 2026-10-17). |
7 +| Committed derivative | `data/processed/airbnb_clean_wp5.parquet` — the 3,456 priced cards, as cleaned by the companion paper UQO WP 5 (`02_clean_airbnb.py`: price winsorised at p1/p99 = $30.96 / $18,205, missing ratings median-imputed, missing review counts set to 0, city names standardised). This is the only local copy of the data and the input of `scripts/10_revision_reanalysis.py`, which reverses the rating imputation and repairs bathrooms/bedrooms from the card title. |
8 +| Collection date | Early 2026; the file carries no timestamp. Same 5,000 cards as WP 5 (rental extraction dated 8 January 2026). |
9 +| Known defects | Displayed price is bimodal: 26.5 % of priced cards show a multi-night stay total (≈ 23 nights) instead of a nightly rate; `bathrooms = 0` whenever the title qualifies the bath (shared/private/half); studios have `bedrooms = 0`; 50 titles served in German with decimal-comma ratings truncated to 4.0 in the `rating` field; `quality_score` is a scraper composite of reviews, badges and photos. |
10 +| Analysis sample | 2,480 cards classified in the nightly-price regime (`data/processed/analysis_sample.csv`, written by the script). |
11 +| Licence / ethics | Publicly displayed listing information; no personal data beyond what the platform shows on search cards; no host identifiers. |
added docs/CHANGELOG-REVISION.md +74 −0
@@ -0,0 +1,74 @@
1 +# Changelog — scientific revision of UQO WP 4 (editorial board, 2026-10-17)
2 +
3 +Reference state: tag `pre-revision-20261017`, `docs/main_pre-revision-20261017.pdf`. All original files are preserved in git.
4 +Every number of v1.1 is produced by `scripts/10_revision_reanalysis.py` and written to `results/tables/rev_*.tex|json` and
5 +`paper/figures/rev_*.pdf`; no table is typed by hand. Key numbers quoted in the text are in `results/tables/rev_key_numbers.json`.
6 +
7 +## 1. Data provenance and preparation
8 +
9 +| # | Where | Before (v1.0) | After (v1.1) | Why / evidence |
10 +|---|---|---|---|---|
11 +| 1 | §2.1, README, `data/raw/README.md` | "Inside Airbnb extract, listings.csv, amenity lists, host profiles, descriptions, calendar" | Scrape of Airbnb search-result cards (19 fields; no room type, host ID, amenity list, cleaning fee, minimum stay); file without timestamp, early 2026, same 5,000 listings as WP 5 | `src/data_loader.py` schema; `data_inspection.txt` of WP 5; Guest Favourite badge and "quality_score" do not exist in Inside Airbnb |
12 +| 2 | data | raw `cleaned_dataset_sample.csv` absent from the repo and from the laptop and cluster | `data/processed/airbnb_clean_wp5.parquet` (227 KB) copied from WP 5 (`02_clean_airbnb.py`: price p1/p99 winsorised, rating median-imputed, reviews NaN→0, city names standardised) and committed; the only local copy of the data | search of laptop + 6 cluster nodes, 2026-10-17 |
13 +| 3 | §2.1 | rating "converted from 0–100 to 0–5"; 810 missing ratings | ratings already 0–5; 456 of 3,456 priced listings unrated (parsed from title: no star); 37 German-locale ratings truncated to 4.0 by a decimal-comma error, repaired from the title | script §1, `KEY.n_unrated`, `KEY.n_rating_truncated_fixed` |
14 +| 4 | §2.1 | bathrooms field used as is (478 zeros) | 433 zero-bathroom records repaired from the title ("1 shared bath", "1 private bath"), 32 half baths = 0.5; 161 studios recoded to one sleeping room + studio indicator; 46 bedroom counts recovered from titles | the scraper stored 0 whenever the bath descriptor was qualified; `KEY.n_bathrooms_recovered = 465` |
15 +| 5 | §2 | "Entire home 48.1 %, private room 35.5 %, shared room 16.4 %" | removed — these were property-type groups relabelled in `src/feature_engineering.py` (`Rental unit` → "private room", `Other` → "shared room"); room type is not observed | code inspection |
16 +| 6 | §2, §3, §4 | six "amenity indices" (luxury, business travel, family comfort, leisure, remote work, richness) | removed — `src/amenities.py::_proxy_indices_from_count` adds N(0, 0.05) noise to the normalised count; only `ln(1 + amenities)` is used | code inspection; integrity |
17 +| 7 | §2, §3 | "multi-listing host" (duplicated titles), `host_professional_dummy` (constant 0), reputation score, cleanliness premium, "location rating premium", "quality score" | removed; quality score shown to be a function of reviews/badges/photos (R² 0.63) | code inspection; script §1 |
18 +| 8 | §2, §4 | TF-IDF/SVD "text embeddings" of the card title (templated: category · city · rating · bedrooms · beds · baths) | removed; the title is parsed into its fields instead (category, rating, beds, bath type) | the "text" effect was a re-encoding of city and size |
19 +
20 +## 2. The price field (main correction)
21 +
22 +| # | Where | Before | After | Evidence |
23 +|---|---|---|---|---|
24 +| 9 | §2.2, Fig. 1, Table 1 | nightly price mean \$1,115, median \$219, P75 \$1,139, Winsorisation \$38–\$10,822; no comment | bimodal log price (mixture modes ≈ \$150 and ≈ \$2,500); 915 listings (26.5 %) above \$1,000; median ratio above/below \$1,000 by bedrooms 16–19 ×; interpretation: total stay price (≈ 23 nights) captured for part of the sample | `rev_price_regimes.tex`, `rev_fig_logprice_mixture.pdf`, `KEY.mix` |
25 +| 10 | §2.2, §3.6, Table 2 | — | two-regime mixture of hedonic regressions (EM, common slopes, δ̂ = 3.154, σ̂₀ = 0.493, σ̂₁ = 0.568, logistic regime equation); 976 stay-regime listings (83 of them ≤ \$1,000), 22 nightly listings > \$1,000, 7 ambiguous; analysis sample N = 2,480 | `rev_mixture.tex`, `KEY.mixreg` |
26 +| 11 | all result tables | N = 3,412 / 2,861 / 1,906 (listwise + neighbour-within-500 m selection) | N = 2,480 in every specification | script |
27 +
28 +## 3. Models and results (old → new)
29 +
30 +| # | Where | Before | After | Evidence |
31 +|---|---|---|---|---|
32 +| 12 | Table 4 (nested OLS) | M1–M9, 15–50 "parameters" (60 rows in appendix, duplicates, pinv), R² 0.052 → 0.274 | M1–M5, 10–21 regressors + FE, R² 0.443 → 0.509, adj. 0.440 → 0.495, RMSE 0.506 → 0.475; HC3 and cluster SEs | `rev_ols_nested.tex` |
33 +| 13 | §4.3 | bedrooms +212.9 % (β = 1.141), log bedrooms −87 % | ln bedrooms elasticity 0.160 (HC3 0.042), ln(1+bathrooms) 0.437 (0.070), ln guests 0.331 (0.037), shared bath −0.385 (0.053) | id. |
34 +| 14 | §4.5 | rating β = 1.052 → "11.1 % per 0.1 point"; "has reviews" β = 9.511 | rating 0.337 per point among rated listings (≈ 3.4 % per 0.1), rated indicator −0.041 n.s., ln reviews 0.015 n.s., Superhost 0.023 n.s., Guest Favourite −0.035 n.s. | id. |
35 +| 15 | §4.4 | amenity richness −23.6 %, business travel −68.5 % | removed (fabricated regressors); ln(1+amenities) 0.094 (0.038), ln(1+photos) 0.087 (0.022), pets −0.044 (0.023) | id. |
36 +| 16 | §4.6 | latitude −8.6 %, density 500 m −0.8 %/listing, density 1 km +0.3 %, "local average price" +0.025 %, spatial cluster −1.3 % | ln(1+km to centre) −0.035 (0.019) with FE, ln(1+listings within 1 km) 0.064 (0.013); no neighbour-price regressor (treated by the SAR instead) | id. |
37 +| 17 | Table 7 (quantiles) | 16 covariates incl. three collinear "room-type" dummies (≈ 1.0 each), pseudo-R² 0.10 → 0.02 | M5 regressors + FE at five quantiles; pseudo-R² 0.278 → 0.405; bootstrap tests of τ = 0.9 − τ = 0.1 differences | `rev_quantile.tex`, `KEY.iq_diff_90_10` |
38 +| 18 | §4.10 (spatial) | no estimate reported (spreg absent; fallbacks) | Moran's I, SAR/SEM/SDM by ML (k = 5; k = 10 check), LR test, LeSage–Pace impacts with simulated SEs | `rev_spatial.tex`, `rev_impacts.tex`, `KEY.moran`, `KEY.spatial` |
39 +| 19 | Table 8 (ML) | random 80/20 split, N_test = 382; "CatBoost" = sklearn GBR; "GAM" = polynomial; MAPE on log prices (14.3 %) | 5-fold random and spatially blocked CV (20 blocks) for OLS-M5, elastic net, RF, GBM, XGBoost, LightGBM; R², RMSE, MAE (log) and MdAPE (price scale); CatBoost and GAM dropped (packages absent, no fallback relabelling) | `rev_ml_cv.tex` |
40 +| 20 | §4.9 (SHAP) | claimed; never computed (permutation fallback, no table) | exact TreeExplainer SHAP on XGBoost; importance table and beeswarm | `rev_shap_importance.tex`, `rev_fig_shap.pdf` |
41 +| 21 | Table 9 (decomposition) | arithmetically impossible (predicted mean 3.99 vs 5.87; intercept 0; two blocks 0) | removed (not a result); block F-tests reported instead | `KEY.ftests_M5` |
42 +| 22 | §5 | property-type subsamples labelled "room type"; regressions within price segments (conditioning on y); "Ultra-Luxury > \$1,000" = stay regime; adj. R² 0.08–0.10 | new robustness table (regime cut-offs 0.25/0.75, \$600/\$1,000 rules, full sample, weighting by 1 − p̂, hotel exclusion, rated only, Montreal/outside, trimming, 60-cell FE) | `rev_robustness.tex` |
43 +| 23 | Figures 1–8 | produced on the contaminated sample; two of them (price distributions) displayed the bimodality without comment | Fig. 1 mixture; Fig. 2 price by category; Fig. 3 map; Fig. 4 partial relationships; Fig. 5 quantile coefficients; Fig. 6 SHAP | `paper/figures/rev_*.pdf` |
44 +| 24 | main.tex | version 1.0, May 2026; JEL C21, C31, C45, C58, L83, R31, R33 | version 1.1, October 2026; JEL C21, C31, C45, L83, R31, Z30; keywords harmonised ("hedonic price function", "implicit prices") | HARMONISATION.md |
45 +
46 +## 4. References
47 +
48 +Removed 3 (Chattopadhyay & Machemehl 2006 unverifiable; Dogru & Pekin 2017 grey literature; Apley & Zhu 2020 unused).
49 +Corrected 5 (Chen & Xie year 2017 and key; Magno et al. third author Ugolini; Gibbs et al. hedonic paper JTTM 35(1) added
50 +as the source of the amenity result; Pérez-Sánchez and Zhang given names). Added 32, all verified on Crossref
51 +(`api.crossref.org/works?query.bibliographic=…` and DOI lookups, 2026-10-17; Halvorsen–Palmquist 1980 and Kennedy 1981 verified
52 +through RePEc). Full list with DOIs in `docs/REVIEW-REPORT.md` §4. Total 21 → 50.
53 +
54 +## 5. Re-analyses executed
55 +
56 +| Script | What | Runtime | Outputs |
57 +|---|---|---|---|
58 +| `scripts/10_revision_reanalysis.py` | title parsing and repairs; marginal mixture; regression mixture (EM); descriptives; OLS M1–M5 (HC3, cluster); VIF; block F-tests; QR (5 τ) + paired bootstrap (B = 100); Moran's I; SAR/SEM/SDM ML + impacts; 5-fold random/blocked CV of 6 models; SHAP; 12-variant robustness; 6 figures | ≈ 9 min on the laptop (bootstrap ≈ 6 min, cached in `rev_iq_bootstrap.json`) | `results/tables/rev_*.{tex,json}`, `paper/figures/rev_*.pdf`, `data/processed/analysis_sample.csv` |
59 +
60 +The v1.0 pipeline (`scripts/run_analysis.py`, `src/`) is kept unchanged for the record; it is not used by the revised paper.
61 +Its outputs in `results/tables/` (non-`rev_` files) and `results/figures/01–08` are the v1.0 artefacts.
62 +
63 +## 6. Not modified / not possible with these data
64 +
65 +Nightly price of stay-regime listings (no stay length or search dates); room type, host identity, amenity list, cleaning fee,
66 +minimum stay (not scraped); seasonality and panel variation (single cross-section); census or FSA neighbourhood identifiers
67 +(no postal code in the Airbnb file); hedonic estimates on realised bookings.
68 +
69 +## 7. Build
70 +
71 +`cd paper && make` (latexmk, pdflatex + bibtex, `aer` style): 0 errors, 0 undefined references/citations, 0 multiply-defined
72 +labels, 0 overfull boxes > 1 pt, 0 BibTeX warnings. 39 pages (v1.0: 28). Page 1: "Working Paper No. 4", title, author,
73 +"October 2026", "Version 1.1"; page 2: Abstract, Keywords, JEL Classification (checked with PyMuPDF). No `main_anon.tex`
74 +exists for this paper (not yet submitted to a journal), so no anonymous PDF was produced.
added docs/REVIEW-REPORT.md +166 −0
@@ -0,0 +1,166 @@
1 +# Editorial-board review — UQO Working Paper No. 4
2 +
3 +**Hedonic Pricing of Short-Term Rental Properties: A Multi-Method Analysis of Airbnb Listing Prices in Quebec**
4 +Version reviewed: 1.0 (May 2026, never audited) → revised version 1.1 (October 2026).
5 +Reference state: git tag `pre-revision-20261017`, `docs/main_pre-revision-20261017.pdf` (28 pages).
6 +Companion document: `docs/CHANGELOG-REVISION.md` (audit trail of every change, references added, scripts run).
7 +
8 +## 1. Summary verdict
9 +
10 +The v1.0 manuscript was not a publishable paper; it was a pipeline report whose text had been written around whatever the
11 +code produced. The code, run on a data set whose fields had been misdescribed, produced numbers that no referee would
12 +accept and several that were not results at all:
13 +
14 +1. **The dependent variable was contaminated.** The displayed price field is bimodal on the log scale (modes near \$150 and
15 + \$2,500; 26.5 % of the 3,456 priced listings above \$1,000). Bedroom by bedroom, listings above \$1,000 are priced 16–19
16 + times those below: the upper mode records the total price of multi-night stays (about 23 nights), concentrated among
17 + small Montreal rental units with few reviews. v1.0 modelled the mixture as if it were a nightly price and obtained
18 + $R^2$ of 0.05–0.27, a "has reviews" coefficient of 9.5 log points, a "bedrooms" premium of +213 % and a Winsorisation
19 + band of \$38–\$10,822 for "nightly" prices.
20 +2. **Five regressors were fabricated or mislabelled.** The "luxury", "business travel", "family comfort", "leisure" and
21 + "remote work" amenity indices were the normalised amenity count plus Gaussian noise (σ = 0.05, `src/amenities.py`,
22 + `_proxy_indices_from_count`); the "business travel index −68.5 %" result is noise. "Entire home / private room / shared
23 + room" were relabelled property-type groups ("Rental unit" → "private room", "Other" → "shared room"); the scrape has
24 + no room type. "Multi-listing host" was a duplicated-title proxy; `host_professional_dummy` was a constant zero.
25 +3. **Several reported analyses had not been executed as described.** The spatial section contained no estimate (spreg was
26 + absent; fallbacks ran and nothing was reported); "CatBoost" and "GAM" were sklearn fallbacks; SHAP was a permutation
27 + importance (no SHAP table or figure was ever produced); MAPE was computed on log prices (the "14.3 %" is meaningless).
28 +4. **The decomposition table was arithmetically impossible** (mean predicted log price 3.99 vs actual 5.87, intercept 0,
29 + location and text components identically 0, residual mean 1.16 for an OLS with intercept): the feature-group keys did not
30 + match the model's blocks.
31 +5. **The design matrix contained exact duplicates** (`is_superhost` = `superhost_flag`, `is_guest_favorite` =
32 + `guest_favorite_flag`, `log_beds` = `log_bedrooms`) and an exhaustive set of "room-type" dummies plus a constant; the
33 + quantile table's three "room-type" coefficients of ≈ 1.0 are pseudo-inverse artefacts. A K-means cluster label was used
34 + as a continuous regressor ("Spatial cluster −1.3 %"). The M8/M9 sample (N = 1,906) was selected on having a priced
35 + neighbour within 500 m.
36 +6. **The data source was misattributed** (Inside Airbnb with amenity lists, host profiles, descriptions, calendars) and the
37 + text referred to "seasons" in a single cross-section.
38 +
39 +The paper has been rebuilt from the data up: the price-regime problem is modelled explicitly (two-regime mixture of hedonic
40 +regressions, EM), the structured card title is parsed to recover the rating, bathrooms, studios and title category, a
41 +parsimonious hedonic specification with city fixed effects is estimated with HC3 and clustered inference, quantile, SAR/SEM/SDM
42 +(with LeSage–Pace impacts) and five learners under random and spatially blocked cross-validation are run for real, and
43 +every number in the text is produced by `scripts/10_revision_reanalysis.py`. The revised paper is an honest, internally
44 +consistent hedonic study of a sparse scrape; its contribution is the Quebec evidence plus the measurement lesson.
45 +
46 +## 2. Section-by-section diagnosis (v1.0 → v1.1)
47 +
48 +| Section | Strengths (v1.0) | Weaknesses / errors found | Action |
49 +|---|---|---|---|
50 +| Abstract | Clear structure | Claims SHAP, CatBoost, spatial models and "amenity indices" that were not estimated/not real; R² 0.052–0.274 on a contaminated variable; "comprehensive" | Rewritten around the regime diagnosis and the verified results |
51 +| 1 Introduction | Rosen–Lancaster framing; four research questions | Literature thin and partly misattributed (Gibbs amenity result cited to the dynamic-pricing paper; Chen & Xie dated 2020; Chattopadhyay & Machemehl 2006 unverifiable; Dogru & Pekin grey literature); "49 features"/"50 parameters"/60 rows in appendix; Quebec gap not established (Deboosere et al. 2019 Montreal absent) | Rewritten; literature enriched (32 verified additions, 3 removals); contribution reframed as evidence + measurement |
52 +| 2 Data | Cleaning steps listed; summary tables | Source misdescribed; bimodality not noticed although mean \$1,115 vs median \$219 and P75 \$1,139 were printed; "0–100 → 0–5 rating conversion" false; "entire home 48.1 %" false; amenity indices fabricated; 810 missing ratings treated as if all in the priced sample; text embeddings of a templated title | New §2: scrape content, title parsing, price-field diagnosis (mixture + regime table + figure), analysis sample, descriptives, data limits |
53 +| 3 Methodology | Equations for OLS, QR, SAR/SEM/SDM, Moran's I | No equation for FE or for the premium correction; reputation score formula ad hoc; Haversine/BallTree detail without purpose; "M9 identical to M8"; random train/test split; MAPE on logs; no impacts | New §3: hedonic equation with FE, Kennedy correction, inference, QR with bootstrap, W on projected km, SAR/SEM/SDM + LR test + impacts, random vs blocked CV, SHAP, mixture model |
54 +| 4 Results | — | Every table affected by items 1–5 above; decomposition impossible; spatial section without numbers; quantile table collinear; "11.1 % per 0.1 rating point" from a coefficient of 1.05 on a 0–5 scale under the contaminated sample | Entirely regenerated: 7 tables, 4 figures, all from one script |
55 +| 5 Robustness | Several dimensions considered | Property-type subsamples labelled "room type"; price-segment regressions condition on the dependent variable; "Ultra-Luxury (> \$1,000)" is the stay regime; adj. R² 0.08–0.10 on a different spec than the main model; "stable" claims without a table | New §5: regime cut-offs, price-rule samples, weighting, hotel exclusion, Montreal/outside, trimming, 60-cell FE, alternative W |
56 +| 6 Conclusion | Lists limitations | Repeats the contaminated magnitudes; admits fallbacks only in passing ("CatBoost, pygam, SHAP, PySAL were unavailable") | Rewritten |
57 +| Appendix | Full coefficient table | 60 rows for "50 covariates", duplicates, pinv artefacts | Variable definitions, regime logit, VIF |
58 +
59 +## 3. Methodology verdicts (master prompt §3)
60 +
61 +| Point | Verdict |
62 +|---|---|
63 +| Specification justified | v1.0: no — 60 regressors incl. duplicates, noise indices, cluster label as continuous. v1.1: parsimonious semi-log with capacity in logs, title category, presentation, reputation, two location variables, city/cell FE; blocks justified in §3.1. |
64 +| Estimation assumptions explicit | v1.1 states the semi-log form, the conditional-association reading, HC3 and clustering, the mixture model's assumptions (common slopes, regime-specific variance, logistic concomitant). |
65 +| Variables correctly defined | v1.0: no (see §1). v1.1: Appendix A lists each variable and its source (field vs title). |
66 +| Fixed effects appropriate | v1.0: none (K-means label as continuous). v1.1: city FE (cities ≥ 15 listings) + 25 cells for the scattered remainder; 60-cell FE as robustness; FE share of SHAP importance reported. |
67 +| Spatial/temporal dependence | v1.0: spatial models not estimated. v1.1: Moran's I on M4/M5 residuals (k = 5, 10), SAR/SEM/SDM by ML on projected-km KNN W, LR test SDM vs SAR, direct/indirect/total impacts with simulated SEs. Temporal: none possible (single cross-section), stated. |
68 +| Standard errors | v1.0: HC3 only. v1.1: HC3 + clustered by FE group (and by 60 cells in the JSON), kernel SEs for QR, bootstrap for inter-quantile differences, simulated SEs for impacts. |
69 +| Sample construction transparent | v1.1: 5,000 → 3,456 priced → mixture classification → 2,480; every step counted; 465 bathroom and 46 bedroom repairs, 456 unrated, 37 truncated ratings documented. |
70 +| Robustness addresses genuine threats | v1.1: the regime classification (cut-offs 0.25/0.75, \$600/\$1,000 rules, weighting, full sample), composition (hotels, Montreal), outliers (trimming), FE granularity, W choice. |
71 +| Coefficient interpretation | v1.1: elasticities for logs, Kennedy-corrected premia for dummies, rating per 0.1 point, impacts for spatial models, SHAP as attribution not effect. |
72 +| Statistical vs economic significance | v1.1 distinguishes precisely estimated small premia (badges) from large ones (capacity, shared bath). |
73 +| Causal claims | None; §3.1 and §6 state the conditional-association reading explicitly. |
74 +
75 +## 4. Literature
76 +
77 +**Removed (unverifiable or inappropriate):** Chattopadhyay & Machemehl (2006, *Transportation*) — no Crossref record for the
78 +cited article; Dogru & Pekin (2017, *Boston Hospitality Review*) — grey literature, no DOI; Apley & Zhu (2020) — not used.
79 +
80 +**Corrected:** Chen & Xie — 2017 (not 2020), IJCHM 29(9); Magno, Cassia & **Ugolini** (2018) — third author was wrong;
81 +Gibbs et al. — the amenity/hedonic result is Gibbs, Guttentag, Gretzel, Morton & Goodwill (2018), *JTTM* 35(1), DOI
82 +10.1080/10548408.2017.1308292, not the dynamic-pricing paper (kept separately as `Gibbs2018dynamic`); Pérez-Sánchez
83 +given name (V. Raúl); Zhang first author (Zhihua).
84 +
85 +**Added (32, all Crossref-verified with DOI unless noted):** Malpezzi 2003 (10.1002/9780470690680.ch5); Sirmans, Macpherson &
86 +Zietz 2005 (10.1080/10835547.2005.12090154); Kuminoff, Parmeter & Pope 2010 (10.1016/j.jeem.2010.06.001); Bishop et al. 2020
87 +(10.1093/reep/reaa001); Teubner, Hawlitschek & Dann 2017 (10.22381/JSME5420173); Ert, Fleischer & Magen 2016
88 +(10.1016/j.tourman.2016.01.013); Zervas, Proserpio & Byers 2017 (10.1509/jmr.15.0204) and 2021 (10.1007/s11002-020-09546-4);
89 +Gyódi & Nawaro 2021 (10.1016/j.tourman.2021.104319); Tong & Gunter 2022 (10.1080/13683500.2020.1718619); Cai et al. 2019
90 +(10.3727/108354219X15525055915554); Sainaghi, Abrate & Mauri 2021 (10.1016/j.ijhm.2020.102709); Voltes-Dorta & Sánchez-Medina
91 +2020 (10.1016/j.jhtm.2020.08.015); Lorde, Jacob & Weekes 2019 (10.1016/j.tmp.2019.03.006); Dudás et al. 2017
92 +(10.15196/RS07108); Kakar et al. 2018 (10.1016/j.jhe.2017.08.001); Ikkala & Lampinen 2015 (10.1145/2675133.2675274);
93 +Guttentag 2015 (10.1080/13683500.2013.827159); Farronato & Fradkin 2022 (10.1257/aer.20180260); Deboosere et al. 2019
94 +(10.1080/21681376.2019.1592699); Combs, Kerrigan & Wachsmuth 2020 (10.36939/cjur/vol29no1/art274); Wachsmuth & Weisler
95 +2018 (10.1177/0308518X18778038); Barron, Kung & Proserpio 2021 (10.1287/mksc.2020.1227); Halvorsen & Palmquist 1980 and
96 +Kennedy 1981 (AER; verified via RePEc records, no DOI); MacKinnon & White 1985 (10.1016/0304-4076(85)90158-7); Cameron &
97 +Miller 2015 (10.3368/jhr.50.2.317); Koenker & Hallock 2001 (10.1257/jep.15.4.143); Elhorst 2010 (10.1080/17421770903541772);
98 +Lundberg et al. 2020 (10.1038/s42256-019-0138-9); Roberts et al. 2017 (10.1111/ecog.02881).
99 +
100 +**Retained and re-verified (18, including the corrected Chen & Xie 2017):** Rosen 1974; Lancaster 1966; Wang & Nicolau 2017; Gibbs et al. 2018 (dynamic); Pérez-Sánchez
101 +et al. 2018; Zhang et al. 2017; Gunter & Önder 2018; Benítez-Aurioles 2018; Magno et al. 2018; Koenker & Bassett 1978;
102 +LeSage & Pace 2009; Anselin 1988; Lundberg & Lee 2017; Breiman 2001; Friedman 2001; Chen & Guestrin 2016; Zou & Hastie 2005.
103 +
104 +References: 21 (v1.0, 2 unverifiable) → 50 (v1.1, all verified).
105 +
106 +## 5. Results: inconsistencies found in v1.0 and what replaces them
107 +
108 +- Abstract/text/README/tables agreed on N = 5,000 / 3,412 / 1,906 and R² 0.052–0.274 but disagreed on the number of
109 + regressors (49 features, 50 parameters, 60 appendix rows); the appendix contained duplicated regressors with split
110 + pseudo-inverse coefficients (`is_superhost` −0.065 vs `superhost_flag` +0.060).
111 +- "Has reviews" β = 9.511 (premium "> 1,000 %") arose because the M4+ samples required a non-missing rating, making the
112 + indicator almost collinear with the constant; the "review component" of the decomposition (mean 6.40) was this artefact.
113 +- The quantile table's "Is entire home / private room / shared room" coefficients of ≈ 1.0 at every τ were the equal split of
114 + the constant across an exhaustive dummy set.
115 +- Spatial section: text claimed "coefficients qualitatively similar … mild spatial bias" without a single number.
116 +- ML: MAPE 14.3 % was |Δ ln p| / ln p; "CatBoost" and "GAM" were sklearn fallbacks; the test set (382) came from one random split.
117 +- Robustness: "adjusted R² 0.083–0.098" referred to a 9-regressor spec, not the 50-regressor main model; price-segment
118 + regressions conditioned on the dependent variable.
119 +
120 +**Replaced by (all verified, `rev_key_numbers.json`):** nightly-regime sample N = 2,480; M1–M5 R² 0.443/0.454/0.461/0.479/0.509;
121 +M5 elasticities guests 0.331 (0.037), ln(1+bathrooms) 0.437 (0.070), bedrooms 0.160 (0.042); shared bath −0.385 (−32 % Kennedy);
122 +studio +0.147; chalet +0.099 (10.3 %), house +0.079 (8.1 %); ln photos 0.087; ln amenities 0.094; rating 0.337/point; Superhost
123 +0.023 n.s.; Guest Favourite −0.035 n.s.; ln reviews 0.015 n.s.; ln density 0.064; ln distance −0.035 (10 %). Clustered SEs
124 +(51 groups) 20–60 % larger for capacity/location. VIF max 4.2. FE-only R² 0.13. Quantiles: pseudo-R² 0.278→0.405; bedrooms
125 +0.014→0.187 (Δ = 0.17, p = 0.08); bathrooms 0.241→0.551; guests 0.374→0.307; ln reviews +0.042→−0.042 (Δ p < 0.001);
126 +Superhost +0.081 at τ = 0.10 only. Moran's I: ln p 0.244, M4 residuals 0.126 (z = 10.8), M5 residuals 0.072 (z = 6.2).
127 +SAR ρ̂ = 0.200 (0.022), SEM λ̂ = 0.284 (0.028), SDM ρ̂ = 0.261 (0.028); LR SDM vs SAR χ²(20) = 52.8; SAR multiplier 1.25;
128 +direct/coefficient ratio 1.006. CV (random | blocked): OLS-M5 0.473 | 0.407; XGBoost 0.559 | 0.483; MdAPE 26–30 %. SHAP shares:
129 +guests 20.9 %, bedrooms 9.8 %, density 8.9 %, FE 8.8 %, bathrooms 8.8 %, reviews 8.6 %, rating 6.6 %.
130 +
131 +## 6. Verified results vs proposed analyses
132 +
133 +Everything reported in v1.1 was executed (`scripts/10_revision_reanalysis.py`, 172 s plus a 6-minute bootstrap cached in
134 +`rev_iq_bootstrap.json`). **Recommended but not executed:** (i) Hartigan dip test of unimodality (package not installed; the
135 +mixture and the median-ratio table make the point); (ii) a concomitant-variable mixture with city fixed effects in the regime
136 +equation; (iii) Conley HAC standard errors (the FE-cluster and 60-cell-cluster SEs are reported instead; `KEY.ols.M5_cluster_cell60`
137 +is in the JSON but not in a table); (iv) a GWR / spatially varying-coefficient model for the Montreal vs resort heterogeneity;
138 +(v) hyper-parameter tuning of the learners by nested CV (fixed, documented settings were used); (vi) SHAP interaction values;
139 +(vii) a hedonic model on the stay-regime listings with the implied stay length as an offset (not identified without stay dates).
140 +
141 +## 7. Remaining limitations
142 +
143 +Asking prices on one day; cleaning fee, room type, host ID, amenity list, minimum stay unobserved; no stay length for the
144 +28 % stay-regime cards (dropped, not corrected); single cross-section (no seasonality despite the v1.0 wording); scrape
145 +coverage; city FE for 54 % of listings only (the rest in 25 cells); the ≤ \$31 winsorisation floor inherited from the WP 5
146 +cleaning affects 35 listings; Montreal sub-sample small (N = 506).
147 +
148 +## 8. Continuity with the research programme
149 +
150 +Terminology aligned with WP 1/9/11 ("hedonic price function", "implicit price", "neighbourhood fixed effects", "out-of-sample",
151 +MdAPE); the WP 5 price-field diagnosis is cited as the companion paper (UQO WP 5) and extended (mixture of regressions instead of
152 +a \$1,000 rule, with the rule shown to bias the capacity elasticity to zero). No paragraph is reused from WP 5.
153 +
154 +## 9. Maturity for publication
155 +
156 +- **Target journals:** *Journal of Housing Economics* (short paper), *Tourism Economics*, *International Journal of Hospitality
157 + Management*, *Journal of Real Estate Research*, *Current Issues in Tourism*; *Regional Science and Urban Economics* only if the
158 + spatial heterogeneity (Montreal vs resort) is developed further.
159 +- **Risks of rejection:** (i) data sparseness (no room type / host ID / amenity list) — a referee may ask for a re-scrape with
160 + these fields; (ii) the stay-price contamination, now modelled, will still invite the question "why not re-scrape with
161 + dates?"; (iii) a single cross-section of asking prices limits the contribution to descriptive hedonics; (iv) the ML section
162 + is a benchmark rather than a method contribution.
163 +- **Verdict:** publishable as a careful descriptive hedonic working paper with a genuine methodological lesson on scraped
164 + prices; before journal submission, a re-scrape recording search dates, stay length, room type and host ID is strongly
165 + recommended, after which the mixture model becomes a validation exercise rather than a necessity. Not yet SSRN-posted;
166 + v1.1 is suitable for posting.
added paper/figures/rev_fig_logprice_mixture.pdf +0 −0

Binary file not shown.

added paper/figures/rev_fig_map.pdf +0 −0

Binary file not shown.

added paper/figures/rev_fig_partials.pdf +0 −0

Binary file not shown.

added paper/figures/rev_fig_price_by_category.pdf +0 −0

Binary file not shown.

added paper/figures/rev_fig_quantile.pdf +0 −0

Binary file not shown.

added paper/figures/rev_fig_shap.pdf +0 −0

Binary file not shown.

modified paper/main.pdf +0 −0

Binary file not shown.

modified paper/main.tex +32 −23
@@ -86,6 +86,7 @@
86 86 % --- Appendix Support ---
87 87 \usepackage{appendix}
88 88 \usepackage{enumitem}
89 +\renewcommand{\theHequation}{\thesection.\arabic{equation}}
89 90
90 91 % --- Graphics Path ---
91 92 \graphicspath{{figures/}}
@@ -104,31 +105,39 @@
104 105 \newcommand{\WPnumber}{4}
105 106 \newcommand{\WPtitle}{Hedonic Pricing of Short-Term Rental Properties: A Multi-Method Analysis of Airbnb Listing Prices in Quebec}
106 107 \newcommand{\WPsubtitle}{}
107 −\newcommand{\WPdate}{May 2026}
108 −\newcommand{\WPversion}{1.0}
108 +\newcommand{\WPdate}{October 2026}
109 +\newcommand{\WPversion}{1.1}
109 110 \newcommand{\WPabstract}{%
110 −This paper develops a comprehensive hedonic pricing model for short-term
111 −rental properties listed on Airbnb across Quebec, Canada. Drawing on
112 −\citet{Rosen1974} and \citet{Lancaster1966}, we decompose nightly prices
113 −into implicit valuations of structural characteristics, amenity bundles,
114 −host attributes, reputation signals, locational factors, and text-derived
115 −features. Our dataset comprises 5,000 listings from Inside Airbnb, of
116 −which 3,412 retain valid prices after cleaning. We employ a layered
117 −econometric strategy: nine nested OLS specifications with HC3 robust
118 −standard errors, progressing from a structural-only model ($R^2 = 0.052$)
119 −to a full specification with spatial controls ($R^2 = 0.274$); quantile
120 −regression at $\tau \in \{0.10, 0.25, 0.50, 0.75, 0.90\}$ revealing
121 −heterogeneity across the price distribution; machine learning
122 −methods---XGBoost ($R^2 = 0.285$), Random Forest, Gradient Boosting,
123 −LightGBM---with SHAP interpretability; and spatial econometric
124 −models---spatial lag, spatial error, and spatial Durbin
125 −specifications---accounting for spatial dependence. Bedrooms, room type,
126 −review scores, spatial context, and amenity indices are the dominant
127 −price determinants, with their relative importance shifting across
128 −quantiles and geographic sub-markets.%
111 +We estimate hedonic price functions for a province-wide cross-section of
112 +Airbnb listings in Quebec, Canada, from a scrape of 5,000 listing cards
113 +collected in early 2026 (3,456 with a displayed price). The displayed
114 +price field is bimodal: about 28\% of priced listings, mostly small
115 +Montreal rental units, show the total price of a stay of roughly three
116 +weeks rather than a nightly rate. A two-regime mixture of hedonic
117 +regressions estimated by EM separates the two populations sharply and
118 +leaves 2,480 nightly prices, on which all estimation is based. A
119 +semi-logarithmic hedonic model with city fixed effects, estimated with
120 +heteroskedasticity-robust and clustered standard errors, explains 51\%
121 +of the variance of log prices. Guest capacity (elasticity 0.33),
122 +bathrooms (0.44) and bedrooms (0.16), a shared bathroom ($-32$\%), the
123 +number of photos, the displayed rating (3.4\% per tenth of a point) and
124 +local listing density are the priced attributes; the Superhost and Guest
125 +Favourite badges carry no premium conditional on capacity, type and
126 +location. Quantile regressions show that cheap listings are priced per
127 +guest and certified by reviews, whereas expensive listings are priced
128 +per room and are cheaper when heavily reviewed. Spatial lag, error and
129 +Durbin models find moderate spatial dependence ($\hat\rho \approx 0.20$,
130 +$\hat\lambda \approx 0.28$) with direct impacts within a few percent of
131 +the OLS coefficients. Gradient-boosting models raise the out-of-sample
132 +$R^2$ from 0.47 to 0.56 under random cross-validation and from 0.41 to
133 +0.48 when whole areas are held out, and their SHAP decomposition ranks
134 +the same attributes as the hedonic model. The paper provides the first
135 +provincial hedonic evidence for Quebec's short-term rental market and a
136 +template for detecting and handling stay-price contamination in scraped
137 +platform prices.%
129 138 }
130 −\newcommand{\WPkeywords}{hedonic pricing, Airbnb, short-term rentals, quantile regression, spatial econometrics, machine learning, SHAP, Quebec, amenity valuation}
131 −\newcommand{\WPjel}{C21, C31, C45, C58, L83, R31, R33}
139 +\newcommand{\WPkeywords}{hedonic price function, short-term rentals, Airbnb, implicit prices, quantile regression, spatial econometrics, machine learning, Quebec}
140 +\newcommand{\WPjel}{C21, C31, C45, L83, R31, Z30}
132 141
133 142 % --- Author ---
134 143 \newcommand{\WPauthor}{Simon-Pierre Boucher}
modified paper/references.bib +412 −101
@@ -1,11 +1,14 @@
1 1 % ==========================================================================
2 −% References for Hedonic Pricing of Airbnb Listings in Quebec
2 +% References -- UQO Working Paper No. 4 (Hedonic Pricing of Short-Term
3 +% Rentals in Quebec). All entries verified against Crossref / publisher
4 +% records on 2026-10-17 (see docs/CHANGELOG-REVISION.md).
3 5 % ==========================================================================
4 6
7 +% ---------------------------- Hedonic theory ------------------------------
8 +
5 9 @article{Rosen1974,
6 10 author = {Rosen, Sherwin},
7 − title = {Hedonic Prices and Implicit Markets: Product Differentiation
8 − in Pure Competition},
11 + title = {Hedonic Prices and Implicit Markets: Product Differentiation in Pure Competition},
9 12 journal = {Journal of Political Economy},
10 13 year = {1974},
11 14 volume = {82},
@@ -25,9 +28,76 @@
25 28 doi = {10.1086/259131}
26 29 }
27 30
31 +@incollection{Malpezzi2003,
32 + author = {Malpezzi, Stephen},
33 + title = {Hedonic Pricing Models: A Selective and Applied Review},
34 + booktitle = {Housing Economics and Public Policy},
35 + editor = {O'Sullivan, Tony and Gibb, Kenneth},
36 + publisher = {Blackwell Science},
37 + address = {Oxford},
38 + year = {2003},
39 + pages = {67--89},
40 + doi = {10.1002/9780470690680.ch5}
41 +}
42 +
43 +@article{Sirmans2005,
44 + author = {Sirmans, G. Stacy and Macpherson, David A. and Zietz, Emily N.},
45 + title = {The Composition of Hedonic Pricing Models},
46 + journal = {Journal of Real Estate Literature},
47 + year = {2005},
48 + volume = {13},
49 + number = {1},
50 + pages = {1--44},
51 + doi = {10.1080/10835547.2005.12090154}
52 +}
53 +
54 +@article{Kuminoff2010,
55 + author = {Kuminoff, Nicolai V. and Parmeter, Christopher F. and Pope, Jaren C.},
56 + title = {Which Hedonic Models Can We Trust to Recover the Marginal Willingness to Pay for Environmental Amenities?},
57 + journal = {Journal of Environmental Economics and Management},
58 + year = {2010},
59 + volume = {60},
60 + number = {3},
61 + pages = {145--160},
62 + doi = {10.1016/j.jeem.2010.06.001}
63 +}
64 +
65 +@article{Bishop2020,
66 + author = {Bishop, Kelly C. and Kuminoff, Nicolai V. and Banzhaf, H. Spencer and Boyle, Kevin J. and von Gravenitz, Kathrine and Pope, Jaren C. and Smith, V. Kerry and Timmins, Christopher D.},
67 + title = {Best Practices for Using Hedonic Property Value Models to Measure Willingness to Pay for Environmental Quality},
68 + journal = {Review of Environmental Economics and Policy},
69 + year = {2020},
70 + volume = {14},
71 + number = {2},
72 + pages = {260--281},
73 + doi = {10.1093/reep/reaa001}
74 +}
75 +
76 +% --------------------------- Airbnb pricing -------------------------------
77 +
78 +@article{WangNicolau2017,
79 + author = {Wang, Dan and Nicolau, Juan L.},
80 + title = {Price Determinants of Sharing Economy Based Accommodation Rental: A Study of Listings from 33 Cities on {Airbnb.com}},
81 + journal = {International Journal of Hospitality Management},
82 + year = {2017},
83 + volume = {62},
84 + pages = {120--131},
85 + doi = {10.1016/j.ijhm.2016.12.007}
86 +}
87 +
28 88 @article{Gibbs2018,
29 − author = {Gibbs, Chris and Guttentag, Daniel and Gretzel, Ulrike and
30 − Yao, Lan and Morton, Jym},
89 + author = {Gibbs, Chris and Guttentag, Daniel and Gretzel, Ulrike and Morton, Jym and Goodwill, Alasdair},
90 + title = {Pricing in the Sharing Economy: A Hedonic Pricing Model Applied to {Airbnb} Listings},
91 + journal = {Journal of Travel \& Tourism Marketing},
92 + year = {2018},
93 + volume = {35},
94 + number = {1},
95 + pages = {46--56},
96 + doi = {10.1080/10548408.2017.1308292}
97 +}
98 +
99 +@article{Gibbs2018dynamic,
100 + author = {Gibbs, Chris and Guttentag, Daniel and Gretzel, Ulrike and Yao, Lan and Morton, Jym},
31 101 title = {Use of Dynamic Pricing Strategies by {Airbnb} Hosts},
32 102 journal = {International Journal of Contemporary Hospitality Management},
33 103 year = {2018},
@@ -37,20 +107,62 @@
37 107 doi = {10.1108/IJCHM-09-2016-0540}
38 108 }
39 109
40 −@article{WangNicolau2017,
41 − author = {Wang, Dan and Nicolau, Juan Luis},
42 − title = {Price Determinants of Sharing Economy Based Accommodation
43 − Rental: A Study of Listings from 33 Cities on {Airbnb.com}},
44 − journal = {International Journal of Hospitality Management},
110 +@article{ChenXie2017,
111 + author = {Chen, Yong and Xie, Karen},
112 + title = {Consumer Valuation of {Airbnb} Listings: A Hedonic Pricing Approach},
113 + journal = {International Journal of Contemporary Hospitality Management},
45 114 year = {2017},
46 − volume = {62},
47 − pages = {120--131},
48 − doi = {10.1016/j.ijhm.2016.12.007}
115 + volume = {29},
116 + number = {9},
117 + pages = {2405--2424},
118 + doi = {10.1108/IJCHM-10-2016-0606}
119 +}
120 +
121 +@article{Teubner2017,
122 + author = {Teubner, Timm and Hawlitschek, Florian and Dann, David},
123 + title = {Price Determinants on {Airbnb}: How Reputation Pays Off in the Sharing Economy},
124 + journal = {Journal of Self-Governance and Management Economics},
125 + year = {2017},
126 + volume = {5},
127 + number = {4},
128 + pages = {53--80},
129 + doi = {10.22381/JSME5420173}
130 +}
131 +
132 +@article{Ert2016,
133 + author = {Ert, Eyal and Fleischer, Aliza and Magen, Nathan},
134 + title = {Trust and Reputation in the Sharing Economy: The Role of Personal Photos in {Airbnb}},
135 + journal = {Tourism Management},
136 + year = {2016},
137 + volume = {55},
138 + pages = {62--73},
139 + doi = {10.1016/j.tourman.2016.01.013}
140 +}
141 +
142 +@article{Zervas2017,
143 + author = {Zervas, Georgios and Proserpio, Davide and Byers, John W.},
144 + title = {The Rise of the Sharing Economy: Estimating the Impact of {Airbnb} on the Hotel Industry},
145 + journal = {Journal of Marketing Research},
146 + year = {2017},
147 + volume = {54},
148 + number = {5},
149 + pages = {687--705},
150 + doi = {10.1509/jmr.15.0204}
151 +}
152 +
153 +@article{Zervas2021,
154 + author = {Zervas, Georgios and Proserpio, Davide and Byers, John W.},
155 + title = {A First Look at Online Reputation on {Airbnb}, Where Every Stay Is Above Average},
156 + journal = {Marketing Letters},
157 + year = {2021},
158 + volume = {32},
159 + number = {1},
160 + pages = {1--16},
161 + doi = {10.1007/s11002-020-09546-4}
49 162 }
50 163
51 164 @article{PerezSanchez2018,
52 − author = {P{\'e}rez-S{\'a}nchez, V. Rosa and Serrano-Estrada, Leticia
53 − and Marti, Pablo and Mora-Garcia, Raul-Tomas},
165 + author = {P{\'e}rez-S{\'a}nchez, V. Raul and Serrano-Estrada, Leticia and Marti, Pablo and Mora-Garcia, Raul-Tomas},
54 166 title = {The What, Where, and Why of {Airbnb} Price Determinants},
55 167 journal = {Sustainability},
56 168 year = {2018},
@@ -61,10 +173,8 @@
61 173 }
62 174
63 175 @article{Zhang2017,
64 − author = {Zhang, Ziqiong and Chen, Rachel J. C. and Han, Lee D. and
65 − Yang, Lu},
66 − title = {Key Factors Affecting the Price of {Airbnb} Listings:
67 − A Geographically Weighted Approach},
176 + author = {Zhang, Zhihua and Chen, Rachel J. C. and Han, Lee D. and Yang, Lu},
177 + title = {Key Factors Affecting the Price of {Airbnb} Listings: A Geographically Weighted Approach},
68 178 journal = {Sustainability},
69 179 year = {2017},
70 180 volume = {9},
@@ -73,33 +183,103 @@
73 183 doi = {10.3390/su9091635}
74 184 }
75 185
76 −@article{ChattopadhyayMachemehl2006,
77 − author = {Chattopadhyay, Sudip and Machemehl, Randy B.},
78 − title = {Estimating the Marginal Willingness to Pay for a
79 − Transportation Improvement Using Hedonic Pricing},
80 − journal = {Transportation},
81 − year = {2006},
82 − volume = {33},
83 − number = {5},
84 − pages = {491--510}
186 +@article{Gyodi2021,
187 + author = {Gy{\'o}di, Krist{\'o}f and Nawaro, {\L}ukasz},
188 + title = {Determinants of {Airbnb} Prices in {European} Cities: A Spatial Econometrics Approach},
189 + journal = {Tourism Management},
190 + year = {2021},
191 + volume = {86},
192 + pages = {104319},
193 + doi = {10.1016/j.tourman.2021.104319}
85 194 }
86 195
87 −@article{Chen2020,
88 − author = {Chen, Yong and Xie, Karen L.},
89 − title = {Consumer Valuation of {Airbnb} Listings: A Hedonic Pricing
90 − Approach},
91 − journal = {International Journal of Contemporary Hospitality Management},
196 +@article{TongGunter2022,
197 + author = {Tong, Baldwin and Gunter, Ulrich},
198 + title = {Hedonic Pricing and the Sharing Economy: How Profile Characteristics Affect {Airbnb} Accommodation Prices in {Barcelona}, {Madrid}, and {Seville}},
199 + journal = {Current Issues in Tourism},
200 + year = {2022},
201 + volume = {25},
202 + number = {20},
203 + pages = {3309--3328},
204 + doi = {10.1080/13683500.2020.1718619}
205 +}
206 +
207 +@article{Cai2019,
208 + author = {Cai, Yuan and Zhou, Yongbo and Ma, Jianyu and Scott, Noel},
209 + title = {Price Determinants of {Airbnb} Listings: Evidence from {Hong Kong}},
210 + journal = {Tourism Analysis},
211 + year = {2019},
212 + volume = {24},
213 + number = {2},
214 + pages = {227--242},
215 + doi = {10.3727/108354219X15525055915554}
216 +}
217 +
218 +@article{Sainaghi2021,
219 + author = {Sainaghi, Ruggero and Abrate, Graziano and Mauri, Aurelio},
220 + title = {Price and {RevPAR} Determinants of {Airbnb} Listings: Convergent and Divergent Evidence},
221 + journal = {International Journal of Hospitality Management},
222 + year = {2021},
223 + volume = {92},
224 + pages = {102709},
225 + doi = {10.1016/j.ijhm.2020.102709}
226 +}
227 +
228 +@article{VoltesDorta2020,
229 + author = {Voltes-Dorta, Augusto and S{\'a}nchez-Medina, Agust{\'\i}n},
230 + title = {Drivers of {Airbnb} Prices According to Property/Room Type, Season and Location: A Regression Approach},
231 + journal = {Journal of Hospitality and Tourism Management},
92 232 year = {2020},
93 − volume = {29},
94 − number = {9},
95 − pages = {2405--2424},
96 − doi = {10.1108/IJCHM-10-2016-0606}
233 + volume = {45},
234 + pages = {266--275},
235 + doi = {10.1016/j.jhtm.2020.08.015}
236 +}
237 +
238 +@article{Lorde2019,
239 + author = {Lorde, Troy and Jacob, Jadon and Weekes, Quinn},
240 + title = {Price-Setting Behavior in a Tourism Sharing Economy Accommodation Market: A Hedonic Price Analysis of {AirBnB} Hosts in the {Caribbean}},
241 + journal = {Tourism Management Perspectives},
242 + year = {2019},
243 + volume = {30},
244 + pages = {251--261},
245 + doi = {10.1016/j.tmp.2019.03.006}
246 +}
247 +
248 +@article{Dudas2017,
249 + author = {Dud{\'a}s, G{\'a}bor and Vida, Gy{\"o}rgy and Kovalcsik, Tam{\'a}s and Boros, Lajos},
250 + title = {A Socio-Economic Analysis of {Airbnb} in {New York City}},
251 + journal = {Regional Statistics},
252 + year = {2017},
253 + volume = {7},
254 + number = {1},
255 + pages = {135--151},
256 + doi = {10.15196/RS07108}
257 +}
258 +
259 +@article{BenitezAurioles2018,
260 + author = {Ben{\'\i}tez-Aurioles, Beatriz},
261 + title = {Why Are Flexible Booking Policies Priced Negatively?},
262 + journal = {Tourism Management},
263 + year = {2018},
264 + volume = {67},
265 + pages = {312--325},
266 + doi = {10.1016/j.tourman.2018.02.008}
267 +}
268 +
269 +@article{Magno2018,
270 + author = {Magno, Francesca and Cassia, Fabio and Ugolini, Marta Maria},
271 + title = {Accommodation Prices on {Airbnb}: Effects of Host Experience and Market Demand},
272 + journal = {The TQM Journal},
273 + year = {2018},
274 + volume = {30},
275 + number = {5},
276 + pages = {608--620},
277 + doi = {10.1108/TQM-12-2017-0164}
97 278 }
98 279
99 280 @article{GunterOnder2018,
100 281 author = {Gunter, Ulrich and {\"O}nder, Irem},
101 − title = {Determinants of {Airbnb} Demand in {Vienna} and Their
102 − Implications for the Traditional Accommodation Industry},
282 + title = {Determinants of {Airbnb} Demand in {Vienna} and Their Implications for the Traditional Accommodation Industry},
103 283 journal = {Tourism Economics},
104 284 year = {2018},
105 285 volume = {24},
@@ -108,10 +288,163 @@
108 288 doi = {10.1177/1354816617731196}
109 289 }
110 290
291 +@article{Kakar2018,
292 + author = {Kakar, Venoo and Voelz, Julisa and Wu, Julia and Franco, Joel},
293 + title = {The Visible Host: Does Race Guide {Airbnb} Rental Rates in {San Francisco}?},
294 + journal = {Journal of Housing Economics},
295 + year = {2018},
296 + volume = {40},
297 + pages = {25--40},
298 + doi = {10.1016/j.jhe.2017.08.001}
299 +}
300 +
301 +@inproceedings{IkkalaLampinen2015,
302 + author = {Ikkala, Tapio and Lampinen, Airi},
303 + title = {Monetizing Network Hospitality: Hospitality and Sociability in the Context of {Airbnb}},
304 + booktitle = {Proceedings of the 18th ACM Conference on Computer Supported Cooperative Work \& Social Computing (CSCW '15)},
305 + year = {2015},
306 + pages = {1033--1044},
307 + doi = {10.1145/2675133.2675274}
308 +}
309 +
310 +@article{Guttentag2015,
311 + author = {Guttentag, Daniel},
312 + title = {{Airbnb}: Disruptive Innovation and the Rise of an Informal Tourism Accommodation Sector},
313 + journal = {Current Issues in Tourism},
314 + year = {2015},
315 + volume = {18},
316 + number = {12},
317 + pages = {1192--1217},
318 + doi = {10.1080/13683500.2013.827159}
319 +}
320 +
321 +@article{FarronatoFradkin2022,
322 + author = {Farronato, Chiara and Fradkin, Andrey},
323 + title = {The Welfare Effects of Peer Entry: The Case of {Airbnb} and the Accommodation Industry},
324 + journal = {American Economic Review},
325 + year = {2022},
326 + volume = {112},
327 + number = {6},
328 + pages = {1782--1817},
329 + doi = {10.1257/aer.20180260}
330 +}
331 +
332 +% ------------------------ Canadian / Quebec STR evidence --------------------
333 +
334 +@article{Deboosere2019,
335 + author = {Deboosere, Robbin and Kerrigan, Danielle Jane and Wachsmuth, David and El-Geneidy, Ahmed},
336 + title = {Location, Location and Professionalization: A Multilevel Hedonic Analysis of {Airbnb} Listing Prices and Revenue},
337 + journal = {Regional Studies, Regional Science},
338 + year = {2019},
339 + volume = {6},
340 + number = {1},
341 + pages = {143--156},
342 + doi = {10.1080/21681376.2019.1592699}
343 +}
344 +
345 +@article{Combs2020,
346 + author = {Combs, Jennifer and Kerrigan, Danielle and Wachsmuth, David},
347 + title = {Short-Term Rentals in {Canada}: Uneven Growth, Uneven Impacts},
348 + journal = {Canadian Journal of Urban Research},
349 + year = {2020},
350 + volume = {29},
351 + number = {1},
352 + pages = {119--135},
353 + doi = {10.36939/cjur/vol29no1/art274}
354 +}
355 +
356 +@article{WachsmuthWeisler2018,
357 + author = {Wachsmuth, David and Weisler, Alexander},
358 + title = {{Airbnb} and the Rent Gap: Gentrification Through the Sharing Economy},
359 + journal = {Environment and Planning A: Economy and Space},
360 + year = {2018},
361 + volume = {50},
362 + number = {6},
363 + pages = {1147--1170},
364 + doi = {10.1177/0308518X18778038}
365 +}
366 +
367 +@article{Barron2021,
368 + author = {Barron, Kyle and Kung, Edward and Proserpio, Davide},
369 + title = {The Effect of Home-Sharing on House Prices and Rents: Evidence from {Airbnb}},
370 + journal = {Marketing Science},
371 + year = {2021},
372 + volume = {40},
373 + number = {1},
374 + pages = {23--47},
375 + doi = {10.1287/mksc.2020.1227}
376 +}
377 +
378 +% ------------------------------ Econometrics -------------------------------
379 +
380 +@article{HalvorsenPalmquist1980,
381 + author = {Halvorsen, Robert and Palmquist, Raymond},
382 + title = {The Interpretation of Dummy Variables in Semilogarithmic Equations},
383 + journal = {American Economic Review},
384 + year = {1980},
385 + volume = {70},
386 + number = {3},
387 + pages = {474--475}
388 +}
389 +
390 +@article{Kennedy1981,
391 + author = {Kennedy, Peter E.},
392 + title = {Estimation with Correctly Interpreted Dummy Variables in Semilogarithmic Equations},
393 + journal = {American Economic Review},
394 + year = {1981},
395 + volume = {71},
396 + number = {4},
397 + pages = {801}
398 +}
399 +
400 +@article{MacKinnonWhite1985,
401 + author = {MacKinnon, James G. and White, Halbert},
402 + title = {Some Heteroskedasticity-Consistent Covariance Matrix Estimators with Improved Finite Sample Properties},
403 + journal = {Journal of Econometrics},
404 + year = {1985},
405 + volume = {29},
406 + number = {3},
407 + pages = {305--325},
408 + doi = {10.1016/0304-4076(85)90158-7}
409 +}
410 +
411 +@article{CameronMiller2015,
412 + author = {Cameron, A. Colin and Miller, Douglas L.},
413 + title = {A Practitioner's Guide to Cluster-Robust Inference},
414 + journal = {Journal of Human Resources},
415 + year = {2015},
416 + volume = {50},
417 + number = {2},
418 + pages = {317--372},
419 + doi = {10.3368/jhr.50.2.317}
420 +}
421 +
422 +@article{KoenkerBassett1978,
423 + author = {Koenker, Roger and Bassett, Gilbert},
424 + title = {Regression Quantiles},
425 + journal = {Econometrica},
426 + year = {1978},
427 + volume = {46},
428 + number = {1},
429 + pages = {33--50},
430 + doi = {10.2307/1913643}
431 +}
432 +
433 +@article{KoenkerHallock2001,
434 + author = {Koenker, Roger and Hallock, Kevin F.},
435 + title = {Quantile Regression},
436 + journal = {Journal of Economic Perspectives},
437 + year = {2001},
438 + volume = {15},
439 + number = {4},
440 + pages = {143--156},
441 + doi = {10.1257/jep.15.4.143}
442 +}
443 +
111 444 @book{LeSagePace2009,
112 445 author = {LeSage, James P. and Pace, R. Kelley},
113 446 title = {Introduction to Spatial Econometrics},
114 − publisher = {CRC Press / Taylor \& Francis},
447 + publisher = {CRC Press},
115 448 year = {2009},
116 449 address = {Boca Raton, FL}
117 450 }
@@ -124,13 +457,48 @@
124 457 address = {Dordrecht}
125 458 }
126 459
460 +@article{Elhorst2010,
461 + author = {Elhorst, J. Paul},
462 + title = {Applied Spatial Econometrics: Raising the Bar},
463 + journal = {Spatial Economic Analysis},
464 + year = {2010},
465 + volume = {5},
466 + number = {1},
467 + pages = {9--28},
468 + doi = {10.1080/17421770903541772}
469 +}
470 +
471 +% ------------------------- Machine learning -------------------------------
472 +
127 473 @inproceedings{Lundberg2017,
128 474 author = {Lundberg, Scott M. and Lee, Su-In},
129 475 title = {A Unified Approach to Interpreting Model Predictions},
130 − booktitle = {Advances in Neural Information Processing Systems 30
131 − ({NIPS} 2017)},
476 + booktitle = {Advances in Neural Information Processing Systems 30 (NIPS 2017)},
132 477 year = {2017},
133 − pages = {4765--4774}
478 + pages = {4765--4774},
479 + address = {Long Beach, CA}
480 +}
481 +
482 +@article{Lundberg2020,
483 + author = {Lundberg, Scott M. and Erion, Gabriel and Chen, Hugh and DeGrave, Alex and Prutkin, Jordan M. and Nair, Bala and Katz, Ronit and Himmelfarb, Jonathan and Bansal, Nisha and Lee, Su-In},
484 + title = {From Local Explanations to Global Understanding with Explainable {AI} for Trees},
485 + journal = {Nature Machine Intelligence},
486 + year = {2020},
487 + volume = {2},
488 + number = {1},
489 + pages = {56--67},
490 + doi = {10.1038/s42256-019-0138-9}
491 +}
492 +
493 +@article{Roberts2017,
494 + author = {Roberts, David R. and Bahn, Volker and Ciuti, Simone and Boyce, Mark S. and Elith, Jane and Guillera-Arroita, Gurutzeta and Hauenstein, Severin and Lahoz-Monfort, Jos{\'e} J. and Schr{\"o}der, Boris and Thuiller, Wilfried and Warton, David I. and Wintle, Brendan A. and Hartig, Florian and Dormann, Carsten F.},
495 + title = {Cross-Validation Strategies for Data with Temporal, Spatial, Hierarchical, or Phylogenetic Structure},
496 + journal = {Ecography},
497 + year = {2017},
498 + volume = {40},
499 + number = {8},
500 + pages = {913--929},
501 + doi = {10.1111/ecog.02881}
134 502 }
135 503
136 504 @article{Breiman2001,
@@ -144,50 +512,6 @@
144 512 doi = {10.1023/A:1010933404324}
145 513 }
146 514
147 −@article{KoenkerBassett1978,
148 − author = {Koenker, Roger and Bassett, Gilbert},
149 − title = {Regression Quantiles},
150 − journal = {Econometrica},
151 − year = {1978},
152 − volume = {46},
153 − number = {1},
154 − pages = {33--50},
155 − doi = {10.2307/1913643}
156 −}
157 −
158 −@article{BenitezAurioles2018,
159 − author = {Ben{\'\i}tez-Aurioles, Beatriz},
160 − title = {Why Are Flexible Booking Policies Priced Negatively?},
161 − journal = {Tourism Management},
162 − year = {2018},
163 − volume = {67},
164 − pages = {312--325},
165 − doi = {10.1016/j.tourman.2018.02.008}
166 −}
167 −
168 −@article{Dogru2017,
169 − author = {Dogru, Tarik and Pekin, Osman},
170 − title = {What Do Guests Value Most in {Airbnb} Accommodations?
171 − An Application of the Hedonic Pricing Approach},
172 − journal = {Boston Hospitality Review},
173 − year = {2017},
174 − volume = {5},
175 − number = {2},
176 − pages = {1--13}
177 −}
178 −
179 −@article{Magno2018,
180 − author = {Magno, Francesca and Cassia, Fabio and Bruni, Attilio},
181 − title = {Accommodation Prices on {Airbnb}: Effects of Host Experience
182 − and Market Demand},
183 − journal = {The TQM Journal},
184 − year = {2018},
185 − volume = {30},
186 − number = {5},
187 − pages = {608--620},
188 − doi = {10.1108/TQM-12-2017-0164}
189 −}
190 −
191 515 @article{Friedman2001,
192 516 author = {Friedman, Jerome H.},
193 517 title = {Greedy Function Approximation: A Gradient Boosting Machine},
@@ -202,8 +526,7 @@
202 526 @inproceedings{ChenGuestrin2016,
203 527 author = {Chen, Tianqi and Guestrin, Carlos},
204 528 title = {{XGBoost}: A Scalable Tree Boosting System},
205 − booktitle = {Proceedings of the 22nd ACM SIGKDD International Conference
206 − on Knowledge Discovery and Data Mining},
529 + booktitle = {Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining},
207 530 year = {2016},
208 531 pages = {785--794},
209 532 doi = {10.1145/2939672.2939785}
@@ -219,15 +542,3 @@
219 542 pages = {301--320},
220 543 doi = {10.1111/j.1467-9868.2005.00503.x}
221 544 }
222 −
223 −@article{ApleyZhu2020,
224 − author = {Apley, Daniel W. and Zhu, Jingyu},
225 − title = {Visualizing the Effects of Predictor Variables in Black Box
226 − Supervised Learning Models},
227 − journal = {Journal of the Royal Statistical Society: Series B},
228 − year = {2020},
229 − volume = {82},
230 − number = {4},
231 − pages = {1059--1086},
232 − doi = {10.1111/rssb.12377}
233 −}
modified paper/sections/appendix.tex +85 −87
@@ -1,109 +1,107 @@
1 1 % ==========================================================================
2 −\section{Additional Regression Results}
3 −\label{sec:app_tables}
2 +\section{Variable Definitions}
3 +\label{sec:app_variables}
4 4 % ==========================================================================
5 5
6 −Table~\ref{tab:app_full_reg} reports the complete set of coefficient
7 −estimates from the full hedonic model (M9) discussed in
8 −Section~\ref{subsec:full_model}. All 50 covariates are shown with
9 −HC3 robust standard errors.
6 +Table~\ref{tab:app_variables} defines every variable used in the paper
7 +and indicates whether it comes from a structured field of the scrape or
8 +is parsed from the card title.
10 9
11 10 \begin{table}[!htbp]
12 11 \centering
13 −\caption{Full Hedonic Model: Complete Coefficient Estimates (M9)}
14 −\label{tab:app_full_reg}
12 +\caption{Variable Definitions}
13 +\label{tab:app_variables}
15 14 \begin{threeparttable}
16 15 \small
17 −\begin{tabular}{lrrr}
16 +\begin{tabular}{p{4.1cm}p{8.3cm}l}
18 17 \toprule
19 −Variable & Coeff. & Std.\ Err. & $p$-value \\
18 +Variable & Definition & Source \\
20 19 \midrule
21 −\multicolumn{4}{l}{\textit{Structural characteristics}} \\
22 −Bedrooms & 1.141*** & (0.346) & 0.001 \\
23 −Bathrooms & $-$0.068 & (0.177) & 0.699 \\
24 −Guests count & 0.046 & (0.064) & 0.476 \\
25 −Log accommodates & $-$0.192 & (0.343) & 0.576 \\
26 −Log bedrooms & $-$2.053*** & (0.770) & 0.008 \\
27 −Log bathrooms & 0.273 & (0.212) & 0.199 \\
28 −Bathrooms/guest & $-$0.033 & (0.421) & 0.938 \\
29 −Bedrooms/guest & 0.399 & (0.349) & 0.253 \\
30 −Is entire home & 0.221 & (0.178) & 0.215 \\
31 −Is private room & 0.285 & (0.188) & 0.130 \\
32 −Is shared room & 0.181 & (0.215) & 0.401 \\
33 −Large capacity & 0.037 & (0.150) & 0.805 \\
34 −Accommodates sq. & $-$0.001 & (0.005) & 0.793 \\
35 −Bedrooms sq. & $-$0.063*** & (0.020) & 0.002 \\
36 −Bathrooms sq. & 0.028** & (0.013) & 0.035 \\
37 −Accommodates $\times$ bedrooms & $-$0.010 & (0.013) & 0.432 \\
38 −Accommodates $\times$ bathrooms & 0.011 & (0.010) & 0.248 \\
20 +\multicolumn{3}{l}{\textit{Dependent variable}} \\
21 +$\ln p$ & Natural log of the displayed price (CAD), winsorised at the 1st/99th percentiles of the priced sample & field \\
39 22 \midrule
40 −\multicolumn{4}{l}{\textit{Amenity indices}} \\
41 −Amenities count & $-$0.002 & (0.003) & 0.491 \\
42 −Amenity richness & $-$0.269** & (0.106) & 0.011 \\
43 −Luxury index & 0.061 & (0.273) & 0.824 \\
44 −Business travel & $-$1.156** & (0.558) & 0.039 \\
45 −Family comfort & 0.316 & (0.274) & 0.249 \\
46 −Leisure index & 0.093 & (0.274) & 0.734 \\
47 −Remote work & 0.584 & (0.478) & 0.222 \\
48 −Pets allowed & 0.036 & (0.079) & 0.647 \\
23 +\multicolumn{3}{l}{\textit{Structural}} \\
24 +$\ln$ bedrooms & Log of the bedroom count; studios recoded to one & field, title \\
25 +$\ln(1+\text{bathrooms})$ & Log of one plus the bathroom count; zeros repaired from the title; half bath $= 0.5$ & field, title \\
26 +$\ln$ guests & Log of the guest capacity (minimum one) & field \\
27 +Shared bathroom & 1 if the title reads ``shared bath'' & title \\
28 +Studio & 1 if the title reads ``Studio'' & title \\
29 +Title category & Six classes of the 44 host-chosen labels (reference: Rental unit) & title \\
49 30 \midrule
50 −\multicolumn{4}{l}{\textit{Host attributes}} \\
51 −Is Superhost & $-$0.065 & (0.079) & 0.410 \\
52 −Superhost flag & 0.060 & (0.126) & 0.636 \\
53 −Multi-listing host & $-$0.043 & (0.071) & 0.548 \\
54 −Superhost $\times$ entire home & 0.007 & (0.099) & 0.946 \\
55 −Guest Favorite flag & 0.048 & (0.092) & 0.602 \\
56 −Is Guest Favorite & $-$0.026 & (0.099) & 0.793 \\
31 +\multicolumn{3}{l}{\textit{Presentation}} \\
32 +$\ln(1+\text{amenities})$ & Log of one plus the number of amenities listed & field \\
33 +$\ln(1+\text{photos})$ & Log of one plus the number of photos & field \\
34 +Pets allowed & 1 if pets are allowed & field \\
57 35 \midrule
58 −\multicolumn{4}{l}{\textit{Reviews and reputation}} \\
59 −Rating & 1.052** & (0.495) & 0.033 \\
60 −Num.\ reviews & 0.003*** & (0.001) & 0.008 \\
61 −Log reviews & $-$0.400*** & (0.102) & 0.000 \\
62 −Review quality & 0.010 & (0.047) & 0.833 \\
63 −Reputation score & $-$0.181 & (0.409) & 0.658 \\
64 −Cleanliness premium & $-$0.036 & (0.079) & 0.647 \\
65 −Location rating premium & 0.062 & (0.076) & 0.415 \\
66 −Has reviews & 9.511** & (3.741) & 0.011 \\
67 −Quality score & 0.002 & (0.001) & 0.211 \\
68 −Num.\ images & $-$0.003 & (0.002) & 0.112 \\
69 −No rating flag & $-$0.038 & (0.131) & 0.772 \\
36 +\multicolumn{3}{l}{\textit{Host and reputation}} \\
37 +Superhost & 1 if the host holds the Superhost badge & field \\
38 +Guest Favourite & 1 if the listing holds the Guest Favourite badge & field \\
39 +$\ln(1+\text{reviews})$ & Log of one plus the number of reviews & field \\
40 +Rated & 1 if a star rating is displayed (0 for ``New'' and unrated cards) & title \\
41 +Rating $-$ 4.8 & Displayed rating minus 4.8, set to zero for unrated listings & title \\
70 42 \midrule
71 −\multicolumn{4}{l}{\textit{Location}} \\
72 −Distance to centre & $-$0.000 & (0.000) & 0.636 \\
73 −Latitude & $-$0.090** & (0.045) & 0.048 \\
74 −Longitude & $-$0.014 & (0.018) & 0.442 \\
43 +\multicolumn{3}{l}{\textit{Location}} \\
44 +$\ln(1+\text{km to centre})$ & Log of one plus the great-circle distance (km) to the nearest of 22 reference municipalities & coordinates \\
45 +$\ln(1+\text{listings within 1 km})$ & Log of one plus the number of other priced listings within 1~km & coordinates \\
46 +Montreal & 1 if the municipality is Montreal & field \\
47 +City / cell fixed effects & Indicator for the municipality (if $\geq 15$ listings) or for one of 25 $k$-means cells of the remaining listings & field, coordinates \\
75 48 \midrule
76 −\multicolumn{4}{l}{\textit{Spatial controls}} \\
77 −Local density 500m & $-$0.008*** & (0.003) & 0.008 \\
78 −Local density 1km & 0.003*** & (0.001) & 0.006 \\
79 −Local avg.\ price 500m & 0.00025*** & (0.00007) & 0.000 \\
80 −Local avg.\ price 1km & $-$0.00003 & (0.00005) & 0.582 \\
81 −Spatial cluster & $-$0.013*** & (0.005) & 0.008 \\
82 −\midrule
83 −\multicolumn{4}{l}{\textit{Text features}} \\
84 −Title length & 0.001 & (0.002) & 0.543 \\
85 −Title word count & $-$0.004 & (0.014) & 0.767 \\
86 −Luxury language & 0.014 & (0.037) & 0.710 \\
87 −Cozy language & 0.004 & (0.036) & 0.919 \\
88 −Professional tone & $-$0.009 & (0.029) & 0.754 \\
89 −Tourism language & 0.004 & (0.020) & 0.853 \\
90 −Text embed.\ 0 & 2.800*** & (0.647) & 0.000 \\
91 −Text embed.\ 1 & 0.356 & (0.583) & 0.541 \\
92 −Text embed.\ 2 & 0.161 & (0.468) & 0.731 \\
93 −Text embed.\ 3 & 0.155 & (0.547) & 0.777 \\
94 −\midrule
95 −Observations & \multicolumn{3}{c}{1,906} \\
96 −$R^2$ & \multicolumn{3}{c}{0.274} \\
97 −Adj.\ $R^2$ & \multicolumn{3}{c}{0.254} \\
98 −AIC & \multicolumn{3}{c}{6,103} \\
49 +\multicolumn{3}{l}{\textit{Regime classification}} \\
50 +$\hat p_i$ & Posterior probability of the stay-price regime from Equation~\eqref{eq:mixture} & estimated \\
99 51 \bottomrule
100 52 \end{tabular}
101 53 \begin{tablenotes}
102 54 \footnotesize
103 −\item \textit{Notes:} OLS estimates with HC3 heteroskedasticity-robust
104 −standard errors in parentheses. ***, **, and * indicate statistical
105 −significance at the 1\%, 5\%, and 10\% levels, respectively. The
106 −dependent variable is $\ln(\text{price})$.
55 +\item \textit{Notes:} ``Field'' denotes a structured field of the
56 +scrape; ``title'' denotes a value parsed from the listing-card title.
57 +The scraper's price category, rating category and composite quality
58 +score are not used.
59 +\end{tablenotes}
60 +\end{threeparttable}
61 +\end{table}
62 +
63 +% ==========================================================================
64 +\section{Additional Results}
65 +\label{sec:app_results}
66 +% ==========================================================================
67 +
68 +Table~\ref{tab:app_stay_logit} reports a logistic regression of the
69 +mixture classification on listing characteristics, estimated on the full
70 +priced sample, which describes the profile of listings whose displayed
71 +price is a stay price. Table~\ref{tab:app_vif} reports variance inflation
72 +factors for the M4 regressors.
73 +
74 +\begin{table}[!htbp]
75 +\centering
76 +\caption{Which Listings Display a Stay Price? Logistic Regression of the Regime Classification}
77 +\label{tab:app_stay_logit}
78 +\begin{threeparttable}
79 +\small
80 +\input{../results/tables/rev_stay_logit.tex}
81 +\begin{tablenotes}
82 +\footnotesize
83 +\item \textit{Notes:} Dependent variable: 1 if the listing is classified
84 +in the stay regime ($\hat p_i \geq 0.5$). Robust (HC1) standard errors.
85 +Average marginal effects are averaged over the sample. Reference title
86 +category: Rental unit. ***, ** and * denote significance at the 1, 5 and
87 +10\% levels.
88 +\end{tablenotes}
89 +\end{threeparttable}
90 +\end{table}
91 +
92 +\begin{table}[!htbp]
93 +\centering
94 +\caption{Variance Inflation Factors, Specification M4}
95 +\label{tab:app_vif}
96 +\begin{threeparttable}
97 +\small
98 +\input{../results/tables/rev_vif.tex}
99 +\begin{tablenotes}
100 +\footnotesize
101 +\item \textit{Notes:} Variance inflation factors computed on the M4
102 +design matrix (analysis sample, $N = 2{,}480$). Values below 5 indicate
103 +that collinearity among the capacity variables does not compromise the
104 +precision of the estimates.
107 105 \end{tablenotes}
108 106 \end{threeparttable}
109 107 \end{table}
modified paper/sections/conclusion.tex +70 −46
@@ -3,53 +3,77 @@
3 3 \label{sec:conclusion}
4 4 % ==========================================================================
5 5
6 −This paper develops a comprehensive hedonic pricing model for Airbnb
7 −listings across Quebec, Canada, combining OLS estimation, quantile
8 −regression, machine learning, and spatial econometrics. Using 5,000
9 −listings from Inside Airbnb---3,412 with valid prices---we estimate nine
10 −nested specifications, quantile regressions at five percentiles, seven
11 −machine learning models, and three spatial econometric models.
6 +This paper has estimated hedonic price functions for a province-wide
7 +cross-section of Airbnb listings in Quebec from a scrape of 5,000 listing
8 +cards. Its first finding concerns the data: the displayed price field
9 +mixes nightly rates with the total prices of stays of about three weeks,
10 +for roughly 28\% of priced listings, concentrated among small Montreal
11 +rental units with few reviews. A two-regime mixture of hedonic
12 +regressions separates the two populations sharply and leaves 2,480
13 +listings with nightly prices. Every estimate in the first version of this
14 +paper was computed on the mixture; none survives, and the magnitudes
15 +reported there (a bedroom premium above 200\%, an 11\% premium per tenth
16 +of a rating point, negative ``amenity index'' effects) were artefacts of
17 +the contamination and of regressors that should not have been
18 +constructed. We have documented these corrections in full so that the
19 +lesson is usable by others who work with scraped platform prices: the
20 +bimodality was visible in the first summary table, and a ratio of
21 +medians by bedroom count is enough to diagnose it.
12 22
13 −\textit{Key findings.} The full hedonic model achieves $R^2 = 0.274$
14 −with 50 covariates. Bedrooms command a premium of approximately 213\%
15 −per unit, modulated by a concave log-bedrooms effect. The review score
16 −carries a premium of approximately 11\% per 0.1-point increment. Local
17 −listing density within 500m depresses prices ($-0.8$\% per listing),
18 −while density at 1~km shows a positive agglomeration effect.
23 +On the nightly-price sample the hedonic model behaves as the literature
24 +leads one to expect. Capacity, bathrooms and bedrooms, the shared-bathroom
25 +indicator that stands in for the unobserved room type, the number of
26 +photos and the displayed rating are the priced attributes; title
27 +categories matter once location is held fixed, with chalets and houses
28 +priced about 8 to 10\% above rental units of the same capacity; local
29 +density is positively priced within cities. The Superhost and Guest
30 +Favourite badges carry no premium conditional on capacity, type and
31 +location, and the number of reviews is unrelated to price on average.
32 +The specification with city fixed effects explains half of the variance
33 +of log prices, with a root mean squared error of 0.475 log points, and
34 +its coefficients are stable to the choice of fixed-effect unit, to
35 +clustering, to the regime cut-off and to the exclusion of commercial
36 +lodging or of Montreal.
19 37
20 −Quantile regression reveals substantial heterogeneity: the entire-home
21 −premium nearly doubles from $\tau = 0.10$ to $\tau = 0.75$, while
22 −review scores matter more at lower quantiles. The pseudo-$R^2$ declines
23 −from 0.100 to 0.020 across quantiles, confirming that luxury pricing
24 −depends heavily on unobserved factors.
38 +The three complementary estimators each add something the linear model
39 +does not show. Quantile regression reveals that cheap listings are priced
40 +per guest and certified by reviews and the Superhost badge, whereas
41 +expensive listings are priced per room and per bathroom, closer to the
42 +centre, and are cheaper when heavily reviewed; the inter-quantile
43 +differences for bedrooms, bathrooms and review counts are statistically
44 +significant. The spatial models find moderate spatial dependence
45 +($\hat\rho \approx 0.20$--$0.26$, $\hat\lambda \approx 0.28$) and a spatial
46 +multiplier of about 1.25, but the direct impacts are within a few
47 +percent of the OLS coefficients, so the hedonic estimates are not
48 +materially biased by the omitted spatial lag. The machine-learning
49 +benchmarks improve the out-of-sample $R^2$ from 0.47 to 0.56 under random
50 +cross-validation and from 0.41 to 0.48 when whole areas are held out; the
51 +seven-point loss under spatial blocking applies to every model, and the
52 +SHAP decomposition of the best learner ranks capacity first and the
53 +badges last, as the hedonic coefficients do, and attributes to the
54 +review count a weight that the linear model cannot, because its
55 +association with price changes sign along the distribution. The flexible models refine the hedonic surface
56 +rather than contradict it, and a median pricing error of about one
57 +quarter of the nightly price is the practical limit of valuation from
58 +card-level information.
25 59
26 −XGBoost achieves the best out-of-sample $R^2$ (0.285, MAPE = 14.3\%),
27 −modestly exceeding the OLS model. The similar performance of parametric
28 −and non-parametric models suggests that the log-linear specification
29 −captures the majority of systematic variation.
60 +\textit{Limitations.} The price is an asking price displayed on a single
61 +day and excludes the cleaning fee; the data are a cross-section, so
62 +seasonality and within-listing dynamics are unobserved and all
63 +coefficients are conditional associations rather than marginal
64 +willingness to pay. The room type, the host identifier and the amenity
65 +list were not scraped, so professionalisation and specific amenities
66 +cannot be priced, and the stay-regime listings cannot be converted to
67 +nightly rates. The scrape reflects the platform's search results on the
68 +collection dates and is denser in urban and resort markets.
30 69
31 −\textit{Practical implications.} The price decomposition framework
32 −allows hosts to benchmark their listing against comparable properties.
33 −The spatial analysis highlights that immediate competitive density
34 −depresses prices, suggesting differentiation on amenities and quality
35 −in dense urban clusters. Quantile-specific estimates are useful for
36 −revenue management: luxury-segment hosts should prioritize entire-home
37 −exclusivity and premium location, while budget-segment hosts gain from
38 −structural capacity and review credibility.
39 −
40 −\textit{Limitations.} The cross-sectional design limits causal
41 −identification. The price variable reflects the listed price, which may
42 −differ from the transaction price. The original dataset contains only
43 −19 variables, requiring extensive feature engineering from listing names
44 −and amenity counts. Certain optional dependencies (CatBoost, pygam,
45 −SHAP, PySAL) were unavailable, necessitating fallback implementations.
46 −The spatial models rely on a fixed $k$-nearest-neighbours weight matrix
47 −($k = 5$); alternative spatial structures may yield different estimates.
48 −
49 −\textit{Future research.} Panel data methods exploiting within-listing
50 −variation would strengthen causal identification. Booking-level
51 −transaction data including cleaning fees and occupancy rates would
52 −permit a more complete analysis. Pre-trained language model embeddings
53 −applied to descriptions and reviews could extract richer text-based
54 −features. Extending the framework to other Canadian provinces would test
55 −external validity.
70 +\textit{Future work.} A repeated scrape that records the search dates,
71 +the stay length behind each displayed price, the room type and the host
72 +identifier would remove the main measurement problems and allow panel
73 +estimation of within-listing price responses to reviews, badges and
74 +seasons. Linking listings to realised bookings or to the calendar would
75 +replace asking prices with revenue. Finally, the Quebec market offers a
76 +natural setting to study how Montreal's registration and
77 +primary-residence rules shift the composition of listings and their
78 +prices, a question that the cross-sectional stay-price pattern documented
79 +here already hints at.
modified paper/sections/data.tex +202 −234
@@ -3,288 +3,256 @@
3 3 \label{sec:data}
4 4 % ==========================================================================
5 5
6 −\subsection{Data Source}
6 +\subsection{Source and Content of the Scrape}
7 +\label{subsec:source}
8 +
9 +The data are a scrape of Airbnb's public search pages for the province
10 +of Quebec collected in early 2026. The file carries no timestamp; it was
11 +assembled in the same period as the January 2026 rental extraction used
12 +in the companion paper on Airbnb and rents (UQO Working Paper No.~5),
13 +which analyses the same 5,000 listings. The unit of observation is the
14 +listing card as it appears in search results, and the record contains
15 +nineteen fields: the card title, the municipality, a property-type label,
16 +the displayed price, a price category, the star rating and a rating
17 +category, the numbers of bedrooms and bathrooms, the guest capacity, the
18 +number of amenities, the number of photos, the number of reviews, a
19 +composite ``quality score'' generated by the scraper, the Superhost and
20 +Guest Favourite badges, the pet policy and the coordinates. The data are
21 +therefore considerably sparser than an Inside Airbnb extract: the room
22 +type (entire home, private room, shared room), the host identifier, the
23 +amenity list, the cleaning fee, the minimum stay and the calendar are not
24 +observed, and the first version of this paper, which described the data
25 +as an Inside Airbnb sample with amenity lists and host profiles, was
26 +wrong on this point.\footnote{The scraper-generated quality score is a
27 +deterministic function of the review count, the badges and the photo
28 +count ($R^2 = 0.63$ in a linear regression on those fields) and is not
29 +used. Three fields of the first version are no longer used: ``amenity
30 +indices'' that were computed by adding random noise to the normalised
31 +amenity count, ``room-type'' indicators that relabelled the property-type
32 +field, and a ``multi-listing host'' proxy based on duplicated card titles.}
33 +
34 +The card title follows a fixed template, for example ``Rental unit in
35 +Montr\'eal $\cdot$ $\star$4.90 $\cdot$ 2 bedrooms $\cdot$ 3 beds $\cdot$
36 +1 shared bath'', and it carries information that the structured fields
37 +do not. We parse it to obtain the title category assigned by the host
38 +(44 distinct labels, which we group into six classes), the star rating
39 +as displayed, a ``New'' marker for listings that have no rating yet, the
40 +number of beds, and whether the bathroom is shared, private or a half
41 +bath. Parsing also repairs three defects of the structured fields. First,
42 +the rating field is missing for 456 of the 3,456 priced listings (13.2\%)
43 +and had been median-imputed in the committed version of the data; the
44 +title shows that these listings display no star, so we treat them as
45 +unrated and add an indicator. Second, the scraper stored zero bathrooms
46 +whenever the title qualified the bathroom (``1 shared bath'', ``1 private
47 +bath'', ``Half-bath''); the count is recovered from the title for 465
48 +listings. Third, 161 studios have zero bedrooms in the structured field
49 +and are recoded as one sleeping room with a studio indicator, and 46
50 +bedroom counts missing from the field are read from the title. Fifty
51 +titles were served in German by the platform's locale and are parsed with
52 +the corresponding patterns; for 37 of them the rating field had been
53 +truncated to 4.0 by a decimal-comma parsing error and the title value is
54 +retained.
55 +
56 +\subsection{The Price Field}
57 +\label{subsec:price_field}
58 +
59 +Of the 5,000 cards, 1,544 (30.9\%) display no price and are dropped. The
60 +displayed price of the remaining 3,456 listings has a median of \$220 and
61 +a mean of \$1,233, and its distribution on the logarithmic scale is
62 +bimodal (Figure~\ref{fig:logprice}). A two-component normal mixture
63 +fitted to $\ln p$ places one mode near \$150 and the other near \$2,500;
64 +26.5\% of listings (915) display a price above \$1,000. The upper mode is
65 +not a luxury segment. Table~\ref{tab:price_regimes} shows that, bedroom
66 +count by bedroom count, the median price of listings above \$1,000 is
67 +sixteen to nineteen times the median of listings below it, a ratio that
68 +no plausible quality difference produces but that a stay of about three
69 +weeks does. Listings in the upper mode are disproportionately small
70 +rental units in Montreal with few reviews and without the Superhost
71 +badge, which is the profile of listings oriented towards stays of a month
72 +or more under Montreal's short-term rental rules. We conclude that the
73 +scraper captured, for part of the sample, the total price of a multi-night
74 +stay rather than the nightly rate, and the companion paper reaches the same
75 +diagnosis on the same file. Because neither the stay length nor the
76 +search dates are recorded, the nightly price of these listings cannot be
77 +recovered.
7 78
8 −The primary data for this study are drawn from Inside Airbnb
9 −(\url{http://insideairbnb.com}), an independent, open-source project that
10 −periodically scrapes publicly available listing information from the Airbnb
11 −platform. The extracts provide a snapshot of every active listing, including
12 −the nightly price, property and room type, geographic coordinates, host
13 −profile variables, review scores, amenity counts, and free-text listing
14 −names and descriptions.
15 −
16 −Our sample covers the province of Quebec, Canada, encompassing the major
17 −urban markets of Montr\'{e}al, Quebec City, Gatineau, Sherbrooke, and
18 −Trois-Rivi\`{e}res, as well as popular tourism and resort regions including
19 −the Laurentians (Mont-Tremblant, Saint-Sauveur), the Eastern Townships
20 −(Magog, Bromont), the Charlevoix corridor, the
21 −Saguenay--Lac-Saint-Jean region, and the Gasp\'{e}sie coast.
22 −
23 −\subsection{Sample Construction}
24 −
25 −Starting from the raw extract of 5,000 listings with 19 original variables,
26 −we apply the following cleaning procedures:
27 −%
28 −\begin{enumerate}[leftmargin=2em]
29 − \item \textbf{Price validity.} Listings with a nightly price below
30 − \$10~CAD (17 observations) or above \$25,000~CAD (27 observations)
31 − are set to missing, eliminating data-entry errors and placeholder
32 − prices. After this step, 3,412 listings retain valid price
33 − observations.
34 −
35 − \item \textbf{Price transformations.} We construct the raw price, three
36 − Winsorized versions at the 1st/99th percentiles
37 − (\$38--\$10,822), 2nd/98th (\$46--\$8,117), and 5th/95th
38 − (\$63--\$4,921), plus natural log transformations.
39 −
40 − \item \textbf{Rating standardization.} Scores originally on a 0--100
41 − scale are converted to 0--5. Of the 5,000 listings, 810
42 − (16.2\%) lack a rating.
43 −
44 − \item \textbf{Geocoding validation.} Listings whose coordinates fall
45 − outside the geographic boundaries of Quebec
46 − (latitude $\in [44.5, 55.5]$, longitude $\in [-80.0, -56.0]$)
47 − are removed (6~observations).
48 −
49 − \item \textbf{Property type standardization.} Approximately 30 Inside
50 − Airbnb property type variants are mapped to six canonical
51 − categories: Rental unit, House, Cabin/Chalet, Condo, Apartment,
52 − and Other.
53 −\end{enumerate}
54 −
55 −After applying these filters, the analytical sample comprises
56 −$N = 3{,}412$ listings with valid prices. Models incorporating additional
57 −covariates with their own missing values use smaller effective samples
58 −(reported alongside each specification).
59 −
60 −\subsection{Variable Definitions}
61 −
62 −We organize the variables into seven categories. The dependent variable
63 −is the natural logarithm of the nightly listing price in Canadian dollars
64 −($\ln p_i$). The log transformation addresses the strong right skew of the
65 −raw price distribution (mean = \$1,115; median = \$219; standard deviation
66 −= \$2,253) and yields coefficients interpretable as approximate percentage
67 −changes via $\text{Premium}(\%) = 100 \times (\exp(\hat{\beta}) - 1)$.
68 −
69 −\textit{Structural characteristics} ($\mathbf{S}_i$) capture the physical
70 −attributes: bedrooms (mean~=~2.08), bathrooms (mean~=~1.28), guest capacity
71 −(mean~=~5.31), log-transformed counterparts, per-guest ratios, property type
72 −dummies (entire home = 48.1\%, private room = 35.5\%), a large-capacity
73 −indicator ($\geq 8$ guests), quadratic and interaction terms.
74 −
75 −\textit{Amenity indices} ($\mathbf{A}_i$) are constructed from the raw
76 −amenity count (mean~=~44.9, range 3--109): luxury index, business travel
77 −index, family comfort index, leisure index, remote work index, and
78 −amenity richness index, all normalized to $[0, 1]$.
79 −
80 −\textit{Host attributes} ($\mathbf{H}_i$) include Superhost status
81 −(52.3\%), Guest Favorite badge (33.4\%), multi-listing host indicator,
82 −and a Superhost $\times$ entire-home interaction.
83 −
84 −\textit{Reputation variables} ($\mathbf{R}_i$) comprise the overall review
85 −score (mean~=~4.80 on a 0--5 scale), log review count, quality score,
86 −reputation score, cleanliness premium indicator, and missing-rating flag.
87 −
88 −\textit{Locational variables} ($\mathbf{L}_i$) include Haversine distance
89 −to the nearest city centre (22 municipalities), local listing density
90 −within 500m (mean~=~14.7, max~=~125) and 1~km, local average price
91 −within 500m and 1~km, and a $K$-means spatial cluster ($K = 20$).
92 −
93 −\textit{Text-derived features} ($\mathbf{N}_i$) include title length,
94 −seven bilingual keyword scores, and 10 TF-IDF/SVD embedding components
95 −capturing 16.98\% of lexical variance.
96 −
97 −\subsection{Descriptive Statistics}
98 −
99 −Table~\ref{tab:summary} reports descriptive statistics for the key
100 −variables. The price distribution is strongly right-skewed: the mean
101 −(\$1,115) exceeds the median (\$219) by a factor of five, confirming the
102 −appropriateness of the log transformation.
79 +\begin{figure}[!htbp]
80 +\centering
81 +\includegraphics[width=0.85\textwidth]{rev_fig_logprice_mixture.pdf}
82 +\caption{Displayed Prices of 3,456 Quebec Airbnb Listings on a Logarithmic Scale}
83 +\label{fig:logprice}
84 +\begin{minipage}{0.9\textwidth}
85 +\footnotesize
86 +\textit{Notes:} Histogram of $\ln p$ with the two components of a normal
87 +mixture fitted by maximum likelihood (solid lines) and their sum (dashed).
88 +The grey dotted line marks \$1,000; the red dotted line marks the price at
89 +which the posterior probability of the upper component reaches one half.
90 +\end{minipage}
91 +\end{figure}
103 92
104 93 \begin{table}[!htbp]
105 94 \centering
106 −\caption{Summary Statistics of Key Variables}
107 −\label{tab:summary}
95 +\caption{Median Displayed Price by Bedroom Count, Below and Above \$1,000}
96 +\label{tab:price_regimes}
108 97 \begin{threeparttable}
109 −\begin{tabular}{lrrrrrrr}
110 −\toprule
111 −Variable & Mean & Std.\ Dev. & Min & P25 & Median & P75 & $N$ \\
112 −\midrule
113 −Price (\$CAD) & 1,115 & 2,253 & 10.5 & 125.0 & 219.2 & 1,139 & 3,412 \\
114 −Log price & 5.87 & 1.42 & 2.36 & 4.83 & 5.39 & 7.04 & 3,412 \\
115 −Bedrooms & 2.08 & 1.53 & 0 & 1 & 2 & 3 & 5,000 \\
116 −Bathrooms & 1.28 & 1.05 & 0 & 1 & 1 & 2 & 5,000 \\
117 −Guest capacity & 5.31 & 3.37 & 1 & 2 & 4 & 7 & 5,000 \\
118 −Amenities count & 44.9 & 16.0 & 3 & 34 & 45 & 56 & 5,000 \\
119 −Rating (0--5) & 4.80 & 0.23 & 2.25 & 4.73 & 4.86 & 4.96 & 4,190 \\
120 −Num.\ reviews & 62.7 & 85.0 & 0 & 10 & 33 & 82 & 4,275 \\
121 −Quality score & 93.8 & 41.9 & 0 & 94.5 & 107.9 & 121.0 & 5,000 \\
122 −Num.\ images & 27.9 & 19.2 & 0 & 14 & 23 & 36 & 5,000 \\
123 −Is Superhost & 0.52 & 0.50 & 0 & 0 & 1 & 1 & 5,000 \\
124 −Is Guest Favorite & 0.33 & 0.47 & 0 & 0 & 0 & 1 & 5,000 \\
125 −Pets allowed & 0.29 & 0.46 & 0 & 0 & 0 & 1 & 5,000 \\
126 −\bottomrule
127 −\end{tabular}
98 +\input{../results/tables/rev_price_regimes.tex}
128 99 \begin{tablenotes}
129 100 \footnotesize
130 −\item \textit{Notes:} This table reports descriptive statistics for the
131 −main variables used in the empirical analysis. Price is measured in
132 −Canadian dollars per night. Rating is on a 0--5 scale. Binary variables
133 −are coded as 0/1.
101 +\item \textit{Notes:} Priced listings ($N = 3{,}456$). Studios are
102 +counted as one bedroom; the ``0'' row contains listings whose bedroom
103 +count could not be parsed. The ratio is the median above \$1,000 divided
104 +by the median below.
134 105 \end{tablenotes}
135 106 \end{threeparttable}
136 107 \end{table}
137 108
138 −Table~\ref{tab:price_type} presents the price distribution by property type.
139 −Condos and apartments exhibit the highest mean prices, driven by urban
140 −premium listings, while Cabin/Chalet listings show moderate means with
141 −substantial variation reflecting Quebec's diverse cottage and ski resort
142 −market.
109 +A single price threshold is an imperfect classifier: the three-week total
110 +of a \$40 room is below \$1,000, and the genuine nightly rate of a large
111 +chalet can exceed it. We therefore classify listings with the mixture of
112 +hedonic regressions of Section~\ref{subsec:mixture_methods}, which uses
113 +the listing's characteristics to judge whether its price is a nightly or
114 +a stay price. Table~\ref{tab:mixture} reports the estimates. The stay
115 +regime shifts the intercept by $\hat\delta = 3.15$ log points, an implied
116 +stay of about 23 nights, and has a wider residual dispersion, as expected
117 +if stay lengths vary; its probability rises in Montreal and falls with
118 +capacity, review count, Superhost status and the hotel and chalet
119 +categories. The posterior classification is sharp: only 7 listings have a
120 +posterior probability between 0.25 and 0.75. It assigns 976 listings
121 +(28.2\%) to the stay regime, of which 83 display a price at or below
122 +\$1,000, and it keeps 22 listings priced above \$1,000, mostly large
123 +chalets, in the nightly regime. The 2,480 listings with a posterior
124 +probability below one half form the analysis sample.
143 125
144 126 \begin{table}[!htbp]
145 127 \centering
146 −\caption{Price Distribution by Property Type (\$CAD)}
147 −\label{tab:price_type}
128 +\caption{Two-Regime Mixture of Hedonic Regressions: Nightly Versus Stay Prices}
129 +\label{tab:mixture}
148 130 \begin{threeparttable}
149 −\begin{tabular}{lrrrrrr}
150 −\toprule
151 −Property Type & Mean & Median & Std.\ Dev. & Min & Max & $N$ \\
152 −\midrule
153 −Apartment & 1,276 & 201 & 3,328 & 15 & 18,117 & 77 \\
154 −Cabin/Chalet & 969 & 237 & 2,215 & 48 & 23,321 & 691 \\
155 −Condo & 1,344 & 210 & 2,343 & 49 & 14,577 & 237 \\
156 −House & 1,058 & 223 & 2,206 & 18 & 22,811 & 679 \\
157 −Other & 1,203 & 170 & 2,727 & 11 & 23,625 & 554 \\
158 −Rental unit & 1,136 & 247 & 1,925 & 14 & 24,928 & 1,174 \\
159 −\bottomrule
160 −\end{tabular}
131 +\input{../results/tables/rev_mixture.tex}
161 132 \begin{tablenotes}
162 133 \footnotesize
163 −\item \textit{Notes:} This table reports the distribution of nightly
164 −prices (CAD) by property type for listings with valid prices ($N = 3{,}412$).
134 +\item \textit{Notes:} Estimates of Equation~\eqref{eq:mixture} by the EM
135 +algorithm on the 3,456 priced listings. The common slopes
136 +$\boldsymbol{\beta}$ use the M4 regressor set plus a Montreal indicator.
137 +The regime equation is a logistic regression of the posterior regime
138 +probability on the listed characteristics; standard errors in
139 +parentheses. ***, ** and * denote significance at the 1, 5 and 10\%
140 +levels.
165 141 \end{tablenotes}
166 142 \end{threeparttable}
167 143 \end{table}
168 144
169 −\subsection{Correlation Structure}
170 −
171 −Table~\ref{tab:correlations} presents pairwise Pearson correlations among
172 −the key continuous variables. Bedrooms, bathrooms, and guest capacity are
173 −moderately to strongly intercorrelated ($r = 0.64$--$0.81$), motivating
174 −the inclusion of per-guest ratios and log transformations to mitigate
175 −multicollinearity. The number of reviews shows a negative correlation
176 −with log price ($r = -0.24$), suggesting that more frequently booked
177 −listings tend to be lower-priced.
145 +\subsection{Analysis Sample and Descriptive Statistics}
146 +\label{subsec:descriptives}
147 +
148 +Table~\ref{tab:summary} describes the analysis sample. The median
149 +displayed price is \$162 and the mean \$206; the 10th and 90th
150 +percentiles are \$70 and \$376. The typical listing has two bedrooms,
151 +one and a half bathrooms and sleeps six; 91\% display a rating, with a
152 +mean of 4.81 and a tenth percentile of 4.57 among rated listings, the
153 +compression documented by \citet{Zervas2021}; 59\% of hosts are
154 +Superhosts and 41\% of listings carry the Guest Favourite badge. The
155 +sample spans 438 municipalities; Montreal accounts for 20\% of
156 +listings, Quebec City and Mont-Tremblant for the next largest shares, and
157 +the median listing is 17~km from the nearest of the 22 reference city
158 +centres. The last column shows that the full priced sample differs from
159 +the analysis sample mainly in price (because of the stay regime) and in
160 +the Montreal share. Prices in the analysis sample are winsorised at the
161 +1st and 99th percentiles of the full priced sample (\$31 and \$18,205) by
162 +the committed cleaning step, which affects 35 listings at the bottom (clipped to \$31) and none
163 +at the top.
178 164
179 165 \begin{table}[!htbp]
180 166 \centering
181 −\caption{Correlation Matrix of Key Variables}
182 −\label{tab:correlations}
167 +\caption{Descriptive Statistics, Analysis Sample}
168 +\label{tab:summary}
183 169 \begin{threeparttable}
184 170 \small
185 −\begin{tabular}{lccccccc}
186 −\toprule
187 − & log\_price & bed & bath & guests & amen. & rating & reviews \\
188 −\midrule
189 −log\_price & 1.000 & & & & & & \\
190 −Bedrooms & 0.111*** & 1.000 & & & & & \\
191 −Bathrooms & 0.138*** & 0.704*** & 1.000 & & & & \\
192 −Guests & 0.072*** & 0.806*** & 0.637*** & 1.000 & & & \\
193 −Amenities & $-$0.051** & 0.322*** & 0.290*** & 0.370*** & 1.000 & & \\
194 −Rating & 0.006 & 0.129*** & 0.157*** & 0.113*** & 0.274*** & 1.000 & \\
195 −Reviews & $-$0.236*** & $-$0.061** & $-$0.049** & $-$0.029 & 0.095*** & 0.072*** & 1.000 \\
196 −\bottomrule
197 −\end{tabular}
171 +\input{../results/tables/rev_summary.tex}
198 172 \begin{tablenotes}
199 173 \footnotesize
200 −\item \textit{Notes:} Pearson correlation coefficients.
201 −***, **, and * indicate statistical significance at the 1\%, 5\%, and
202 −10\% levels, respectively.
174 +\item \textit{Notes:} Analysis sample of 2,480 listings classified in
175 +the nightly-price regime. The last column reports the mean in the full
176 +priced sample ($N = 3{,}456$). Binary variables are 0/1. Bathrooms and
177 +bedrooms are the repaired counts described in
178 +Section~\ref{subsec:source}. Distances are great-circle distances to the
179 +nearest of 22 reference municipalities.
203 180 \end{tablenotes}
204 181 \end{threeparttable}
205 182 \end{table}
206 183
207 −\subsection{Price Distribution}
208 −
209 −Figure~\ref{fig:price_dist} displays the distribution of nightly prices.
210 −The raw price distribution is strongly right-skewed, with the median
211 −(\$219) substantially below the mean (\$1,115).
212 −Figure~\ref{fig:logprice_dist} shows the log-transformed distribution,
213 −which is approximately symmetric.
184 +Table~\ref{tab:price_category} and Figure~\ref{fig:price_by_category}
185 +show prices by title category. Chalets, cottages and cabins (30\% of the
186 +sample) and houses (20\%) have the highest median prices, about \$200 and
187 +\$180; rental units (28\%) and condominiums, lofts and apartments (12\%)
188 +are priced near \$135; hotel rooms, bed-and-breakfasts and hostels (6\%)
189 +near \$100. These raw differences confound type with capacity and
190 +location, which the hedonic model separates. Figure~\ref{fig:map} maps
191 +the analysis sample: the Montreal and Quebec City agglomerations, the
192 +Laurentian corridor north of Montreal, Charlevoix and the Eastern
193 +Townships are the main concentrations, and the density of listings within
194 +1~km ranges from zero for a third of the sample to over 90 in central
195 +Montreal.
214 196
215 −\begin{figure}[!htbp]
197 +\begin{table}[!htbp]
216 198 \centering
217 −\includegraphics[width=0.85\textwidth]{01_price_distribution.png}
218 −\caption{Distribution of Nightly Listing Prices (\$CAD)}
219 −\label{fig:price_dist}
220 −\begin{minipage}{0.9\textwidth}
199 +\caption{Displayed Nightly Price by Title Category, Analysis Sample}
200 +\label{tab:price_category}
201 +\begin{threeparttable}
202 +\input{../results/tables/rev_price_by_category.tex}
203 +\begin{tablenotes}
221 204 \footnotesize
222 −\textit{Notes:} This figure plots the histogram and kernel density estimate
223 −of nightly listing prices in Canadian dollars. The vertical dashed lines
224 −indicate the mean and median.
225 −\end{minipage}
226 −\end{figure}
205 +\item \textit{Notes:} Title categories group the 44 labels hosts choose
206 +for the listing card. ``Chalet/cottage/cabin'' includes vacation and
207 +holiday homes and nature lodges; ``House'' includes townhouses,
208 +bungalows, villas and farm stays; ``Condo/loft/apartment'' includes
209 +serviced apartments and guest suites; ``Hotel/B\&B/hostel'' includes
210 +aparthotels, boutique hotels, guesthouses and resorts.
211 +\end{tablenotes}
212 +\end{threeparttable}
213 +\end{table}
227 214
228 215 \begin{figure}[!htbp]
229 216 \centering
230 −\includegraphics[width=0.85\textwidth]{02_log_price_distribution.png}
231 −\caption{Distribution of Log Nightly Prices}
232 −\label{fig:logprice_dist}
217 +\includegraphics[width=0.85\textwidth]{rev_fig_price_by_category.pdf}
218 +\caption{Displayed Nightly Price by Title Category}
219 +\label{fig:price_by_category}
233 220 \begin{minipage}{0.9\textwidth}
234 221 \footnotesize
235 −\textit{Notes:} This figure plots the histogram and kernel density estimate
236 −of $\ln(\text{price})$. The approximately symmetric distribution confirms
237 −the suitability of the log-linear specification.
222 +\textit{Notes:} Box plots (median, interquartile range, whiskers at 1.5
223 +times the interquartile range; outliers omitted) on a logarithmic price
224 +axis, analysis sample.
238 225 \end{minipage}
239 226 \end{figure}
240 227
241 −\subsection{Geographic Coverage}
242 −
243 −Figure~\ref{fig:map} maps the spatial distribution of listings across
244 −Quebec, with colour indicating nightly price. The majority of listings
245 −are concentrated in Montr\'{e}al, with secondary clusters in Quebec City,
246 −the Laurentian resort corridor, and the Eastern Townships. Local listing
247 −density reaches 125 within 500 metres in central Montr\'{e}al.
248 −
249 228 \begin{figure}[!htbp]
250 229 \centering
251 −\includegraphics[width=0.95\textwidth]{03_price_map.png}
252 −\caption{Geographic Distribution of Airbnb Listings in Quebec}
230 +\includegraphics[width=0.95\textwidth]{rev_fig_map.pdf}
231 +\caption{Geographic Distribution of the Analysis Sample}
253 232 \label{fig:map}
254 233 \begin{minipage}{0.9\textwidth}
255 234 \footnotesize
256 −\textit{Notes:} Each point represents one listing, coloured by nightly
257 −price (capped at the 99th percentile for visual clarity). Coordinates are
258 −latitude/longitude (WGS-84).
235 +\textit{Notes:} Each point is a listing in the nightly-price regime,
236 +coloured by displayed price on a logarithmic scale. Coordinates are
237 +WGS-84; a small number of listings in the Gasp\'esie and on the North
238 +Shore lie outside the plotted window.
259 239 \end{minipage}
260 240 \end{figure}
261 241
262 −\subsection{Price Variation by Property Type and Neighbourhood}
263 −
264 −Figure~\ref{fig:price_neighbourhood} displays boxplots of nightly prices
265 −for the top 20 cities by listing count, and Figure~\ref{fig:price_room}
266 −shows the price distribution by property type.
267 −
268 −\begin{figure}[!htbp]
269 −\centering
270 −\includegraphics[width=0.95\textwidth]{04_price_by_neighbourhood.png}
271 −\caption{Nightly Price Distribution by City (Top 20)}
272 −\label{fig:price_neighbourhood}
273 −\begin{minipage}{0.9\textwidth}
274 −\footnotesize
275 −\textit{Notes:} Boxplots of nightly prices for the 20 cities with the
276 −most listings, ordered by median price.
277 −\end{minipage}
278 −\end{figure}
279 −
280 −\begin{figure}[!htbp]
281 −\centering
282 −\includegraphics[width=0.85\textwidth]{05_price_by_room_type.png}
283 −\caption{Price Distribution by Property Type}
284 −\label{fig:price_room}
285 −\begin{minipage}{0.9\textwidth}
286 −\footnotesize
287 −\textit{Notes:} Violin plots of nightly prices by property type. Inner
288 −markers indicate quartiles.
289 −\end{minipage}
290 −\end{figure}
242 +\subsection{What the Cross-Section Can and Cannot Measure}
243 +\label{subsec:limits_data}
244 +
245 +Three features of the data bound the interpretation of everything that
246 +follows. The price is the host's asking price displayed on one day, not
247 +a transaction price, and it embodies whatever dynamic pricing the host
248 +applies \citep{Gibbs2018dynamic}; the cleaning fee, which is a
249 +substantial and variable component of what guests pay, is not observed.
250 +The sample is a single cross-section: the first version of this paper
251 +referred to ``seasons'' and ``seasonal sub-markets'', but no seasonal
252 +variation exists in the data, and seasonality can enter only through the
253 +composition of listings active at the time of the scrape, which the city
254 +fixed effects absorb. Finally, the scrape covers listings returned by
255 +the platform's search for Quebec on the collection dates, so listings
256 +that were calendar-blocked or filtered out are missing, and the
257 +province-wide coverage is denser in the urban and resort areas where the
258 +platform is most active.
modified paper/sections/introduction.tex +108 −87
@@ -3,96 +3,117 @@
3 3 \label{sec:introduction}
4 4 % ==========================================================================
5 5
6 −The theory of hedonic prices, formalized by \citet{Rosen1974} and rooted in
7 −the characteristics approach to consumer demand developed by
8 −\citet{Lancaster1966}, posits that differentiated goods can be described by a
9 −vector of objectively measured attributes and that the market price of such a
10 −good equals the sum of the implicit valuations consumers place on each
11 −attribute. In the four decades since Rosen's seminal contribution, hedonic
12 −models have become a workhorse of applied microeconomics, with extensive
13 −applications in real estate \citep{ChattopadhyayMachemehl2006}, automobiles,
14 −environmental valuation, and, more recently, the sharing economy.
6 +A short-term rental listing is a bundle of characteristics priced by an
7 +individual host rather than by a centralised market maker. The theory of
8 +hedonic prices \citep{Rosen1974}, which builds on the characteristics view
9 +of demand of \citet{Lancaster1966}, treats the observed price of such a
10 +differentiated good as the sum of the implicit prices of its attributes,
11 +and the hedonic price function has become the standard empirical tool for
12 +housing and property markets \citep{Malpezzi2003, Sirmans2005}. Short-term
13 +rental platforms offer an unusually complete view of this function: every
14 +listing displays its capacity, its type, its amenities, its host's status
15 +and its reputation, together with a price that the host chose. Since
16 +\citet{WangNicolau2017} and \citet{Gibbs2018}, a sizeable literature has
17 +estimated hedonic price equations for Airbnb listings in individual cities
18 +and across cities \citep{ChenXie2017, Teubner2017, PerezSanchez2018,
19 +Cai2019, Lorde2019, Gyodi2021, TongGunter2022}, with the recurrent finding
20 +that capacity, room type, location and reputation signals explain most of
21 +the cross-sectional variation in displayed prices, and with a secondary
22 +literature on the value of trust signals such as Superhost status, review
23 +scores and host photos \citep{Ert2016, Zervas2021}.
15 24
16 −The rapid global expansion of Airbnb and competing short-term rental (STR)
17 −platforms has created a uniquely rich laboratory for hedonic analysis. Unlike
18 −traditional hotel room inventories, which are relatively standardized within
19 −a star-rating tier, Airbnb listings exhibit enormous heterogeneity along
20 −structural, locational, amenity, and reputational dimensions. Each listing
21 −is, in effect, a bundle of characteristics chosen and priced by an individual
22 −host operating in a decentralized marketplace. The platform's publicly
23 −accessible data---including detailed descriptions, amenity lists, review
24 −scores, host profiles, calendar availability, and geographic
25 −coordinates---provides researchers with an unusually granular view of the
26 −hedonic price surface.
25 +Quebec is an interesting and little-studied case. The province combines a
26 +large metropolitan market (Montreal), a heritage tourism market (Quebec
27 +City) and an extensive resort and cottage market in the Laurentians,
28 +Charlevoix and the Eastern Townships, so that a provincial sample mixes
29 +urban apartments with rural chalets in a way that single-city studies
30 +cannot. Canadian evidence on short-term rentals has concentrated on their
31 +housing-market consequences \citep{WachsmuthWeisler2018, Combs2020}; the
32 +only hedonic study we are aware of, \citet{Deboosere2019}, estimates a
33 +multilevel model of prices and revenue for Montreal and finds that
34 +accessibility and professionalisation dominate. No provincial hedonic
35 +analysis exists, and none uses the newer platform signals (the Guest
36 +Favourite badge, introduced in 2023) or compares the hedonic model with
37 +quantile, spatial and machine-learning estimators on the same data.
27 38
28 −A growing empirical literature has exploited this richness.
29 −\citet{WangNicolau2017} estimate hedonic price equations for a cross-section
30 −of Airbnb listings in 33~major cities, finding that property type, location,
31 −host characteristics, and online reputation are significant price
32 −determinants. \citet{Gibbs2018} extend the analysis to include amenity
33 −bundles and find that premium amenities such as pools and hot tubs
34 −command substantial price premiums. \citet{Zhang2017} and \citet{Chen2020}
35 −document similar patterns across Chinese and U.S.\ markets, respectively,
36 −while \citet{BenitezAurioles2018} and \citet{Dogru2017} examine European and
37 −Turkish markets. \citet{PerezSanchez2018} apply geographically weighted
38 −regression to Spanish Airbnb data, demonstrating that implicit prices vary
39 −spatially. \citet{GunterOnder2018} study Vienna's market structure,
40 −while \citet{Magno2018} investigate the role of host experience in shaping
41 −pricing outcomes.
39 +This paper estimates hedonic price functions for a province-wide
40 +cross-section of Airbnb listings in Quebec scraped from the public search
41 +pages of the platform in early 2026. The data are a snapshot of 5,000
42 +listing cards, of which 3,456 display a price. They are not an Inside
43 +Airbnb extract: the record is the listing card, which carries the title,
44 +the displayed price, the star rating, the review count, capacity, bedroom
45 +and bathroom counts, an amenity count, the Superhost and Guest Favourite
46 +badges, the pet policy and the coordinates, but neither the room type, the
47 +host identifier, the amenity list, the cleaning fee nor the minimum stay.
48 +The limited field set is a constraint that shapes the paper, and we
49 +describe exactly what each variable measures rather than relabelling it.
42 50
43 −Despite these contributions, several gaps remain. First, most studies rely on
44 −a single econometric specification---typically ordinary least squares (OLS)
45 −applied to a log-linear price equation---and therefore cannot capture
46 −heterogeneity across the conditional price distribution. Second, the
47 −potential for complex non-linear interactions among listing characteristics
48 −is seldom explored, and when machine learning methods are employed, the
49 −resulting models are treated as black boxes rather than as complements to
50 −structural hedonic inference. Third, spatial dependence in listing
51 −prices---a first-order concern in any market where location matters---is
52 −frequently acknowledged but rarely modeled explicitly using spatial
53 −econometric techniques.
51 +The first task of the paper is a measurement problem that any user of
52 +scraped Airbnb prices must confront. The displayed price field is
53 +bimodal on the logarithmic scale: one mode lies near \$150 and a second
54 +near \$2,500, and 26.5\% of priced listings carry a ``nightly'' price
55 +above \$1,000. The second mode is populated by ordinary one- and
56 +two-bedroom rental units in Montreal, its listings have prices that are
57 +about twenty times those of otherwise similar listings in the first mode,
58 +and the pattern is best explained by the platform displaying the total
59 +price of a multi-night stay for part of the search results. We document
60 +this with a two-component mixture model and a regime regression, and we
61 +estimate the hedonic models on the subsample priced at or below \$1,000,
62 +with the threshold varied in robustness checks. The companion paper on
63 +Airbnb and rents (UQO Working Paper No.~5) uses the same scrape and
64 +reaches the same diagnosis; here we treat it as the point of departure.
54 65
55 −This paper addresses all three gaps by developing a comprehensive
56 −multi-method hedonic pricing model for Airbnb listings in Quebec, Canada.
57 −Our central research questions are:
58 −%
59 −\begin{enumerate}[leftmargin=2em]
60 − \item What are the implicit prices of structural, amenity, host,
61 − reputation, locational, and text-derived characteristics of
62 − Airbnb listings in Quebec?
63 − \item How do these implicit prices vary across the conditional price
64 − distribution, from budget to luxury segments?
65 − \item To what extent do non-linear interactions and spatial dependence
66 − alter the hedonic price surface estimated by conventional linear
67 − models?
68 − \item Which listing attributes contribute most to predictive accuracy,
69 − and does the importance ranking differ between econometric and
70 − machine learning frameworks?
71 −\end{enumerate}
66 +The second task is the hedonic analysis itself. We estimate a sequence of
67 +nested ordinary least squares specifications that add amenity, host and
68 +reputation, location and finally city fixed effects to a structural
69 +baseline, with heteroskedasticity-robust and city-clustered standard
70 +errors; quantile regressions at five quantiles of the conditional
71 +log-price distribution, with bootstrap tests of inter-quantile
72 +differences; spatial lag, spatial error and spatial Durbin models
73 +estimated by maximum likelihood on a nearest-neighbour weights matrix,
74 +with direct and indirect impacts computed as in \citet{LeSagePace2009};
75 +and five supervised learning models evaluated under both random and
76 +spatially blocked cross-validation \citep{Roberts2017}, with the best
77 +model interpreted through SHAP values \citep{Lundberg2017, Lundberg2020}.
78 +Throughout, the estimates are read as conditional associations in a
79 +cross-section of asking prices, not as structural marginal willingness to
80 +pay \citep{Kuminoff2010, Bishop2020}.
72 81
73 −Our contribution is fourfold. First, we assemble a comprehensive hedonic
74 −dataset for Quebec---a market that, despite its significance as a major
75 −North American tourism destination, has received relatively little attention
76 −in the Airbnb pricing literature. Our sample encompasses 5,000 listings
77 −across Montr\'{e}al, Quebec City, the Laurentians, the Eastern Townships,
78 −Charlevoix, and dozens of smaller municipalities. Second, we construct a
79 −feature space spanning seven attribute categories---structural
80 −characteristics, amenity indices, host attributes, reputation signals,
81 −locational variables, NLP-derived text features, and spatial
82 −controls---producing 49 modeling features. Third, we implement a layered
83 −estimation strategy combining OLS with heteroskedasticity-robust standard
84 −errors (HC3), quantile regression at five percentiles, an ensemble of seven
85 −machine learning models interpreted through SHAP values
86 −\citep{Lundberg2017}, and spatial econometric models including spatial lag,
87 −spatial error, and spatial Durbin specifications \citep{LeSagePace2009,
88 −Anselin1988}. Fourth, we demonstrate how estimated implicit prices aggregate
89 −into a price decomposition that benchmarks any listing against the market,
90 −providing actionable intelligence for hosts and platform managers.
82 +Three results stand out. First, once the stay-price regime is removed,
83 +the hedonic model behaves as the literature leads one to expect: capacity
84 +variables, title category and location explain the bulk of price
85 +variation, with an $R^2$ that rises from about one-third in the structural
86 +baseline to about one-half with city fixed effects, compared with
87 +$R^2$ values of 0.05 to 0.27 obtained on the contaminated full sample in
88 +the first version of this paper. Second, reputation signals carry
89 +precisely estimated but modest premia once capacity and location are
90 +held fixed: Superhost status and the Guest Favourite badge are each worth
91 +a few percent of the nightly price, the review score matters mainly at
92 +the lower quantiles, and the number of reviews is negatively associated
93 +with price, consistent with high-turnover listings being cheaper.
94 +Third, flexible estimators improve on the fixed-effects hedonic model
95 +by a meaningful but bounded margin: gradient-boosting models raise the
96 +out-of-sample $R^2$ from 0.47 to 0.56 under random cross-validation and
97 +from 0.41 to 0.48 when whole areas are held out, every model loses about
98 +seven points of $R^2$ in the second design, and the SHAP decomposition of
99 +the best model ranks capacity first and the badges last, as the hedonic
100 +coefficients do, while exposing one sign-switching association (the
101 +review count) that a constant coefficient averages away. The non-linearities that the learners capture
102 +refine the hedonic surface rather than overturn it.
91 103
92 −The remainder of the paper is organized as follows.
93 −Section~\ref{sec:data} describes the data sources, variable construction,
94 −and summary statistics. Section~\ref{sec:methodology} presents the
95 −econometric and machine learning methodology.
96 −Section~\ref{sec:results} reports the main empirical results.
97 −Section~\ref{sec:robustness} discusses robustness checks.
98 −Section~\ref{sec:conclusion} concludes.
104 +The contribution is therefore twofold. Substantively, the paper provides
105 +the first province-wide hedonic estimates for Quebec's short-term rental
106 +market and documents how implicit prices differ between the urban and the
107 +resort segments and across the price distribution. Methodologically, it
108 +shows how a measurement defect of scraped platform prices can be detected
109 +and handled, and it benchmarks, on one data set, how much the choice of
110 +estimator matters relative to the choice of sample.
111 +
112 +The remainder of the paper is organised as follows.
113 +Section~\ref{sec:data} describes the data, the price-field diagnosis and
114 +the analysis sample. Section~\ref{sec:methodology} sets out the hedonic,
115 +quantile, spatial and machine-learning specifications and the inference
116 +used. Section~\ref{sec:results} reports the results,
117 +Section~\ref{sec:robustness} the robustness checks, and
118 +Section~\ref{sec:conclusion} concludes with limitations and directions
119 +for future work.
modified paper/sections/methodology.tex +188 −235
@@ -3,254 +3,207 @@
3 3 \label{sec:methodology}
4 4 % ==========================================================================
5 5
6 −\subsection{Hedonic Pricing Framework}
7 −
8 −Following \citet{Rosen1974}, we model the nightly listing price as a
9 −function of the listing's observable characteristics. Let $p_i$ denote the
10 −nightly price of listing $i$ and let $\mathbf{x}_i$ denote the vector of
11 −$K$ characteristics. The hedonic price function is:
12 −\begin{equation}
13 −p_i = P(\mathbf{x}_i) + \eps_i,
14 −\label{eq:hedonic_general}
15 −\end{equation}
16 −where $P(\cdot)$ maps the characteristic space into prices and
17 −$\eps_i$ is an idiosyncratic error term.
18 −
19 −We adopt a log-linear specification:
20 −\begin{equation}
21 −\ln p_i = \alpha + \boldsymbol{\beta}' \mathbf{x}_i + \eps_i,
22 −\label{eq:loglinear}
23 −\end{equation}
24 −where $\alpha$ is a constant, $\boldsymbol{\beta}$ is the $K \times 1$
25 −vector of hedonic coefficients, and $\eps_i \sim (0, \sigma^2_i)$ is
26 −mean-zero but potentially heteroskedastic. The log transformation
27 −accommodates the right-skewed price distribution, yields coefficients
28 −interpretable as approximate percentage changes, and imposes a
29 −multiplicative structure consistent with proportional interactions among
30 −characteristics.
31 −
32 −\subsection{Model Specification}
33 −
34 −The full hedonic equation expands the characteristic vector into seven
35 −attribute blocks:
36 −\begin{equation}
37 −\begin{aligned}
38 −\ln p_i = \; & \alpha
39 − + \boldsymbol{\beta}_S' \, \mathbf{S}_i
40 − + \boldsymbol{\beta}_A' \, \mathbf{A}_i
41 − + \boldsymbol{\beta}_H' \, \mathbf{H}_i
42 − + \boldsymbol{\beta}_R' \, \mathbf{R}_i \\
43 − & + \boldsymbol{\beta}_L' \, \mathbf{L}_i
44 − + \boldsymbol{\beta}_N' \, \mathbf{N}_i
45 − + \boldsymbol{\beta}_C' \, \mathbf{C}_i
46 − + \eps_i,
47 −\end{aligned}
48 −\label{eq:full_model}
49 −\end{equation}
50 −where $\mathbf{S}_i$ collects structural characteristics,
51 −$\mathbf{A}_i$ contains amenity indices,
52 −$\mathbf{H}_i$ captures host attributes,
53 −$\mathbf{R}_i$ comprises reputation variables,
54 −$\mathbf{L}_i$ includes locational controls,
55 −$\mathbf{N}_i$ represents text-derived features, and
56 −$\mathbf{C}_i$ denotes spatial context controls.
57 −
58 −\subsection{Feature Engineering}
59 −
60 −\textit{Structural features.} We include linear terms for bedrooms,
61 −bathrooms, and guest capacity, plus log-transformed counterparts
62 −($\log(1 + x)$). Per-guest ratios address the proportionality of space
63 −to capacity. Quadratic terms (accommodates$^2$, bedrooms$^2$,
64 −bathrooms$^2$) and interactions (accommodates $\times$ bedrooms,
65 −accommodates $\times$ bathrooms) capture non-linear and joint effects.
66 −
67 −\textit{Amenity features.} Six expert-weighted composite indices are
68 −constructed from 24 tracked amenity categories, with weights reflecting
69 −assumed market value (e.g., pool receives weight 2.0 in the luxury index;
70 −Wi-Fi receives weight 3.0 in the remote work index). All indices are
71 −normalized to $[0, 1]$.
72 −
73 −\textit{Host features.} Superhost status enters as a binary indicator. A
74 −multi-listing host indicator proxies for professionalization. An interaction
75 −term (Superhost $\times$ entire-home) tests whether the Superhost premium
76 −differs by listing type.
77 −
78 −\textit{Reputation features.} The overall review score (0--5) enters
79 −linearly. The number of reviews enters in log form. A composite reputation
80 −score combines normalized rating and review volume:
81 −\begin{equation}
82 −\text{reputation}_i = 0.6 \times \frac{\text{rating}_i}{5}
83 − + 0.4 \times \frac{\log(1 + \text{reviews}_i)}
84 − {\max_j \log(1 + \text{reviews}_j)}.
85 −\label{eq:reputation}
86 −\end{equation}
87 −
88 −\textit{Locational features.} Distance to the nearest city centre is
89 −computed using the Haversine formula:
6 +\subsection{Hedonic Price Function}
7 +\label{subsec:hedonic}
8 +
9 +Let $p_i$ denote the displayed nightly price of listing $i$ and
10 +$\mathbf{x}_i$ the vector of its observed characteristics. Following
11 +\citet{Rosen1974}, the hedonic price function $P(\cdot)$ maps
12 +characteristics into prices, and we approximate it by the semi-logarithmic
13 +form that dominates the housing and short-term rental literatures
14 +\citep{Malpezzi2003, Sirmans2005, WangNicolau2017}:
90 15 \begin{equation}
91 −d_{ij} = 2R \arcsin\!\left(
92 − \sqrt{\sin^2\!\left(\frac{\Delta\phi}{2}\right)
93 − + \cos\phi_i \cos\phi_j \sin^2\!\left(\frac{\Delta\lambda}{2}\right)}
94 −\right),
95 −\label{eq:haversine}
16 +\ln p_i = \alpha
17 + + \boldsymbol{\beta}_S' \mathbf{S}_i
18 + + \boldsymbol{\beta}_A' \mathbf{A}_i
19 + + \boldsymbol{\beta}_H' \mathbf{H}_i
20 + + \boldsymbol{\beta}_L' \mathbf{L}_i
21 + + \mu_{c(i)}
22 + + \eps_i ,
23 +\label{eq:hedonic}
96 24 \end{equation}
97 −where $R = 6{,}371$~km. Reference coordinates are provided for 22
98 −Quebec municipalities.
99 −
100 −\textit{Spatial context features.} Using a BallTree with haversine metric,
101 −we compute local listing density within 500m and 1~km, local average price
102 −within 500m and 1~km, and a $K$-means spatial cluster ($K = 20$).
103 −
104 −\textit{Text features.} From listing names and descriptions, we extract
105 −title length, seven bilingual keyword scores, and 10 TF-IDF/SVD components
106 −(sublinear term frequency, up to 5,000 features, unigrams and bigrams,
107 −dimensionality reduced via Truncated SVD capturing 16.98\% of variance).
108 −
109 −\subsection{OLS Estimation with Robust Inference}
110 −
111 −We estimate Equation~\eqref{eq:full_model} by OLS with
112 −heteroskedasticity-robust standard errors using the HC3 estimator:
25 +where $\mathbf{S}_i$ collects the structural variables ($\ln$ bedrooms,
26 +$\ln(1+\text{bathrooms})$, $\ln$ guest capacity, a shared-bathroom
27 +indicator, a studio indicator and five title-category indicators with
28 +\emph{Rental unit} as the reference), $\mathbf{A}_i$ the listing-level
29 +presentation variables ($\ln(1+\text{amenities})$, $\ln(1+\text{photos})$,
30 +pets allowed), $\mathbf{H}_i$ the host and reputation variables (Superhost,
31 +Guest Favourite, $\ln(1+\text{reviews})$, a rated indicator and the
32 +centred rating interacted with it), $\mathbf{L}_i$ the location variables
33 +($\ln(1+\text{km to the nearest centre})$ and $\ln(1+\text{listings within
34 +1 km})$), and $\mu_{c(i)}$ a fixed effect for the city or spatial cell
35 +$c(i)$ in which the listing is located. The error $\eps_i$ is mean zero
36 +conditional on the regressors but is allowed to be heteroskedastic and
37 +spatially correlated within cities.
38 +
39 +The semi-logarithmic form has three consequences for interpretation. For
40 +a continuous regressor entered in logarithms the coefficient is an
41 +elasticity. For a continuous regressor in levels, such as the rating,
42 +$100\,\beta$ is the approximate percentage change in price per unit. For
43 +an indicator variable the percentage premium is
113 44 \begin{equation}
114 −\widehat{\Var}(\hat{\boldsymbol{\beta}})_{\text{HC3}}
115 −= (\mathbf{X}'\mathbf{X})^{-1}
116 − \left( \sum_{i=1}^{N} \frac{\hat{u}_i^2}{(1 - h_{ii})^2}
117 − \mathbf{x}_i \mathbf{x}_i' \right)
118 − (\mathbf{X}'\mathbf{X})^{-1},
119 −\label{eq:hc3}
45 +g = 100\left[\exp\!\left(\hat{\beta} - \tfrac{1}{2}\widehat{\Var}(\hat{\beta})\right) - 1\right],
46 +\label{eq:kennedy}
120 47 \end{equation}
121 −where $h_{ii}$ is the $i$th diagonal element of the hat matrix
122 −$\mathbf{H} = \mathbf{X}(\mathbf{X}'\mathbf{X})^{-1}\mathbf{X}'$.
123 −
124 −\subsection{Nested Model Strategy}
125 −
126 −To assess the marginal explanatory power of each attribute block, we
127 −estimate nine nested models:
128 −%
129 −\begin{enumerate}[leftmargin=2em]
130 − \item[M1.] Structural characteristics only.
131 − \item[M2.] M1 + amenity bundle.
132 − \item[M3.] M2 + host attributes.
133 − \item[M4.] M3 + reputation and reviews.
134 − \item[M5.] M4 + locational controls.
135 − \item[M6.] M5 + neighbourhood (spatial cluster).
136 − \item[M7.] M6 + text-derived features.
137 − \item[M8.] M7 + spatial context controls.
138 − \item[M9.] Full hedonic model (identical to M8).
139 −\end{enumerate}
140 −%
141 −We compare models using $R^2$, adjusted $R^2$, AIC, BIC, RMSE, and MAE.
48 +the \citet{Kennedy1981} correction of the \citet{HalvorsenPalmquist1980}
49 +transformation, which removes the small-sample bias of
50 +$\exp(\hat{\beta}) - 1$ and is the form we report in the text. The
51 +coefficients in Equation~\eqref{eq:hedonic} are conditional associations
52 +between characteristics and asking prices in a cross-section; they are
53 +not marginal willingness to pay, which would require the stronger
54 +assumptions discussed by \citet{Kuminoff2010} and \citet{Bishop2020}, nor
55 +realised transaction prices.
56 +
57 +\subsection{Specifications and Inference}
58 +\label{subsec:specs}
59 +
60 +We estimate Equation~\eqref{eq:hedonic} by ordinary least squares in five
61 +nested specifications: M1 contains the structural block only; M2 adds the
62 +presentation block; M3 the host and reputation block; M4 the two location
63 +variables; and M5 the city fixed effects. Cities with at least 15 listings
64 +in the analysis sample receive their own effect; the remaining listings,
65 +which are scattered across several hundred small municipalities, are
66 +grouped into 25 spatial cells obtained by $k$-means clustering of their
67 +projected coordinates, so that every listing belongs to exactly one
68 +fixed-effect group. The fixed effects absorb all between-city variation in
69 +prices, including tourism demand, seasonality of the local market and
70 +regulation, and the remaining coefficients are identified from
71 +within-city variation.
72 +
73 +Standard errors are heteroskedasticity-robust (HC3,
74 +\citealp{MacKinnonWhite1985}) in all specifications. Because the
75 +regressors of neighbouring listings are correlated and the error term is
76 +likely to be spatially correlated, we also report standard errors
77 +clustered by fixed-effect group for M5 \citep{CameronMiller2015}, and we
78 +re-estimate M5 with 60 finer spatial cells as the fixed-effect unit in the
79 +robustness section. Multicollinearity among the capacity variables is
80 +monitored through variance inflation factors, and block significance is
81 +assessed with robust $F$ tests.
142 82
143 83 \subsection{Quantile Regression}
84 +\label{subsec:quantile_methods}
144 85
145 −To explore heterogeneity across the price distribution, we estimate
146 −quantile regressions \citep{KoenkerBassett1978} at
147 −$\tau \in \{0.10, 0.25, 0.50, 0.75, 0.90\}$:
86 +To examine whether implicit prices differ between budget and premium
87 +listings we estimate the conditional quantile function of
88 +\citet{KoenkerBassett1978},
148 89 \begin{equation}
149 −Q_\tau(\ln p_i \mid \mathbf{x}_i)
150 −= \alpha_\tau + \boldsymbol{\beta}_\tau' \, \mathbf{x}_i,
90 +Q_\tau(\ln p_i \mid \mathbf{x}_i) = \alpha_\tau + \boldsymbol{\beta}_\tau' \mathbf{x}_i + \mu_{c(i),\tau},
91 +\qquad \tau \in \{0.10, 0.25, 0.50, 0.75, 0.90\},
151 92 \label{eq:quantile}
152 93 \end{equation}
153 −solved by minimizing the asymmetric check function:
154 −\begin{equation}
155 −\min_{\alpha_\tau, \boldsymbol{\beta}_\tau}
156 −\sum_{i=1}^{N} \rho_\tau\!\left(\ln p_i - \alpha_\tau
157 − - \boldsymbol{\beta}_\tau' \mathbf{x}_i \right),
158 −\quad
159 −\rho_\tau(u) = u \left(\tau - \mathbf{1}(u < 0)\right).
160 −\label{eq:check_function}
161 −\end{equation}
162 −Model fit is assessed via the Koenker--Bassett pseudo-$R^2$:
163 −\begin{equation}
164 −\text{pseudo-}R^2_\tau = 1
165 − - \frac{\sum_i \rho_\tau(\hat{u}_i)}
166 − {\sum_i \rho_\tau(\ln p_i - \hat{Q}_\tau^{(0)})}.
167 −\label{eq:pseudoR2}
168 −\end{equation}
169 −
170 −\subsection{Machine Learning Models}
171 −
172 −We complement the econometric analysis with seven supervised learning
173 −algorithms trained on the same feature set using an 80/20 train/test
174 −split ($N_{\text{train}} = 1{,}524$, $N_{\text{test}} = 382$):
175 −ElasticNet \citep{ZouHastie2005}, Random Forest ($B = 500$ trees)
176 −\citep{Breiman2001}, Gradient Boosting (500 trees, learning rate 0.05)
177 −\citep{Friedman2001}, XGBoost (500 estimators, depth 6)
178 −\citep{ChenGuestrin2016}, LightGBM (500 estimators, 31 leaves),
179 −CatBoost (500 iterations, depth 6), and a Generalized Additive Model.
180 −Predictive performance is evaluated using $R^2$, RMSE, MAE, and MAPE.
181 −
182 −\subsection{SHAP Interpretability}
183 −
184 −To reconcile predictive power with interpretability, we employ
185 −SHAP \citep{Lundberg2017}. For each prediction $\hat{f}(\mathbf{x}_i)$,
186 −SHAP decomposes the deviation from the baseline into additive feature
187 −contributions:
188 −\begin{equation}
189 −\hat{f}(\mathbf{x}_i) = \phi_0
190 − + \sum_{k=1}^{K} \phi_k(\mathbf{x}_i),
191 −\label{eq:shap}
192 −\end{equation}
193 −where $\phi_0 = \E[\hat{f}]$ and $\phi_k(\mathbf{x}_i)$ is the SHAP
194 −value of feature $k$ for observation $i$. The mean absolute SHAP value
195 −$\overline{|\phi_k|}$ provides a global importance ranking.
94 +with the full M5 regressor set, by minimising the check-function loss
95 +$\sum_i \rho_\tau(\ln p_i - \alpha_\tau - \boldsymbol{\beta}_\tau'\mathbf{x}_i - \mu_{c(i),\tau})$,
96 +$\rho_\tau(u) = u\,(\tau - \mathbf{1}\{u<0\})$
97 +\citep{KoenkerHallock2001}. Standard errors use the kernel estimate of the
98 +sparsity function. Goodness of fit is the Koenker--Machado pseudo-$R^2$,
99 +one minus the ratio of the minimised loss to the loss of the
100 +unconditional quantile. Because the coefficients at different quantiles
101 +are estimated from the same sample, differences between the
102 +$\tau = 0.90$ and $\tau = 0.10$ coefficients are tested with a paired
103 +bootstrap of 100 replications in which both quantile regressions are
104 +re-estimated on each resample.
196 105
197 106 \subsection{Spatial Econometric Models}
198 −
199 −We construct a row-standardized $k$-nearest-neighbours weight matrix
200 −$\mathbf{W}$ with $k = 5$ and estimate three spatial models
201 −\citep{LeSagePace2009, Anselin1988}:
202 −
203 −\textit{Spatial Lag Model (SLM):}
107 +\label{subsec:spatial_methods}
108 +
109 +Listings cluster in space and their prices may depend on neighbours'
110 +prices or on spatially correlated unobservables. We construct a
111 +row-standardised $k$-nearest-neighbour weights matrix $\mathbf{W}$
112 +($k = 5$, with $k = 10$ as a check) from coordinates projected to
113 +kilometres, so that the anisotropy of degrees of longitude at Quebec's
114 +latitude does not distort distances, and we test the OLS residuals of M4
115 +and M5 for spatial autocorrelation with Moran's $I$,
204 116 \begin{equation}
205 −\ln \mathbf{p} = \rho \, \mathbf{W} \ln \mathbf{p}
206 − + \mathbf{X} \boldsymbol{\beta} + \boldsymbol{\eps},
207 −\label{eq:slm}
117 +I = \frac{N}{\sum_i \sum_j w_{ij}}\,
118 + \frac{\sum_i \sum_j w_{ij}\,\hat{u}_i \hat{u}_j}{\sum_i \hat{u}_i^2},
119 +\label{eq:moran}
208 120 \end{equation}
209 −where $\rho$ captures endogenous spatial interaction.
210 −
211 −\textit{Spatial Error Model (SEM):}
212 −\begin{equation}
213 −\ln \mathbf{p} = \mathbf{X} \boldsymbol{\beta} + \mathbf{u}, \quad
214 −\mathbf{u} = \lambda \, \mathbf{W} \mathbf{u}
215 − + \boldsymbol{\eps},
216 −\label{eq:sem}
217 −\end{equation}
218 −where $\lambda$ captures spatial autocorrelation in the errors.
219 −
220 −\textit{Spatial Durbin Model (SDM):}
221 −\begin{equation}
222 −\ln \mathbf{p} = \rho \, \mathbf{W} \ln \mathbf{p}
223 − + \mathbf{X} \boldsymbol{\beta}
224 − + \mathbf{W} \mathbf{X} \boldsymbol{\theta}
225 − + \boldsymbol{\eps},
226 −\label{eq:sdm}
227 −\end{equation}
228 −which nests both SLM and SEM under parameter restrictions and allows
229 −neighbours' characteristics to exert direct spillover effects.
230 −
231 −Spatial dependence is tested using Moran's $I$ on the OLS residuals:
232 −\begin{equation}
233 −I = \frac{N}{\sum_{i}\sum_{j} w_{ij}}
234 − \frac{\sum_{i}\sum_{j} w_{ij}
235 − (\hat{u}_i - \bar{\hat{u}})(\hat{u}_j - \bar{\hat{u}})}
236 − {\sum_{i} (\hat{u}_i - \bar{\hat{u}})^2}.
237 −\label{eq:moranI}
238 −\end{equation}
239 −
240 −\subsection{Price Decomposition}
241 −
242 −For listing $i$, the predicted log-price decomposes as:
121 +with inference from 999 random permutations. We then estimate by maximum
122 +likelihood \citep{Anselin1988, LeSagePace2009} the spatial lag model
123 +(SAR), the spatial error model (SEM) and the spatial Durbin model (SDM),
124 +\begin{align}
125 +\text{SAR:}\quad & \ln \mathbf{p} = \rho\,\mathbf{W}\ln\mathbf{p} + \mathbf{X}\boldsymbol{\beta} + \boldsymbol{\eps}, \label{eq:sar}\\
126 +\text{SEM:}\quad & \ln \mathbf{p} = \mathbf{X}\boldsymbol{\beta} + \mathbf{u}, \qquad \mathbf{u} = \lambda\,\mathbf{W}\mathbf{u} + \boldsymbol{\eps}, \label{eq:sem}\\
127 +\text{SDM:}\quad & \ln \mathbf{p} = \rho\,\mathbf{W}\ln\mathbf{p} + \mathbf{X}\boldsymbol{\beta} + \mathbf{W}\mathbf{X}\boldsymbol{\theta} + \boldsymbol{\eps}, \label{eq:sdm}
128 +\end{align}
129 +using the M4 regressor set, since the city fixed effects and the spatial
130 +lag compete for the same between-city variation. The SDM nests the SAR
131 +($\boldsymbol{\theta} = \mathbf{0}$) and the SEM
132 +($\boldsymbol{\theta} = -\rho\boldsymbol{\beta}$), and we use a
133 +likelihood-ratio test of the first restriction \citep{Elhorst2010}.
134 +
135 +In models with a spatial lag the coefficients are not marginal effects.
136 +Writing $\mathbf{S}_k(\mathbf{W}) = (\mathbf{I} - \rho\mathbf{W})^{-1}(\mathbf{I}\beta_k + \mathbf{W}\theta_k)$
137 +for regressor $k$ (with $\theta_k = 0$ in the SAR), the average direct
138 +effect is $N^{-1}\,\mathrm{tr}\,\mathbf{S}_k(\mathbf{W})$, the average
139 +total effect is $N^{-1}\,\boldsymbol{\iota}'\mathbf{S}_k(\mathbf{W})\boldsymbol{\iota}$,
140 +and the indirect (spillover) effect is their difference
141 +\citep{LeSagePace2009}. We compute the three summary measures exactly
142 +from the dense inverse and obtain their standard errors from 300 draws
143 +of the parameters from their estimated asymptotic distribution.
144 +
145 +\subsection{Machine Learning Benchmarks and Interpretation}
146 +\label{subsec:ml_methods}
147 +
148 +The log-linear form imposes additive, constant implicit prices. To
149 +measure how much predictive accuracy this restriction costs we compare
150 +the M5 specification with an elastic net \citep{ZouHastie2005}, a random
151 +forest \citep{Breiman2001}, gradient boosting \citep{Friedman2001},
152 +XGBoost \citep{ChenGuestrin2016} and LightGBM, all trained on the same
153 +regressors, including the fixed-effect indicators. Performance is
154 +measured out of sample by five-fold cross-validation in two designs:
155 +random folds, which is the usual benchmark, and spatially blocked folds in
156 +which the 20 spatial clusters of listings are assigned to folds as whole
157 +blocks \citep{Roberts2017}. The second design asks whether a model trained
158 +on some areas predicts prices in areas it has never seen, which is the
159 +relevant question for an automated valuation tool and a stricter test of
160 +generalisation when observations are spatially dependent. We report the
161 +out-of-sample $R^2$, root mean squared error and mean absolute error on the
162 +log scale and the median absolute percentage error (MdAPE) on the price
163 +scale, $\operatorname{median}_i |\exp(\hat{y}_i) - p_i| / p_i$. The
164 +first version of this paper reported a mean absolute percentage error
165 +computed on log prices, which is not interpretable as a price error and
166 +is not used here.
167 +
168 +The best learner is interpreted with SHAP values \citep{Lundberg2017},
169 +computed exactly for tree ensembles \citep{Lundberg2020}. For a prediction
170 +$\hat f(\mathbf{x}_i)$ the SHAP values $\phi_{ik}$ satisfy
171 +$\hat f(\mathbf{x}_i) = \phi_0 + \sum_k \phi_{ik}$ with
172 +$\phi_0 = \E[\hat f]$, and the mean absolute value
173 +$\overline{|\phi_k|} = N^{-1}\sum_i |\phi_{ik}|$ ranks features by their
174 +average contribution to predicted log prices. SHAP values describe the
175 +fitted model, not the data-generating process; they are attribution
176 +weights for associations captured by the learner and carry no causal
177 +content.
178 +
179 +\subsection{Identifying the Nightly-Price Regime}
180 +\label{subsec:mixture_methods}
181 +
182 +Section~\ref{sec:data} shows that the displayed price field mixes
183 +nightly prices with total prices of multi-night stays. A price threshold
184 +separates the two regimes imperfectly because the stay total of a cheap
185 +listing can fall below the threshold while the nightly price of a large
186 +chalet can exceed it. We therefore model the regime explicitly with a
187 +two-component mixture of hedonic regressions with common slopes,
243 188 \begin{equation}
244 −\widehat{\ln p_i}
245 −= \hat{\alpha}
246 − + \underbrace{\hat{\boldsymbol{\beta}}_S' \mathbf{S}_i}_{\text{property}}
247 − + \underbrace{\hat{\boldsymbol{\beta}}_A' \mathbf{A}_i}_{\text{amenity}}
248 − + \underbrace{\hat{\boldsymbol{\beta}}_H' \mathbf{H}_i}_{\text{host}}
249 − + \underbrace{\hat{\boldsymbol{\beta}}_R' \mathbf{R}_i}_{\text{review}}
250 − + \underbrace{\hat{\boldsymbol{\beta}}_L' \mathbf{L}_i}_{\text{location}}
251 − + \underbrace{\hat{\boldsymbol{\beta}}_N' \mathbf{N}_i}_{\text{text}}
252 − + \underbrace{\hat{\boldsymbol{\beta}}_C' \mathbf{C}_i}_{\text{spatial}}.
253 −\label{eq:decomposition}
189 +\ln p_i = \mathbf{x}_i'\boldsymbol{\beta} + \delta\, z_i + \eps_i,
190 +\qquad \eps_i \mid z_i \sim \mathcal{N}(0, \sigma^2_{z_i}),
191 +\qquad \Pr(z_i = 1 \mid \mathbf{w}_i) = \Lambda(\mathbf{w}_i'\boldsymbol{\gamma}),
192 +\label{eq:mixture}
254 193 \end{equation}
255 −This decomposition provides hosts with a transparent breakdown of how the
256 −market values each attribute of their listing.
194 +where $z_i = 1$ indicates the stay regime, $\delta$ is the log of the
195 +typical stay length that the displayed price covers, the regime-specific
196 +variance allows stay lengths to vary across listings, and the regime
197 +probability depends through a logistic link on characteristics
198 +$\mathbf{w}_i$ (Montreal location, review count, capacity, Superhost
199 +status and the hotel and chalet categories) that the descriptive analysis
200 +identifies as predictors of the second mode. The model is estimated by
201 +the EM algorithm, initialised at the \$1,000 rule; the E-step computes
202 +the posterior probability $\hat p_i = \Pr(z_i = 1 \mid \ln p_i,
203 +\mathbf{x}_i, \mathbf{w}_i)$ and the M-step updates
204 +$(\boldsymbol{\beta}, \delta)$ by weighted least squares on the stacked
205 +data, $(\sigma_0, \sigma_1)$ from the weighted residuals and
206 +$\boldsymbol{\gamma}$ by a weighted logistic regression. Listings with
207 +$\hat p_i < 0.5$ constitute the analysis sample used in all subsequent
208 +estimation; the robustness section varies the cut-off, re-weights by
209 +$1 - \hat p_i$ and compares with the simple price-threshold rules.
modified paper/sections/results.tex +370 −280
@@ -3,372 +3,462 @@
3 3 \label{sec:results}
4 4 % ==========================================================================
5 5
6 −This section reports the empirical findings. We begin with the nested OLS
7 −models, then present attribute-specific results, quantile regression
8 −estimates, machine learning comparisons, spatial model estimates, and the
9 −price decomposition.
10 −
11 6 % ------------------------------------------------------------------
12 7 \subsection{Nested Hedonic Models}
13 8 \label{subsec:nested}
14 9 % ------------------------------------------------------------------
15 10
16 −Table~\ref{tab:nested} reports the fit statistics for the nine nested
17 −OLS models. The structural-only baseline (M1) yields $R^2 = 0.052$,
18 −confirming that physical characteristics alone explain a modest share of
19 −hedonic price variation. Adding amenity indices (M2) raises $R^2$
20 −marginally to 0.057. Host attributes (M3) contribute a larger increment
21 −($R^2 = 0.098$). Reputation and review variables (M4) produce the single
22 −largest gain, lifting $R^2$ to 0.187. Location controls (M5),
23 −neighbourhood effects (M6), and text features (M7) provide successive
24 −improvements. The full model incorporating spatial context controls
25 −(M8/M9) achieves $R^2 = 0.274$ (adjusted $R^2 = 0.254$) on $N = 1{,}906$.
11 +Table~\ref{tab:nested} reports the five nested specifications. The
12 +structural block alone (M1) explains 44\% of the variance of log prices
13 +in the analysis sample, a figure in line with single-city Airbnb studies
14 +\citep{WangNicolau2017, ChenXie2017, Gyodi2021} and far above the 5\%
15 +obtained on the contaminated price field. Adding the presentation
16 +variables (M2) and the host and reputation variables (M3) raises $R^2$
17 +by about one percentage point each; the two location variables (M4) add
18 +two points, and the city and cell fixed effects (M5) a further three, to
19 +0.509 (adjusted 0.495). The fixed effects alone explain
20 +13\% of the variance, so the structural and listing-level
21 +characteristics carry most of the explanatory power and location acts
22 +mainly through the composition of listings across places rather than
23 +through large city-level price differences. The root mean squared error
24 +of M5 is 0.475 log points, which is a typical prediction error of about
25 +40\% of the nightly price for an individual listing.
26 26
27 27 \begin{table}[!htbp]
28 28 \centering
29 −\caption{Nested Model Comparison}
29 +\caption{Nested Hedonic Specifications, Dependent Variable $\ln$(Displayed Nightly Price)}
30 30 \label{tab:nested}
31 31 \begin{threeparttable}
32 −\begin{tabular}{llrrrrrr}
33 −\toprule
34 − & Variables Added & $N$ & $K$ & $R^2$ & Adj.\ $R^2$ & RMSE & AIC \\
35 −\midrule
36 −M1 & Structural & 3,412 & 15 & 0.052 & 0.048 & 1.380 & 11,911 \\
37 −M2 & + Amenities & 3,412 & 22 & 0.057 & 0.052 & 1.376 & 11,904 \\
38 −M3 & + Host & 3,412 & 26 & 0.098 & 0.092 & 1.346 & 11,760 \\
39 −M4 & + Reviews & 2,861 & 33 & 0.187 & 0.178 & 1.233 & 9,382 \\
40 −M5 & + Location & 2,857 & 36 & 0.198 & 0.188 & 1.224 & 9,336 \\
41 −M6 & + Neighbourhood & 2,857 & 37 & 0.198 & 0.188 & 1.224 & 9,338 \\
42 −M7 & + NLP/Text & 2,857 & 46 & 0.225 & 0.213 & 1.204 & 9,259 \\
43 −M8 & + Spatial & 1,906 & 50 & 0.274 & 0.254 & 1.169 & 6,103 \\
44 −M9 & Full Hedonic & 1,906 & 50 & 0.274 & 0.254 & 1.169 & 6,103 \\
45 −\bottomrule
46 −\end{tabular}
47 −\begin{tablenotes}
48 32 \footnotesize
49 −\item \textit{Notes:} OLS estimates with HC3 robust standard errors.
50 −AIC is the Akaike Information Criterion. RMSE is root mean squared error.
51 −$K$ denotes the number of estimated parameters including the intercept.
52 −Sample sizes differ across models due to listwise deletion of missing
53 −values in added covariates.
54 −\end{tablenotes}
55 −\end{threeparttable}
56 −\end{table}
57 −
58 −The AIC declines monotonically from 11,911 (M1) to 6,103 (M9), and
59 −the RMSE decreases from 1.380 to 1.169, a 15.3\% reduction.
60 −
61 −% ------------------------------------------------------------------
62 −\subsection{Full Hedonic Model Estimates}
63 −\label{subsec:full_model}
64 −% ------------------------------------------------------------------
65 −
66 −Table~\ref{tab:hedonic} presents selected coefficient estimates for the
67 −full hedonic model (M9). Coefficients are converted to percentage premiums
68 −via $(\exp(\hat{\beta}) - 1) \times 100$.
69 −
70 −\begin{table}[!htbp]
71 −\centering
72 −\caption{Full Hedonic Model: Selected Coefficient Estimates (M9)}
73 −\label{tab:hedonic}
74 −\begin{threeparttable}
75 −\begin{tabular}{lrrrr}
76 −\toprule
77 −Variable & Coeff. & Std.\ Err. & $p$-value & Premium (\%) \\
78 −\midrule
79 −\multicolumn{5}{l}{\textit{Structural characteristics}} \\
80 −Bedrooms & 1.141*** & (0.346) & 0.001 & +212.9 \\
81 −Log bedrooms & $-$2.053*** & (0.770) & 0.008 & $-$87.2 \\
82 −Bathrooms sq. & 0.028** & (0.013) & 0.035 & +2.9 \\
83 −Bedrooms sq. & $-$0.063*** & (0.020) & 0.002 & $-$6.1 \\
84 −\midrule
85 −\multicolumn{5}{l}{\textit{Amenity indices}} \\
86 −Amenity richness & $-$0.269** & (0.106) & 0.011 & $-$23.6 \\
87 −Business travel & $-$1.156** & (0.558) & 0.039 & $-$68.5 \\
88 −\midrule
89 −\multicolumn{5}{l}{\textit{Reviews and reputation}} \\
90 −Rating & 1.052** & (0.495) & 0.033 & +186.2 \\
91 −Has reviews (=1) & 9.511** & (3.741) & 0.011 & $>$1,000 \\
92 −Log reviews & $-$0.400*** & (0.102) & 0.000 & $-$33.0 \\
93 −Num.\ reviews & 0.003*** & (0.001) & 0.008 & +0.3 \\
94 −\midrule
95 −\multicolumn{5}{l}{\textit{Location}} \\
96 −Latitude & $-$0.090** & (0.045) & 0.048 & $-$8.6 \\
97 −\midrule
98 −\multicolumn{5}{l}{\textit{Spatial controls}} \\
99 −Local density 500m & $-$0.008*** & (0.003) & 0.008 & $-$0.8 \\
100 −Local density 1km & 0.003*** & (0.001) & 0.006 & +0.3 \\
101 −Local avg.\ price 500m & 0.00025*** & (0.00007) & 0.000 & +0.025 \\
102 −Spatial cluster & $-$0.013*** & (0.005) & 0.008 & $-$1.3 \\
103 −\midrule
104 −\multicolumn{5}{l}{\textit{Text features}} \\
105 −Text embed.\ 0 & 2.800*** & (0.647) & 0.000 & $>$1,000 \\
106 −\midrule
107 −Observations & \multicolumn{4}{c}{1,906} \\
108 −$R^2$ & \multicolumn{4}{c}{0.274} \\
109 −Adj.\ $R^2$ & \multicolumn{4}{c}{0.254} \\
110 −AIC & \multicolumn{4}{c}{6,103} \\
111 −RMSE & \multicolumn{4}{c}{1.169} \\
112 −\bottomrule
113 −\end{tabular}
33 +\setlength{\tabcolsep}{4pt}
34 +\input{../results/tables/rev_ols_nested.tex}
114 35 \begin{tablenotes}
115 36 \footnotesize
116 −\item \textit{Notes:} Standard errors in parentheses are
117 −heteroskedasticity-robust (HC3). ***, **, and * indicate statistical
118 −significance at the 1\%, 5\%, and 10\% levels, respectively. Premium
119 −(\%) is computed as $100 \times (\exp(\hat{\beta}) - 1)$. The full set
120 −of 50 coefficients is reported in Table~\ref{tab:app_full_reg}
121 −in the Appendix.
37 +\item \textit{Notes:} OLS on the analysis sample ($N = 2{,}480$).
38 +Columns (1)--(5) report HC3 standard errors in parentheses; column
39 +(5$'$) repeats M5 with standard errors clustered by fixed-effect group
40 +(51 groups) in brackets. The reference title category is
41 +\emph{Rental unit}. Rating is centred at 4.8 and set to zero for unrated
42 +listings, so the ``Rated'' indicator is the premium of a listing rated
43 +4.8 over an unrated one. City / cell fixed effects: one indicator per
44 +municipality with at least 15 listings (26 cities) and 25
45 +$k$-means cells for the remaining listings. ***, ** and * denote
46 +significance at the 1, 5 and 10\% levels.
122 47 \end{tablenotes}
123 48 \end{threeparttable}
124 49 \end{table}
125 50
126 −% ------------------------------------------------------------------
127 −\subsection{Structural Characteristics}
128 −\label{subsec:structural}
129 −% ------------------------------------------------------------------
130 −
131 −Bedrooms emerge as the strongest structural predictor. The positive linear
132 −coefficient ($\hat{\beta} = 1.141$, $p < 0.001$) combined with the
133 −negative log-bedrooms term ($\hat{\beta} = -2.053$, $p = 0.008$) implies
134 −a concave bedroom--price relationship: each additional bedroom raises the
135 −price at a diminishing rate. The positive bathrooms-squared coefficient
136 −($\hat{\beta} = 0.028$, $p = 0.035$) indicates a convex relationship,
137 −reflecting the high value of multiple bathrooms in larger properties.
51 +The coefficients are stable across specifications, which indicates that
52 +the omitted-variable bias from leaving out reputation or location is
53 +small for the structural variables. Clustering the standard errors by
54 +fixed-effect group raises them by 20 to 60\% for the capacity and
55 +location variables and leaves the inference qualitatively unchanged,
56 +except that the bedroom elasticity falls from the 1\% to the 5\% level
57 +and the rating coefficient becomes more precise. Variance inflation
58 +factors in M4 peak at 4.2 (for $\ln$ bedrooms), so the capacity
59 +variables, although correlated, are separately identified
60 +(Appendix Table~\ref{tab:app_vif}).
138 61
139 62 % ------------------------------------------------------------------
140 −\subsection{Amenity Effects}
141 −\label{subsec:amenities}
63 +\subsection{Capacity, Type and Presentation}
64 +\label{subsec:structural}
142 65 % ------------------------------------------------------------------
143 66
144 −The amenity richness index carries a negative coefficient
145 −($\hat{\beta} = -0.269$, $p = 0.011$), implying a 23.6\% discount.
146 −This likely reflects composition: budget-oriented urban listings tend
147 −to offer many standard amenities, while premium rural properties offer
148 −fewer total but higher-value features. The business travel index is
149 −significantly negative ($-68.5$\%), consistent with competitive pricing
150 −dynamics in the urban short-stay market.
67 +Capacity is priced through three channels. Holding bedrooms and
68 +bathrooms constant, a 10\% increase in guest capacity is associated with
69 +a 3.3\% higher price (elasticity 0.331, HC3 standard error 0.037);
70 +holding capacity constant, a 10\% increase in one plus the bathroom
71 +count is associated with a 4.4\% higher price (0.437, 0.070), and a 10\%
72 +increase in bedrooms with a 1.6\% higher price (0.160, 0.042). The
73 +bedroom elasticity is modest because capacity and bathrooms absorb most
74 +of the size effect; in M1 without the other capacity variables it would
75 +be far larger. A shared bathroom, which in these data identifies the
76 +room-in-a-home segment that the missing room-type field would otherwise
77 +have captured, carries a premium of
78 +$g = 100[\exp(-0.385 - \tfrac{1}{2}0.053^2) - 1] = -32\%$ by
79 +Equation~\eqref{eq:kennedy}, the largest single implicit price in the
80 +model. Studios are priced 16\% above an otherwise equivalent
81 +one-bedroom listing of the same capacity, which reflects their urban
82 +location and the fact that a studio of given capacity is a complete
83 +dwelling rather than a room.
84 +
85 +Title categories matter less than their raw price differences in
86 +Table~\ref{tab:price_category} suggest. Without location controls
87 +(M1--M3) no category differs significantly from rental units; once
88 +distance and density are held fixed (M4) and especially within cities
89 +(M5), chalets, cottages and cabins are priced 10\% above rental units of
90 +the same capacity (Kennedy-corrected premium 10.3\%, $p < 0.01$) and
91 +houses 8\% above ($p < 0.05$), while condominiums and lofts, hotel rooms
92 +and unconventional listings are not significantly different. The
93 +reversal between M3 and M4 arises because chalets are located where
94 +listings are sparse and far from city centres, two attributes that are
95 +themselves priced; the within-city chalet premium is the better estimate
96 +of the type's implicit price.
97 +
98 +Among the presentation variables the number of photos is the most
99 +robust: a 10\% increase in one plus the photo count is associated with a
100 +0.9\% higher price in every specification. The amenity count has a
101 +smaller and less stable coefficient (elasticity 0.09 with fixed effects,
102 +$p < 0.05$), and allowing pets is associated with a price about 4\%
103 +lower, significant at the 10\% level. The first version of this paper
104 +reported large negative ``amenity index'' effects; those indices were
105 +noise and the amenity count, which is the only amenity information in
106 +the data, is positively priced.
151 107
152 108 % ------------------------------------------------------------------
153 −\subsection{Review and Reputation Effects}
109 +\subsection{Reputation Signals}
154 110 \label{subsec:reviews}
155 111 % ------------------------------------------------------------------
156 112
157 −The review score has a positive and significant effect
158 −($\hat{\beta} = 1.052$, $p = 0.033$). Given the compressed rating
159 −distribution (mean~=~4.80, $\sigma$~=~0.23), a 0.1-point improvement
160 −corresponds to approximately an 11.1\% premium. The binary ``has
161 −reviews'' indicator ($\hat{\beta} = 9.511$, $p = 0.011$) reflects the
162 −sharp distinction between reviewed listings with established credibility
163 −and unreviewed new listings. The log-reviews coefficient is negative
164 −($-0.400$), while the linear count is positive ($0.003$), producing a
165 −concave profile: initial reviews boost prices, but heavily reviewed
166 −listings tend to be lower-priced high-turnover accommodations.
113 +The reputation block adds little to the fit, and its coefficients are
114 +small relative to the capacity effects. The displayed rating is the one
115 +reputation variable with a sizeable and precisely estimated coefficient:
116 +among rated listings, each additional point of rating is associated with
117 +a 34\% higher price (0.337, standard error 0.068 in M5), so that the
118 +typical spread between a listing rated 4.6 and one rated 5.0 corresponds
119 +to about 14\%. Because ratings are compressed near the top of the scale,
120 +with a tenth percentile of 4.57 \citep[the pattern documented
121 +by][]{Zervas2021}, this coefficient is identified from small differences
122 +and should be read as the price distance between the lower tail and the
123 +mass of near-perfect ratings, not as a linear effect across the whole
124 +scale. Unrated listings, mostly new ones, are priced 4\% below rated
125 +listings at 4.8, a difference that is not significant.
126 +
127 +Superhost status and the Guest Favourite badge carry no premium once
128 +capacity, type and location are controlled: the Superhost coefficient is
129 +0.023 (standard error 0.025) and the Guest Favourite coefficient
130 +$-0.035$ (0.027). Both badges are strongly associated with price in the
131 +raw data, but in the direction of the stay-price regime (Appendix
132 +Table~\ref{tab:app_stay_logit}), not of the nightly price. This null is
133 +consistent with the mixed evidence in the literature, where
134 +\citet{Teubner2017} and \citet{Gibbs2018} find Superhost premia of a few
135 +percent in some cities and none in others, and with the view that the
136 +badge rewards responsiveness and reliability rather than quality that
137 +guests pay for. The number of reviews is likewise unrelated to price on
138 +average (0.015, 0.010); the quantile results below show that this
139 +average conceals opposite signs at the two ends of the distribution.
140 +Figure~\ref{fig:partials} displays the partial relationship between the
141 +rating and log price and between distance to the nearest centre and log
142 +price as binned partial residuals from M4.
167 143
168 144 \begin{figure}[!htbp]
169 145 \centering
170 −\includegraphics[width=0.85\textwidth]{07_review_score_premium.png}
171 −\caption{Review Score Premium}
172 −\label{fig:review_premium}
146 +\includegraphics[width=0.95\textwidth]{rev_fig_partials.pdf}
147 +\caption{Partial Relationships: Distance to Centre and Rating}
148 +\label{fig:partials}
173 149 \begin{minipage}{0.9\textwidth}
174 150 \footnotesize
175 −\textit{Notes:} Left panel: scatter plot with OLS trend line. Right
176 −panel: binned means with 95\% confidence intervals.
151 +\textit{Notes:} Binned means (20 quantile bins) of the partial residual
152 +$\hat u_i + \hat\beta_k x_{ik}$ from specification M4, with 95\%
153 +confidence intervals. Left: distance to the nearest of 22 reference
154 +centres (symmetric-log axis). Right: displayed rating, rated listings
155 +only.
177 156 \end{minipage}
178 157 \end{figure}
179 158
180 159 % ------------------------------------------------------------------
181 −\subsection{Location Gradient}
160 +\subsection{Location}
182 161 \label{subsec:location}
183 162 % ------------------------------------------------------------------
184 163
185 −Latitude enters negatively ($\hat{\beta} = -0.090$, $p = 0.048$),
186 −indicating that more northern listings command lower prices. Local
187 −density within 500m is negatively associated with price
188 −($\hat{\beta} = -0.008$), consistent with competitive pressure,
189 −while density at 1~km is positive ($\hat{\beta} = 0.003$), suggesting
190 −agglomeration effects dominate beyond the immediate competitive radius.
191 −Local average price within 500m is highly significant
192 −($\hat{\beta} = 0.00025$, $p < 0.001$), confirming spatial price
193 −contagion.
164 +The two location variables behave as the urban-economics literature
165 +predicts once the sample is restricted to nightly prices. Local density
166 +is positively priced: a 10\% increase in one plus the number of listings
167 +within 1~km is associated with a 0.6\% higher price (0.064, 0.013 with
168 +fixed effects), the opposite of the ``competitive pressure'' reading in
169 +the first version of this paper and consistent with density proxying
170 +for centrality and amenity within cities. Distance to the nearest
171 +reference centre has a small negative coefficient that is significant
172 +only at the 10\% level with fixed effects ($-0.035$, 0.019); across the
173 +province, distance mixes the within-city gradient with the fact that
174 +resort listings are far from any city centre and expensive, which the
175 +category and density variables partly absorb. The fixed effects
176 +themselves are jointly significant (robust $F$ test,
177 +$p < 0.001$), and the robustness section shows that finer spatial cells
178 +leave the listing-level coefficients essentially unchanged.
179 +
180 +% ------------------------------------------------------------------
181 +\subsection{Quantile Regression}
182 +\label{subsec:quantile}
183 +% ------------------------------------------------------------------
184 +
185 +Table~\ref{tab:quantile} and Figure~\ref{fig:quantile} report the
186 +quantile estimates. The pseudo-$R^2$ rises from 0.278 at $\tau = 0.10$
187 +to 0.405 at $\tau = 0.90$: observed characteristics explain more of the
188 +variation among expensive listings than among cheap ones, the reverse of
189 +what the first version reported on the contaminated field.
190 +
191 +\begin{table}[!htbp]
192 +\centering
193 +\caption{Quantile Regression Estimates, Specification M5}
194 +\label{tab:quantile}
195 +\begin{threeparttable}
196 +\footnotesize
197 +\setlength{\tabcolsep}{4pt}
198 +\input{../results/tables/rev_quantile.tex}
199 +\begin{tablenotes}
200 +\footnotesize
201 +\item \textit{Notes:} Analysis sample ($N = 2{,}480$). Column OLS
202 +repeats M5 (HC3 standard errors); quantile columns report kernel-based
203 +standard errors. All regressions include the city / cell fixed effects
204 +and the studio and ``Other'' category indicators (not shown). Pseudo-$R^2$
205 +is one minus the ratio of the minimised check-function loss to the loss
206 +at the unconditional quantile. ***, ** and * denote significance at the
207 +1, 5 and 10\% levels.
208 +\end{tablenotes}
209 +\end{threeparttable}
210 +\end{table}
194 211
195 212 \begin{figure}[!htbp]
196 213 \centering
197 −\includegraphics[width=0.85\textwidth]{08_distance_to_center_gradient.png}
198 −\caption{Price Gradient by Distance to City Centre}
199 −\label{fig:distance_gradient}
214 +\includegraphics[width=0.95\textwidth]{rev_fig_quantile.pdf}
215 +\caption{Quantile Regression Coefficients Across the Conditional Price Distribution}
216 +\label{fig:quantile}
200 217 \begin{minipage}{0.9\textwidth}
201 218 \footnotesize
202 −\textit{Notes:} Nightly price as a function of distance to the nearest
203 −city centre, with LOWESS smoother ($f = 0.3$, capped at 5,000
204 −observations).
219 +\textit{Notes:} Point estimates and 95\% confidence bands at
220 +$\tau \in \{0.10, 0.25, 0.50, 0.75, 0.90\}$; the dashed red line is the
221 +OLS (M5) coefficient.
205 222 \end{minipage}
206 223 \end{figure}
207 224
208 −% ------------------------------------------------------------------
209 −\subsection{Text-Derived Features}
210 −\label{subsec:text}
211 −% ------------------------------------------------------------------
212 −
213 −The first TF-IDF/SVD component is the strongest text predictor
214 −($\hat{\beta} = 2.800$, $p < 0.001$). Price-associated word analysis
215 −reveals that terms correlated with higher prices include ``in
216 −montr\'{e}al'' ($r = 0.181$), ``rental unit'' ($r = 0.118$), and
217 −``bedrooms'' ($r = 0.110$). Negatively correlated terms include ``new''
218 −($r = -0.107$) and ``shared'' ($r \approx -0.05$).
225 +Three patterns emerge. First, the implicit prices of bedrooms and
226 +bathrooms increase along the distribution: the bedroom elasticity is
227 +indistinguishable from zero at $\tau = 0.10$ and 0.19 at
228 +$\tau = 0.90$, and the bathroom elasticity doubles from 0.24 to 0.55,
229 +while the capacity elasticity moves the other way, from 0.37 to 0.31.
230 +Cheap listings are priced per guest; expensive listings are priced per
231 +room. The paired bootstrap puts the $\tau = 0.90$ minus $\tau = 0.10$
232 +difference in the bedroom elasticity at 0.17 (standard error 0.10,
233 +$p = 0.08$) and finds no significant difference for capacity
234 +($-0.07$, $p = 0.37$); the bathroom gradient, the steepest of the three,
235 +is visible in the non-overlapping confidence bands of
236 +Figure~\ref{fig:quantile}. The chalet premium shows the same
237 +gradient, from 2\% at the bottom to 21\% at the top of the distribution.
238 +
239 +Second, the reputation variables matter at the bottom. The Superhost
240 +badge is associated with 8\% and 5\% higher prices at $\tau = 0.10$ and
241 +0.25 and with nothing above the median; the number of reviews is
242 +positively associated with price in the lower quantiles (0.042 at
243 +$\tau = 0.10$) and negatively in the upper quantiles ($-0.042$ at
244 +$\tau = 0.90$), the inter-quantile difference of $-0.084$ (standard error 0.023,
245 +$p < 0.001$) being the most significant in the table. At the lower end, reviews and the badge certify a cheap
246 +listing; at the upper end, heavily reviewed listings are high-turnover
247 +properties that are priced below the less reviewed, more exclusive
248 +ones. The rating coefficient, by contrast, is stable across quantiles
249 +(0.26 to 0.38) and its inter-quantile difference is not significant
250 +($0.03$, $p = 0.86$).
251 +
252 +Third, the location gradient strengthens with price: distance to the
253 +centre is unpriced at $\tau = 0.10$ and carries an elasticity of
254 +$-0.07$ to $-0.08$ in the upper half, while local density is priced most
255 +strongly at the bottom (0.10 at $\tau = 0.10$, 0.04 at
256 +$\tau = 0.90$). Budget listings gain from being where listings are
257 +dense, premium listings from being close to the centre.
219 258
220 259 % ------------------------------------------------------------------
221 −\subsection{Quantile Regression}
222 −\label{subsec:quantile}
260 +\subsection{Spatial Dependence}
261 +\label{subsec:spatial}
223 262 % ------------------------------------------------------------------
224 263
225 −Table~\ref{tab:quantile} presents quantile regression estimates at five
226 −points of the conditional log-price distribution.
264 +The residuals of the hedonic model are spatially autocorrelated.
265 +Moran's $I$ on the M4 residuals with the five-nearest-neighbour matrix
266 +is 0.126 ($z = 10.8$) ($p < 0.001$ under 999 permutations) and it remains
267 +0.072 ($z = 6.2$, $p < 0.001$) after the city fixed effects, so dependence exists within
268 +cities as well as between them. Table~\ref{tab:spatial} reports the
269 +three spatial models estimated on the M4 regressor set. The spatial lag
270 +coefficient is $\hat\rho = 0.200$ (standard error 0.022) in the SAR and
271 +0.261 (0.028) in the SDM; the spatial error coefficient is
272 +$\hat\lambda = 0.284$ (0.028). All three models improve substantially on
273 +OLS in log-likelihood; the SDM has the highest likelihood and the
274 +likelihood-ratio test rejects the SAR restriction
275 +$\boldsymbol{\theta} = \mathbf{0}$ ($\chi^2(20) = 52.8$, $p < 0.001$), while the SEM has the
276 +lowest AIC because it adds a single parameter.
227 277
228 278 \begin{table}[!htbp]
229 279 \centering
230 −\caption{Quantile Regression: Selected Coefficients}
231 −\label{tab:quantile}
280 +\caption{Spatial Lag, Spatial Error and Spatial Durbin Models (M4 Regressors)}
281 +\label{tab:spatial}
232 282 \begin{threeparttable}
233 −\begin{tabular}{lrrrrr}
234 −\toprule
235 − & (1) & (2) & (3) & (4) & (5) \\
236 −Variable & $\tau = 0.10$ & $\tau = 0.25$ & $\tau = 0.50$
237 − & $\tau = 0.75$ & $\tau = 0.90$ \\
238 −\midrule
239 −Is entire home & 1.007 & 0.852 & 1.337 & 1.877 & 1.818 \\
240 −Is private room & 1.018 & 0.832 & 1.319 & 2.793 & 1.791 \\
241 −Log bathrooms & 0.796 & 0.643 & 0.610 & 0.679 & 0.629 \\
242 −Bedrooms/guest & 0.456 & 0.221 & 1.240 & $-$0.898 & $-$0.802 \\
243 −Log accommodates & $-$0.178 & 0.067 & $-$0.150 & $-$0.095 & $-$0.042 \\
244 −Amenities count & $-$0.009 & $-$0.004 & $-$0.006 & $-$0.004 & $-$0.004 \\
245 −Rating & 0.379 & 0.285 & 0.245 & 0.206 & 0.161 \\
246 −Is Superhost & $-$0.090 & 0.019 & 0.038 & 0.205 & 0.178 \\
247 −Pets allowed & 0.063 & 0.068 & 0.168 & 0.147 & 0.218 \\
248 −\midrule
249 −Pseudo-$R^2$ & 0.100 & 0.083 & 0.061 & 0.070 & 0.020 \\
250 −\bottomrule
251 −\end{tabular}
283 +\footnotesize
284 +\setlength{\tabcolsep}{4pt}
285 +\input{../results/tables/rev_spatial.tex}
252 286 \begin{tablenotes}
253 287 \footnotesize
254 −\item \textit{Notes:} Quantile regression estimates at $\tau \in \{0.10,
255 −0.25, 0.50, 0.75, 0.90\}$. Pseudo-$R^2$ is the Koenker--Bassett
256 −measure. 16 covariates included; selected coefficients shown.
288 +\item \textit{Notes:} Maximum-likelihood estimates on the analysis sample
289 +with a row-standardised 5-nearest-neighbour weights matrix built on
290 +coordinates projected to kilometres. The last column reports the
291 +coefficients $\boldsymbol{\theta}$ on the spatially lagged regressors of
292 +the SDM. Studio and ``Other'' category indicators included but not
293 +shown. Standard errors in parentheses (HC3 for OLS, asymptotic for the
294 +spatial models). ***, ** and * denote significance at the 1, 5 and 10\%
295 +levels.
257 296 \end{tablenotes}
258 297 \end{threeparttable}
259 298 \end{table}
260 299
261 −The entire-home coefficient increases from 1.007 at $\tau = 0.10$ to
262 −1.877 at $\tau = 0.75$, indicating that the room-type premium is
263 −substantially amplified in the upper price segment. The rating
264 −coefficient declines monotonically from 0.379 to 0.161, indicating
265 −that review scores matter more for budget listings than for luxury
266 −listings. The pseudo-$R^2$ is highest at $\tau = 0.10$ (0.100) and
267 −lowest at $\tau = 0.90$ (0.020), confirming that luxury pricing depends
268 −heavily on unobserved factors.
300 +The hedonic coefficients are robust to the spatial specification: the
301 +capacity, shared-bathroom, photo and rating coefficients move by less
302 +than one standard error between OLS and any of the spatial models. The
303 +largest changes are in the variables that carry spatial information,
304 +the chalet premium (0.154 in OLS, 0.097 in the SAR) and local density
305 +(0.067 to 0.044 in the SDM), part of whose OLS coefficient is absorbed
306 +by neighbours' prices. The SDM's spatially lagged regressors are mostly
307 +insignificant; two exceptions are that a listing surrounded by
308 +high-capacity listings is priced lower ($\theta = -0.153$) and one
309 +surrounded by highly rated listings is priced lower ($-0.294$),
310 +conditional on its own characteristics, which is the pattern expected
311 +when neighbours are substitutes.
312 +
313 +Table~\ref{tab:impacts} translates the SAR and SDM estimates into
314 +average direct, indirect and total impacts. In the SAR the spatial
315 +multiplier is $1/(1 - \hat\rho) = 1.25$: the total impact of each
316 +characteristic is 25\% larger than its coefficient, and a fifth of the
317 +total impact accrues to neighbouring listings through the price
318 +feedback. The direct impacts are within a few percent of the
319 +coefficients, so the OLS coefficients are good approximations of the
320 +own-listing associations. In the SDM the indirect impacts are imprecisely
321 +estimated, with two exceptions: the bathroom count has a positive
322 +spillover significant at the 5\% level (total impact 0.70 against a
323 +direct impact of 0.45), and the rating has a negative spillover,
324 +significant at the 10\% level, that offsets its direct impact, so the
325 +total association between the average rating of a neighbourhood and its
326 +prices is close to zero. These spillovers describe
327 +the equilibrium price surface, not a causal effect of neighbours' ratings
328 +on a listing's price.
329 +
330 +\begin{table}[!htbp]
331 +\centering
332 +\caption{Average Direct, Indirect and Total Impacts, SAR and SDM}
333 +\label{tab:impacts}
334 +\begin{threeparttable}
335 +\footnotesize
336 +\setlength{\tabcolsep}{4pt}
337 +\input{../results/tables/rev_impacts.tex}
338 +\begin{tablenotes}
339 +\footnotesize
340 +\item \textit{Notes:} Impacts computed as in \citet{LeSagePace2009}
341 +from the dense inverse $(\mathbf{I} - \hat\rho\mathbf{W})^{-1}$.
342 +Standard errors (in parentheses) from 300 draws of the parameters from
343 +their estimated asymptotic distribution. ***, ** and * denote
344 +significance at the 1, 5 and 10\% levels.
345 +\end{tablenotes}
346 +\end{threeparttable}
347 +\end{table}
269 348
270 349 % ------------------------------------------------------------------
271 −\subsection{Machine Learning Comparison}
350 +\subsection{Machine Learning Benchmarks}
272 351 \label{subsec:ml_comparison}
273 352 % ------------------------------------------------------------------
274 353
275 −Table~\ref{tab:ml} compares the out-of-sample predictive performance of
276 −all seven models on the held-out test set ($N_{\text{test}} = 382$).
354 +Table~\ref{tab:ml} compares the out-of-sample accuracy of the M5
355 +hedonic model and five learners under random and spatially blocked
356 +cross-validation. Under random folds the M5 hedonic
357 +model reaches an out-of-sample $R^2$ of 0.473 and a median absolute
358 +percentage error of 28.5\%; the elastic net, which regularises the same
359 +linear specification, does no better. The tree ensembles are clearly
360 +more accurate: XGBoost attains $R^2 = 0.559$, RMSE 0.450 and MdAPE
361 +26.4\%, with gradient boosting, LightGBM and the random forest within one
362 +point of it. The gain of 0.086 in $R^2$ over the hedonic model is the
363 +value of the interactions and non-linearities that the semi-log
364 +specification rules out, for instance between type and capacity or
365 +between density and city.
366 +
367 +Spatially blocked cross-validation is the sterner test, and it lowers
368 +every model by about seven points of $R^2$: the hedonic model falls to
369 +0.407, the tree ensembles to 0.48. The ranking is unchanged and the gap
370 +between the best learner and the hedonic model narrows slightly, from
371 +0.086 to 0.076. Two conclusions follow. The random-fold figures
372 +overstate how well any of these models would price listings in an area
373 +absent from the training data, because listings in the same area share
374 +unobserved determinants of price; and the predictive advantage of the
375 +learners is not an artefact of their fitting local spatial structure
376 +more closely, since it survives when that structure cannot be exploited.
377 +A median error of 26 to 30\% of the nightly price is, in either design,
378 +the practical accuracy limit of an automated valuation of Quebec
379 +short-term rentals from listing-card information alone.
277 380
278 381 \begin{table}[!htbp]
279 382 \centering
280 −\caption{Out-of-Sample Predictive Performance}
383 +\caption{Out-of-Sample Accuracy Under Random and Spatially Blocked Cross-Validation}
281 384 \label{tab:ml}
282 385 \begin{threeparttable}
283 −\begin{tabular}{lrrrr}
284 −\toprule
285 −Model & $R^2$ & RMSE & MAE & MAPE (\%) \\
286 −\midrule
287 −XGBoost & 0.285 & 1.160 & 0.841 & 14.27 \\
288 −CatBoost & 0.258 & 1.182 & 0.862 & 14.63 \\
289 −LightGBM & 0.244 & 1.192 & 0.874 & 14.84 \\
290 −Random Forest & 0.243 & 1.193 & 0.884 & 15.00 \\
291 −Gradient Boosting & 0.238 & 1.197 & 0.870 & 14.90 \\
292 −GAM (fallback) & 0.195 & 1.230 & 0.965 & 16.53 \\
293 −ElasticNet & 0.131 & 1.278 & 0.996 & 17.15 \\
294 −\bottomrule
295 −\end{tabular}
386 +\footnotesize
387 +\setlength{\tabcolsep}{4pt}
388 +\input{../results/tables/rev_ml_cv.tex}
296 389 \begin{tablenotes}
297 390 \footnotesize
298 −\item \textit{Notes:} Performance evaluated on the held-out test set
299 −($N = 382$). All models trained on 49 features with $N_{\text{train}} =
300 −1{,}524$. MAPE is mean absolute percentage error. CatBoost and GAM use
301 −sklearn fallback implementations.
391 +\item \textit{Notes:} Five-fold cross-validation on the analysis sample
392 +($N = 2{,}480$); all models use the M5 regressors including the fixed-effect
393 +indicators. Random folds assign listings at random; blocked folds assign
394 +20 $k$-means spatial clusters of listings to folds as whole blocks, so
395 +that each listing is predicted by a model that has seen no listing from
396 +its cluster. $R^2$, RMSE and MAE are on the log scale; MdAPE is the median
397 +absolute percentage error on the price scale. Hyper-parameters: elastic
398 +net with cross-validated penalty; random forest 500 trees, minimum leaf 3;
399 +gradient boosting 500 trees, depth 3, learning rate 0.05; XGBoost 600
400 +trees, depth 5, learning rate 0.03; LightGBM 600 trees, 15 leaves,
401 +learning rate 0.03.
302 402 \end{tablenotes}
303 403 \end{threeparttable}
304 404 \end{table}
305 405
306 −XGBoost achieves the best performance ($R^2 = 0.285$, MAPE = 14.27\%),
307 −modestly exceeding the full OLS hedonic $R^2$ of 0.274. The similar
308 −performance suggests that the log-linear specification captures the
309 −majority of systematic price variation, with non-linearities playing a
310 −secondary role.
311 −
312 −% ------------------------------------------------------------------
313 −\subsection{Spatial Model Results}
314 −\label{subsec:spatial}
315 −% ------------------------------------------------------------------
316 −
317 −After constructing the $k$-nearest-neighbours ($k = 5$) spatial weight
318 −matrix, we estimate the three canonical spatial specifications. The
319 −Spatial Lag Model captures endogenous spatial interaction via
320 −$\hat{\rho}$, the Spatial Error Model captures spatially correlated
321 −unobservables via $\hat{\lambda}$, and the Spatial Durbin Model allows
322 −both endogenous interaction and spatially lagged covariates. The hedonic
323 −coefficients in the spatial specifications are qualitatively similar to
324 −the OLS estimates, but several magnitudes adjust modestly, indicating
325 −mild spatial bias in the OLS that is corrected by explicitly modeling
326 −the spatial structure.
327 −
328 406 % ------------------------------------------------------------------
329 −\subsection{Price Decomposition}
330 −\label{subsec:decomposition}
407 +\subsection{SHAP Decomposition of the Boosted Model}
408 +\label{subsec:shap}
331 409 % ------------------------------------------------------------------
332 410
333 −Table~\ref{tab:decomp} summarizes the price decomposition across all
334 −1,906 listings in the full-model sample.
411 +Table~\ref{tab:shap} ranks the features of the XGBoost model by mean
412 +absolute SHAP value and Figure~\ref{fig:shap} shows the distribution of
413 +the contributions. Guest capacity is by far the most important feature
414 +(21\% of the total attribution), followed by bedrooms (10\%), local
415 +density, the aggregate of the city and cell indicators, bathrooms and the
416 +review count (9\% each), the rating (7\%), photos (5\%), distance to the
417 +centre (5\%), amenities (4\%) and the shared-bathroom indicator (3\%).
418 +The ranking mirrors the hedonic model in two respects: the capacity block
419 +dominates, and the badges, pets and the rated indicator are at the
420 +bottom, with the Superhost badge absent from the top sixteen. It differs
421 +in one: the review count, whose average hedonic coefficient is zero,
422 +receives a large attribution. The beeswarm plot explains why. The SHAP
423 +values of the review count are negative for listings with many reviews
424 +and positive for listings with few, exactly the sign reversal between
425 +the lower and upper quantiles in Table~\ref{tab:quantile}; a linear
426 +coefficient averages the two to nothing, whereas the learner uses the
427 +variable in both directions. Together with the quantile results, this is
428 +the clearest instance in these data of an implicit price that is not a
429 +constant. SHAP values quantify how the fitted model uses each feature;
430 +they are attribution weights for associations, computed from an
431 +estimator that has no identification strategy, and they carry no causal
432 +content.
335 433
336 434 \begin{table}[!htbp]
337 435 \centering
338 −\caption{Price Decomposition: Log-Price Contributions by Attribute Block}
339 −\label{tab:decomp}
436 +\caption{Mean Absolute SHAP Values, XGBoost}
437 +\label{tab:shap}
340 438 \begin{threeparttable}
341 −\begin{tabular}{lrrrrr}
342 −\toprule
343 −Component & Mean & Median & Std.\ Dev. & Min & Max \\
344 −\midrule
345 −Actual log-price & 5.871 & 5.395 & 1.417 & 2.446 & 10.124 \\
346 −Predicted log-price & 3.985 & 5.392 & 3.730 & $-$9.310 & 10.742 \\
347 −\midrule
348 −Base (intercept) & 0.000 & 0.000 & 0.000 & 0.000 & 0.000 \\
349 −Property & $-$2.349 & $-$1.949 & 1.321 & $-$10.055 & 2.555 \\
350 −Amenity & $-$0.035 & $-$0.034 & 0.082 & $-$0.293 & 0.323 \\
351 −Host & 0.014 & 0.017 & 0.016 & $-$0.012 & 0.041 \\
352 −Review & 6.402 & 7.477 & 2.987 & $-$0.745 & 9.238 \\
353 −Location & 0.000 & 0.000 & 0.000 & 0.000 & 0.000 \\
354 −Text & 0.000 & 0.000 & 0.000 & 0.000 & 0.000 \\
355 −Spatial & $-$0.047 & $-$0.087 & 0.283 & $-$2.920 & 3.708 \\
356 −\midrule
357 −Prediction error & 1.163 & 0.108 & 3.090 & $-$6.211 & 15.328 \\
358 −\bottomrule
359 −\end{tabular}
439 +\input{../results/tables/rev_shap_importance.tex}
360 440 \begin{tablenotes}
361 441 \footnotesize
362 −\item \textit{Notes:} Decomposition based on the full hedonic model
363 −(M9). Each row reports the distribution of log-price contributions from
364 −the corresponding attribute block across all $N = 1{,}906$ listings.
442 +\item \textit{Notes:} Exact SHAP values from the TreeExplainer for the
443 +XGBoost model fitted to the analysis sample. $\overline{|\phi_k|}$ is the
444 +mean absolute contribution of feature $k$ to the predicted log price;
445 +the share is relative to the sum over all features, including the
446 +individual fixed-effect indicators, which are reported as one aggregate
447 +row.
365 448 \end{tablenotes}
366 449 \end{threeparttable}
367 450 \end{table}
368 451
369 −The review component contributes the largest mean share (6.402), driven
370 −by the large ``has reviews'' indicator coefficient. The property
371 −component shows the widest range ($-10.055$ to $+2.555$), reflecting
372 −heterogeneity in structural characteristics. The spatial component
373 −exhibits meaningful variation (std.\ dev.\ = 0.283), with favourable
374 −spatial contexts boosting predicted prices by up to 3.7 log points.
452 +\begin{figure}[!htbp]
453 +\centering
454 +\includegraphics[width=0.9\textwidth]{rev_fig_shap.pdf}
455 +\caption{SHAP Summary Plot, XGBoost (Twelve Most Important Listing-Level Features)}
456 +\label{fig:shap}
457 +\begin{minipage}{0.9\textwidth}
458 +\footnotesize
459 +\textit{Notes:} Each point is one listing; the horizontal position is
460 +the SHAP value (contribution to predicted log price), the colour the
461 +feature value (blue low, red high). Fixed-effect indicators are
462 +excluded from the plot.
463 +\end{minipage}
464 +\end{figure}
modified paper/sections/robustness.tex +87 −86
@@ -1,104 +1,105 @@
1 1 % ==========================================================================
2 −\section{Robustness Checks}
2 +\section{Robustness}
3 3 \label{sec:robustness}
4 4 % ==========================================================================
5 5
6 −This section evaluates the sensitivity of the main hedonic estimates to
7 −alternative sample definitions, variable transformations, model
8 −specifications, and subsample restrictions.
9 −
10 −% ------------------------------------------------------------------
11 −\subsection{Outlier Treatment}
12 −\label{subsec:winsorize}
13 −% ------------------------------------------------------------------
14 −
15 −We assess sensitivity to alternative outlier treatments through five
16 −specifications: (1)~raw OLS, (2)~Winsorized dependent variable at the
17 −1st/99th percentiles, (3)~trimmed sample dropping observations outside
18 −the 1st--99th range, (4)~semi-log specification, and (5)~median
19 −regression (LAD). Across all five, the sign, significance, and
20 −approximate magnitude of the key hedonic coefficients remain stable.
21 −The adjusted $R^2$ ranges from 0.083 to 0.098, confirming that the
22 −results are not driven by extreme prices.
23 −
24 −% ------------------------------------------------------------------
25 −\subsection{Subsample Analysis by Property Type}
26 −\label{subsec:room_type}
27 −% ------------------------------------------------------------------
28 −
29 −We re-estimate the full model separately for each property type.
30 −Table~\ref{tab:robustness_type} summarizes the results.
6 +Table~\ref{tab:robustness} re-estimates the M5 specification under
7 +alternative definitions of the sample and of the fixed effects and
8 +reports the coefficients that carry the paper's main results. The
9 +checks address three threats: that the results depend on how the
10 +stay-price regime was removed, that they are driven by a particular
11 +segment of the market, and that they depend on the spatial resolution
12 +of the fixed effects.
31 13
32 14 \begin{table}[!htbp]
33 15 \centering
34 −\caption{Hedonic Model by Property Type}
35 −\label{tab:robustness_type}
16 +\caption{Robustness of the Main Coefficients (Specification M5)}
17 +\label{tab:robustness}
36 18 \begin{threeparttable}
37 −\begin{tabular}{lrrr}
38 −\toprule
39 −Property Type & $N$ & $R^2$ & Adj.\ $R^2$ \\
40 −\midrule
41 −Apartment & 77 & 0.186 & 0.082 \\
42 −Cabin/Chalet & 691 & 0.084 & 0.068 \\
43 −Condo & 237 & 0.104 & 0.065 \\
44 −House & 679 & 0.098 & 0.083 \\
45 −Other & 554 & 0.130 & 0.112 \\
46 −Rental unit & 1,174 & 0.095 & 0.085 \\
47 −\bottomrule
48 −\end{tabular}
19 +\scriptsize
20 +\setlength{\tabcolsep}{3pt}
21 +\input{../results/tables/rev_robustness.tex}
49 22 \begin{tablenotes}
50 23 \footnotesize
51 −\item \textit{Notes:} OLS estimates with HC1 robust standard errors.
52 −Each row reports the model estimated on the corresponding property type
53 −subsample. Zero-variance regressors are dropped within each subsample.
24 +\item \textit{Notes:} Each row re-estimates M5 (all regressors and city /
25 +cell fixed effects) on the indicated sample; HC3 standard errors in
26 +parentheses. ``Bedr.'', ``Bathr.'' and ``Guests'' are the elasticities
27 +with respect to bedrooms, one plus bathrooms and guest capacity;
28 +``Rating'' is the coefficient on the centred rating among rated
29 +listings; ``ln dist.'' is the coefficient on $\ln(1+\text{km to
30 +centre})$. $\hat p_i$ is the posterior probability of the stay regime
31 +from Equation~\eqref{eq:mixture}. The ``weighted'' row uses weighted
32 +least squares with weights $1 - \hat p_i$ on the baseline sample. The
33 +last row replaces the city / cell fixed effects by 60 $k$-means spatial
34 +cells. ***, ** and * denote significance at the 1, 5 and 10\% levels.
54 35 \end{tablenotes}
55 36 \end{threeparttable}
56 37 \end{table}
57 38
58 −The Apartment subsample achieves the highest $R^2$ (0.186) despite the
59 −smallest sample size. Cabin/Chalet and House show lower $R^2$ values,
60 −consistent with greater heterogeneity depending on unobserved
61 −experiential characteristics.
62 −
63 −% ------------------------------------------------------------------
64 −\subsection{Price Segment Heterogeneity}
65 −\label{subsec:price_segment}
66 −% ------------------------------------------------------------------
67 −
68 −We partition the sample into five price segments (Budget, Moderate,
69 −Premium, Luxury, Ultra-Luxury) and re-estimate the full model within
70 −each. In the Budget segment, structural variables carry larger
71 −standardized coefficients. In the Luxury and Ultra-Luxury segments,
72 −amenity indices and reputation variables gain relative importance,
73 −consistent with the quantile regression findings.
74 −
75 −% ------------------------------------------------------------------
76 −\subsection{Alternative Location Controls}
77 −\label{subsec:alt_location}
78 −% ------------------------------------------------------------------
79 −
80 −We test five progressively richer location specifications: (1)~no
81 −controls, (2)~city/neighbourhood fixed effects (top 30 by count),
82 −(3)~latitude and longitude as continuous controls, (4)~spatial cluster
83 −fixed effects ($K = 20$), and (5)~spatial lag (5-NN mean price). City
84 −fixed effects raise the adjusted $R^2$ from 0.094 to 0.164. Under all
85 −specifications, the non-locational hedonic coefficients remain stable
86 −in sign and significance.
39 +\paragraph{The regime classification.} The baseline results are
40 +insensitive to the posterior cut-off: tightening it to 0.25 removes five
41 +listings and loosening it to 0.75 adds two, and no coefficient moves by
42 +more than 0.02. Weighting observations by $1 - \hat p_i$ instead of
43 +classifying them gives the same estimates. The comparison with the
44 +simple price rules is instructive. Keeping every listing priced at or
45 +below \$1,000, the rule used in the companion paper, leaves 83
46 +stay-regime listings in the sample; because these are small, cheap-per-night
47 +units, they pull the capacity elasticity to zero (0.015 against 0.331),
48 +halve the rating coefficient and lower $R^2$ to 0.28. A \$600 cut-off
49 +removes all but nine of them but also discards 87 genuine nightly prices
50 +of large chalets and houses, which compresses the bathroom and rating
51 +coefficients (0.247 and 0.254) and lowers $R^2$ to 0.42. The full priced
52 +sample, finally, reproduces the pathology of the first version of this
53 +paper: the capacity elasticity turns negative, the badges and the review
54 +count acquire large negative coefficients, the rating coefficient
55 +doubles, and $R^2$ is 0.16. The model-based classification is therefore
56 +not a cosmetic choice; the price rules are biased in opposite directions
57 +and the bias is concentrated in exactly the coefficients of interest.
87 58
88 −% ------------------------------------------------------------------
89 −\subsection{Host Type Stratification}
90 −\label{subsec:professional}
91 −% ------------------------------------------------------------------
59 +\paragraph{Composition.} Excluding hotel rooms, bed-and-breakfasts and
60 +hostels, which are priced per room on a different logic, raises the
61 +bathroom elasticity to 0.54 and the rating coefficient to 0.38 and
62 +leaves the rest unchanged. Restricting the sample to rated listings, so
63 +that the rating enters for every observation, gives the same rating
64 +coefficient (0.37) and confirms that the unrated indicator is not driving
65 +it. Splitting the sample at Montreal reveals the one substantive
66 +heterogeneity in the table. Within Montreal ($N = 506$) the bedroom
67 +elasticity is small and imprecise, the review count is positively priced
68 +(0.112, standard error 0.021) and the distance gradient is steep
69 +($-0.173$ per log-kilometre); outside Montreal the bedroom elasticity is
70 +0.22, reviews are unpriced and distance to the nearest centre does not
71 +matter. In the metropolitan market, where listings are substitutes
72 +within a dense grid, an established review record and proximity to the
73 +centre are what differentiate listings; in the resort and small-town
74 +markets, size does. The capacity, bathroom and rating coefficients are
75 +nonetheless similar in the two sub-samples, and the within-Montreal
76 +$R^2$ (0.54) is slightly higher than the provincial one.
92 77
93 −We stratify by host type: all hosts (baseline), Superhosts only
94 −($R^2 = 0.077$), and multi-listing hosts. The lower $R^2$ for
95 −Superhosts suggests that, conditional on meeting the quality threshold,
96 −other observables explain less of the remaining price variation.
78 +\paragraph{Outliers and fixed effects.} Trimming the top and bottom
79 +percentile of prices within the analysis sample lowers the bathroom
80 +elasticity to 0.30 and leaves the other coefficients unchanged; the
81 +largest bathroom counts belong to the most expensive chalets, so the
82 +bathroom coefficient is partly identified from the upper tail, as the
83 +quantile results already indicated. Replacing the 51 city and cell fixed
84 +effects by 60 finer spatial cells, which halves the average number of
85 +listings per group, changes no coefficient by more than 0.03 and leaves
86 +$R^2$ at 0.505, so the listing-level implicit prices are not sensitive
87 +to how finely location is controlled. The spatial models of
88 +Section~\ref{subsec:spatial} provide the complementary check that the
89 +coefficients are robust to modelling the dependence explicitly rather
90 +than absorbing it: with ten rather than five nearest neighbours the
91 +spatial lag coefficient is 0.215 (standard error 0.027) and the Moran
92 +statistic of the M4 residuals is 0.094 ($z = 11.4$), so the dependence is
93 +not an artefact of a particular neighbourhood definition.
97 94
98 95 \medskip
99 −In summary, the main findings---the dominant role of bedrooms and
100 −structural capacity, the significant review score premium, the concave
101 −bedroom--price relationship, competitive density effects, and positive
102 −local price contagion---are robust across alternative sample definitions,
103 −outlier treatments, property type subsamples, price segments, location
104 −controls, and host type stratifications.
96 +In summary, the implicit prices of capacity, bathrooms, the shared
97 +bathroom, photos, the rating and local density, and the absence of a
98 +Superhost or Guest Favourite premium, hold across the regime cut-off,
99 +weighting, the exclusion of commercial lodging, trimming, finer fixed
100 +effects and alternative spatial weights. The two results that are
101 +sample-dependent are the bedroom elasticity, which is driven by the
102 +non-metropolitan market, and the review-count coefficient, which is
103 +positive in Montreal and zero elsewhere; both are consistent with the
104 +quantile patterns and are reported as heterogeneity rather than as
105 +instability.
added results/figures/rev_fig_logprice_mixture.pdf +0 −0

Binary file not shown.

added results/figures/rev_fig_map.pdf +0 −0

Binary file not shown.

added results/figures/rev_fig_partials.pdf +0 −0

Binary file not shown.

added results/figures/rev_fig_price_by_category.pdf +0 −0

Binary file not shown.

added results/figures/rev_fig_quantile.pdf +0 −0

Binary file not shown.

added results/figures/rev_fig_shap.pdf +0 −0

Binary file not shown.

added results/tables/rev_impacts.tex +42 −0
@@ -0,0 +1,42 @@
1 +\begin{tabular}{lrrrrrr}
2 +\toprule
3 + & \multicolumn{3}{c}{SAR} & \multicolumn{3}{c}{SDM} \\
4 +\cmidrule(lr){2-4}\cmidrule(lr){5-7}
5 +Variable & Direct & Indirect & Total & Direct & Indirect & Total \\
6 +\midrule
7 +ln(bedrooms) & 0.166*** & 0.040*** & 0.207*** & 0.154*** & 0.098 & 0.252*** \\
8 + & (0.032) & (0.010) & (0.040) & (0.035) & (0.086) & (0.095) \\
9 +ln(1 + bathrooms) & 0.447*** & 0.108*** & 0.555*** & 0.445*** & 0.253** & 0.698*** \\
10 + & (0.042) & (0.018) & (0.054) & (0.043) & (0.117) & (0.123) \\
11 +ln(guests) & 0.303*** & 0.073*** & 0.376*** & 0.330*** & -0.086 & 0.244*** \\
12 + & (0.030) & (0.012) & (0.038) & (0.032) & (0.075) & (0.081) \\
13 +Shared bathroom & -0.385*** & -0.093*** & -0.479*** & -0.391*** & -0.145 & -0.536*** \\
14 + & (0.044) & (0.016) & (0.056) & (0.048) & (0.116) & (0.120) \\
15 +Chalet/cottage/cabin & 0.098*** & 0.024*** & 0.122*** & 0.115*** & 0.024 & 0.138* \\
16 + & (0.034) & (0.008) & (0.042) & (0.037) & (0.072) & (0.076) \\
17 +House & 0.073** & 0.018** & 0.091** & 0.089** & -0.053 & 0.036 \\
18 + & (0.032) & (0.008) & (0.040) & (0.035) & (0.088) & (0.092) \\
19 +Condo/loft/apartment & -0.041 & -0.010 & -0.051 & -0.019 & -0.076 & -0.095 \\
20 + & (0.035) & (0.009) & (0.044) & (0.033) & (0.081) & (0.086) \\
21 +Hotel/B\&B/hostel & 0.109** & 0.026** & 0.135** & 0.100** & 0.135 & 0.236* \\
22 + & (0.048) & (0.013) & (0.060) & (0.047) & (0.117) & (0.124) \\
23 +ln(1 + amenities) & 0.064* & 0.015* & 0.079* & 0.058* & 0.082 & 0.140 \\
24 + & (0.034) & (0.008) & (0.042) & (0.031) & (0.080) & (0.086) \\
25 +ln(1 + photos) & 0.081*** & 0.020*** & 0.100*** & 0.093*** & -0.007 & 0.086* \\
26 + & (0.021) & (0.006) & (0.027) & (0.020) & (0.047) & (0.051) \\
27 +Superhost & 0.002 & 0.001 & 0.003 & 0.006 & 0.046 & 0.052 \\
28 + & (0.023) & (0.006) & (0.028) & (0.022) & (0.058) & (0.062) \\
29 +Guest Favourite & -0.034 & -0.008 & -0.042 & -0.030 & 0.016 & -0.014 \\
30 + & (0.026) & (0.006) & (0.032) & (0.026) & (0.072) & (0.079) \\
31 +ln(1 + reviews) & 0.017** & 0.004* & 0.021** & 0.016* & 0.012 & 0.028 \\
32 + & (0.009) & (0.002) & (0.011) & (0.008) & (0.023) & (0.025) \\
33 +Rated (star shown) & -0.037 & -0.009 & -0.046 & -0.037 & -0.028 & -0.065 \\
34 + & (0.043) & (0.011) & (0.054) & (0.042) & (0.121) & (0.137) \\
35 +Rating $-$ 4.8 (rated only) & 0.317*** & 0.077*** & 0.394*** & 0.321*** & -0.272* & 0.050 \\
36 + & (0.058) & (0.016) & (0.071) & (0.065) & (0.165) & (0.190) \\
37 +ln(1 + km to centre) & -0.006 & -0.002 & -0.008 & -0.024 & 0.020 & -0.004 \\
38 + & (0.010) & (0.003) & (0.012) & (0.062) & (0.061) & (0.015) \\
39 +ln(1 + listings within 1 km) & 0.054*** & 0.013*** & 0.067*** & 0.045** & 0.025 & 0.070*** \\
40 + & (0.009) & (0.002) & (0.011) & (0.019) & (0.022) & (0.014) \\
41 +\bottomrule
42 +\end{tabular}
\ No newline at end of file
added results/tables/rev_iq_bootstrap.json +1 −0
@@ -0,0 +1 @@
1 +{"ln_bedrooms": [0.09495777017582441, 0.1101708553651406, 0.160248525790621, 0.2051683875552044, 0.178631385875633, 0.17913563743786654, 0.08779784524813294, 0.12363142148933548, 0.31437820688734064, 0.04732693568439572, 0.19243943743640557, 0.1555443910365284, 0.25093777901474823, 0.220562253517528, 0.26851096264476837, 0.2731978361525762, 0.15591254709761415, 0.2361350022838451, 0.11461696540459343, 0.19986320967063875, 0.11453675890334125, 0.20345124714458507, -0.0240132177657415, 0.08553121420209209, 0.234863259964186, 0.21086558333308858, 0.09240338931613223, 0.071083240738119, 0.17412841111081434, 0.1353961357690423, 0.2238039999283501, 0.19261988043035672, 0.21044061932298064, 0.051291177450366376, 0.06593667661400104, 0.10621986278761142, 0.11924127315796795, 0.0966795419499249, 0.1592531182723178, 0.29986799123560104, 0.054991356187201745, 0.11310125860649123, 0.04231365767191164, 0.26376224070145327, 0.013190997995479847, 0.045807831860656734, 0.23667142884823988, 0.20005375449363783, 0.03975365721998969, 0.20741796407401125, 0.31422921947796567, 0.15011195708302694, 0.16182516205594766, -0.1128663088779831, 0.32415672150273167, 0.31591441909108653, -0.009591040829036501, -0.004963302674696024, 0.11340651030513982, 0.17827826020948123, 0.17317032035634838, 0.15241360100981183, 0.3256794325318424, 0.06958915478094241, 0.3278812138187277, 0.3230983150715474, 0.2366216677282864, 0.12849611664523763, 0.22007121002206986, 0.22234059507718484, 0.12643561778077128, 0.06617677278154588, 0.15096077277053155, 0.2677125890681964, 0.12529397410617094, -0.031093352220068482, -0.024404924150076113, 0.10018561047763797, 0.08767431810883863, 0.16032651944806275, 0.09276431652688188, 0.26280047846034904, 0.14903499440606538, 0.07726331855519675, 0.16811681276749368, 0.18400079428465688, 0.05798161866914597, 0.14147513166426506, 0.10632111961240298, 0.2803621236143954, 0.22651096316803887, 0.19414688017116077, -0.07158388804236893, 0.01844315529342566, 0.041385756701856735, 0.1435943478545596, 0.027820461350529513, -0.07169485016311228, 0.0617687599369674, 0.15702650185949096], "ln_guests": [-0.012969937781235785, -0.08402340912289219, 0.010733696504757972, 0.046131989601576606, -0.03470207771169953, -0.0005002739244446275, -0.01948243097467639, 0.003076435013099399, -0.10066289929909544, 0.07876254399161553, 0.027559613745324896, -0.044632228620685055, -0.1217985826651784, -0.08377032498037806, -0.16127476287812215, -0.146809122448758, -0.05699626940986491, -0.0173206004583335, 0.025333225165582007, -0.08361084861189738, -0.02811493612648519, -0.054645805814288906, -0.008629535830095847, -0.032942901181741036, -0.11091138253323152, -0.13216897703944142, -0.029291262246260885, -0.013072756141809805, -0.02092526727665245, -0.004454476211321889, -0.08497469665962853, 0.06239925686168135, -0.0490913342400745, 0.025236332218810276, 0.007777686118060956, -0.08832243632537029, -0.0002509925407139235, -0.024189814912688234, -0.13860070540067682, -0.09221460093772293, 0.08697150207115101, -0.10464715281148074, 0.05659191050381196, -0.06687695386972337, 0.03618880631438515, -0.09755888051222428, 0.02515246557913997, -0.08268402824251098, 0.08095726049214136, -0.0676492355114533, -0.08274557662571169, -0.1342866277664143, -0.1415914327981227, 0.1687829306574713, -0.07334614680803497, -0.20068380952000098, 0.08284499861474615, 0.02307119369334032, -0.07514879859627399, -0.08374191663824604, -0.03129619993569577, -0.08273115861311453, -0.10905018274911527, 0.04912481577184735, -0.0555199285291792, -0.09728540902142413, -0.050317680714215385, -0.093308582862619, -0.03513984059100039, 0.04844677415621845, -0.014161405481900147, -0.06939795409334693, -0.12499712607180413, 0.04452461492655857, -0.07627021483131102, -0.004458424455606291, 0.05733293313824106, -0.09785889047998353, -0.10732083369111933, -0.01691896147440275, 0.052109182437561685, -0.07948065041705377, -0.03860612983862666, 0.015273315113518038, -0.02018164487890317, 0.010489636772945232, 0.0874062657730974, -0.05434069017883303, 0.0635381707106717, -0.1577235911763637, -0.0567339382469072, -0.10241716393511524, 0.15008172571106115, 0.020883918486561015, 0.022670415177344694, 0.04596655353088863, 0.08848529395436344, 0.18409474841064366, -0.009432479171664454, -0.08515154184988205], "is_superhost": [-0.035234958492083024, -0.11941935478171217, -0.06482966789189959, -0.11253629445536717, -0.09890692940462031, -0.09485580277714689, -0.08650319973821752, -0.07646054666679447, -0.02232504901894572, 0.019107548585452605, -0.14682025553292988, -0.15315031389764044, -0.08703070646129163, -0.11950457731654751, 0.02734316406531434, -0.13363714215415712, -0.059076286541312584, -0.0013250799656816525, 0.016000702681139956, 0.11591701973969748, -0.10604519903699838, -0.05817004847995122, -0.1086364680359111, -0.12018150492531277, -0.14391076303877526, -0.16166853987147078, -0.13981075525680353, -0.06643414948291593, -0.12249356502022124, -0.09902807936168756, -0.17918076872410893, -0.010840809528986028, -0.10013359614185902, -0.06813241869917874, -0.07707991809093073, -0.12921066254921243, -0.17716228189146932, -0.07227983782183856, -0.010738757633362184, -0.014698364197798242, -0.06762224485646584, 0.05563487342988083, -0.08209483156224451, -0.04812630302762955, -0.05342448948272249, -0.08602116462770937, -0.13683417228276085, -0.057791507069396175, -0.1440345827722922, -0.14195473214851972, -0.10219078201498633, -0.02360341320365933, -0.12413513653882546, -0.09047669830670202, -0.0538092271590358, -0.10732993257170165, -0.13348332790246786, -0.06488150955283345, 0.041775189210966346, -0.09268568388188214, 0.05961120146207577, -0.1362864616735351, 0.0029133579466815718, -0.06293441486241136, -0.019618422829580595, 0.04488950403901981, -0.11028216558986514, -0.027958908578966657, -0.06478701564628864, -0.15301180136634684, -0.04723667942198517, -0.13355762859066544, -0.08894797492348516, -0.069061891221736, -0.07423645244853105, -0.02826218169866479, 0.017988470161071746, -0.06291330494786962, 0.016460304124848335, -0.03174654329950499, -0.11343131507783255, -0.06973933632718854, -0.04558072844486105, -0.14386504649633025, -0.04672517695462375, -0.09366258889303936, -0.05353754368661612, -0.08188120974227786, -0.12494694775614335, 0.02818238787676819, -0.1339930162357632, -0.1165226931871075, -0.1346314109996456, -0.008082344853846735, -0.06144523890725395, -0.10669191495890118, -0.13157783652809485, -0.12007986394291947, -0.1431118398468243, -0.07893553942813014], "rating_c": [-0.25084130283721606, 0.03815916851090151, 0.04348612168359978, -0.04102413719192555, -0.03434540511079831, 0.13688583060866222, 0.06151051042979816, 0.15863959793068716, -0.052778681954805506, 0.06780326486477861, -0.08882025380444247, -0.12418318331765477, -0.19743860152721027, 0.2007144114481889, 0.015852460126552614, -0.20679137134538905, 0.06416757889019209, -0.09134349905252748, -0.07388779160646664, -0.16527836004661367, -0.050038286339258775, 0.20122549245354548, 0.12712001318595867, 0.15851165132653477, 0.09156978615737899, -0.18348773742400226, -0.24760706418055634, 0.02575553214944648, 0.05250518952925631, 0.06278601432427422, 0.0994530716452573, -0.14649694683066627, -0.0014584482519239828, -0.0016608025289315265, 0.20375593700737227, -0.0031257110315436876, -0.148619451225386, 0.11264077931565453, 0.11779434295567626, -0.16094625163623277, 0.017793567189073656, 0.03271431546704662, 0.18062032637772063, 0.133671504080894, 0.19535484535299474, -0.1831805313777295, -0.09664242042526894, -0.13591750425439386, -0.11175909310168208, 0.24239553951429116, -0.05784432284326613, -0.15457032883932698, 0.17447422838358762, 0.24951131270881888, 0.13068205278523237, 0.03783145730164961, -0.12644539743905625, -0.1900544101044943, 0.007909648695203941, -0.346663731686931, 0.03189192149102382, -0.19373418343911908, -0.08134289458166677, -0.19938954104964068, 0.07380422277628895, -0.015093039570274414, 0.10136977197907981, -0.025179737014696002, 0.16245812676788773, 0.15873673462419902, 0.0878343199228766, -0.08684305070437404, -0.20899233360250946, -0.09931244872450407, -0.020950578204065096, 0.1511793987101555, -0.3084045539944782, -0.143934509032988, 0.06362194592111337, 0.42146492824031156, 0.024579204669407773, 0.017396483596712642, 0.2839769809215795, 0.1774234477616119, 0.1950091894752859, -0.011834009685117053, 0.17374987858397617, 0.04948635378241306, 0.011025699699530378, -0.17691986095451284, -0.011688551981933415, 0.27238221250991046, 0.06359955903462833, -0.2787922545371657, -0.37495975827187067, -0.2177771204869714, 0.2742357690622157, 0.11122803061880404, 0.16862419186509214, -0.10882511183251609], "ln_reviews": [-0.04419818796020536, -0.08166295558294223, -0.03581715225845983, -0.06905055319202802, -0.06623238332576875, -0.05710541906887556, -0.08442824348117028, -0.06513625196043904, -0.045269552962963644, -0.08661588906943507, -0.04640674737606787, -0.02569152196053892, -0.08862266768835525, -0.05078903715252636, -0.04526749477642511, -0.050180400671251846, -0.06762954927398823, -0.0710653986491252, -0.077462353767487, -0.10818445487643658, -0.0794490940952528, -0.07876010020709145, -0.07514004991435286, -0.04741569182880312, -0.10056514257166782, -0.07466794440017566, -0.06655956390477513, -0.10826975291615781, -0.130261509529646, -0.09263241655060028, -0.06739420689501685, -0.0745060969561564, -0.06253009897377382, -0.11519130636202135, -0.09958844881293771, -0.07664640972990355, -0.04525495559892079, -0.08623739027677857, -0.07564531402931607, -0.07071958110128662, -0.08098582954261246, -0.08599185480514393, -0.09215327979973154, -0.10836206653769409, -0.08745452308914992, -0.07545776690139405, -0.07936407194119965, -0.07662600340427161, -0.03243447110071429, -0.04955873215538986, -0.10265812060720236, -0.09956958454654341, -0.04071059600664739, -0.06917122256598418, -0.08787041647190108, -0.039603727759640606, -0.03673530418001292, -0.09464261644029648, -0.08625286305880309, -0.11018638582754647, -0.05171385621531499, -0.08464368742363604, -0.07920877024932338, -0.09716875632966548, -0.09083168360325544, -0.07061366956349957, -0.03673553616897607, -0.10425448595219677, -0.06079222134758311, -0.04724083004134627, -0.07349928457486499, -0.08813334355318148, -0.059368600959146534, -0.1100163991530394, -0.04528738626413542, -0.1011831123888669, -0.07486705520568648, -0.10041459289413979, -0.07907813787988971, -0.052378417132786126, -0.06466411532346683, -0.08854190974051335, -0.10711241221224554, -0.04632499088035047, -0.057843509048780106, -0.06769435179558059, -0.09208918756917228, -0.08965888267198352, -0.08372180179685529, -0.09234395026396669, -0.07853374274873204, -0.04545182858947783, -0.06168226009594946, -0.1367122791736648, -0.04753037391037651, -0.1072671395800171, -0.09107798520585675, -0.05389266786460212, -0.10284400485437573, -0.053224922755816806], "ln_dist": [-0.1497578569055804, -0.14555900765310525, -0.0775131639807114, -0.07075329956114729, 0.03540664813408512, -0.054244575242137216, -0.1388694393062906, -0.02155338375327176, -0.07825619962022756, -0.1653221798942468, -0.14366012946743467, 0.016745628992339334, -0.0009337378169220756, 0.05312774052390523, -0.0703928725752121, -0.12891960889191978, -0.06437525957699108, -0.10789680340553787, -0.16343775353288947, -0.14747536343384127, -0.051781739269699756, -0.06920084459125064, 0.04276313838818169, -0.11184979318977639, -0.10627885634312406, -0.10095631198009869, -0.1517439781464418, -0.13132861909610938, -0.021545896067436843, -0.13615079376677386, -0.19332100160886512, -0.10258610963683168, -0.05406934585107592, -0.19992211390956527, -0.07820165088878639, -0.03380737729651173, -0.13279410749237286, -0.11175572090655805, -0.022735511160135502, -0.12688552450163115, 0.01189469383098185, -0.18602763236890496, -0.09782383342007961, -0.15364625624386008, -0.08076499295657413, -0.103878884198366, -0.06990845832888226, -0.1127067696489803, -0.14358833340429555, -0.12006740905508195, -0.14992554543096048, -0.23895063760573976, -0.06023697929504124, -0.12812101661802444, -0.09587533766170964, -0.06573834768005327, -0.08230875854678743, -0.06855348777162362, -0.06198922409021179, -0.1419725762689268, -0.06890123921300528, -0.08921964069486421, -0.18364240613743732, -0.11436283684997761, -0.11593645969992394, -0.16716190798342723, -0.06391555874256483, -0.09051141243799066, -0.0729485257052147, -0.05367283832129033, -0.11343447622266467, -0.02050651017907512, 0.006832489844782685, -0.1325800128897754, -0.1242910776163626, -0.10636951217747992, -0.13562812729287543, -0.16616440726102155, -0.11576226352917729, -0.2106204456171099, -0.1342552628411795, 0.00957161104622628, -0.05992122040515824, -0.16805267345239372, -0.11593015229357206, -0.12379464202240342, -0.015167775842201081, -0.04592918711091443, -0.1301711047963181, -0.14054950689751422, -0.09737672386063423, -0.01006245765802305, -0.13582596782543988, -0.13116880652228247, -0.02706267018947983, -0.09752942258410258, -0.2058202018623092, -0.07124200906571332, -0.034823147136194166, -0.11032800284738187]}
\ No newline at end of file
added results/tables/rev_key_numbers.json +2527 −0
@@ -0,0 +1,2527 @@
1 +{
2 + "n_rating_truncated_fixed": 37,
3 + "n_unrated": 456,
4 + "n_new": 71,
5 + "n_bathrooms_recovered": 465,
6 + "n_bedrooms_recovered": 46,
7 + "n_studio_recoded": 161,
8 + "n_centres": 17,
9 + "mix": {
10 + "mu_lo": 153.77088749340422,
11 + "mu_hi": 2451.953092926835,
12 + "sd_lo": 0.630153879923939,
13 + "sd_hi": 0.8539860178647487,
14 + "w_lo": 0.6928374473264646,
15 + "w_hi": 0.3071625526735355,
16 + "threshold": 616.5471296193522
17 + },
18 + "share_gt1000": 0.2647569444444444,
19 + "n_gt1000": 915,
20 + "share_gt_mix": 0.3038194444444444,
21 + "share_le600": 0.6950231481481481,
22 + "price_median_all": 219.825,
23 + "price_mean_all": 1233.3454716435183,
24 + "bimodality_coefficient": 0.6042406721594321,
25 + "hartigan_note": "dip test not run (package not installed)",
26 + "median_ratio_by_bedrooms": {
27 + "0": 44.56190476190476,
28 + "1": 18.53488372093023,
29 + "2": 16.905151899125382,
30 + "3": 18.616675054521053,
31 + "4": 17.101124218778892,
32 + "5": 10.023025281321356
33 + },
34 + "mixreg": {
35 + "iterations": 16,
36 + "loglik": -4323.4075377283425,
37 + "delta": 3.1538760760658477,
38 + "implied_nights": 23.426692469164372,
39 + "sigma_nightly": 0.4930596821037612,
40 + "sigma_stay": 0.568412403267213,
41 + "share_stay": 0.2830733720640172,
42 + "n_stay": 976,
43 + "n_nightly": 2480,
44 + "gamma": {
45 + "const": [
46 + 1.4663890984648664,
47 + 0.14130219045961614,
48 + 3.1329182092802837e-25
49 + ],
50 + "is_montreal": [
51 + 0.6217080701961774,
52 + 0.09550911803762151,
53 + 7.544621451784356e-11
54 + ],
55 + "ln_reviews": [
56 + -0.3314164104565698,
57 + 0.02724298487393502,
58 + 4.762665083314056e-34
59 + ],
60 + "ln_guests": [
61 + -0.8893292542914106,
62 + 0.07283785470014474,
63 + 2.7586273159291313e-34
64 + ],
65 + "is_superhost": [
66 + -0.5882541479045038,
67 + 0.08713473859201455,
68 + 1.4674218574027064e-11
69 + ],
70 + "hotel": [
71 + -0.9473110632336585,
72 + 0.1908621650205798,
73 + 6.929627817321296e-07
74 + ],
75 + "chalet": [
76 + -0.25495600619170666,
77 + 0.12107078078766685,
78 + 0.03521802819239639
79 + ]
80 + },
81 + "beta_common": {
82 + "const": 3.286929637912328,
83 + "ln_bedrooms": 0.15314431041772164,
84 + "ln_bathrooms": 0.40271816511819797,
85 + "ln_guests": 0.3793649111146694,
86 + "shared_bath": -0.40765592392943106,
87 + "studio": 0.107869896218951,
88 + "ln_amenities": 0.040319046833442305,
89 + "ln_images": 0.08607649947110048,
90 + "is_superhost": -0.009758575640060062,
91 + "is_guest_favorite": -0.01912273808046353,
92 + "ln_reviews": 0.02923865039953598,
93 + "rated": -0.05088821033321356,
94 + "rating_c": 0.2732793687130732,
95 + "ln_dist": 0.007901398153118196,
96 + "ln_density_1km": 0.07242334091763829,
97 + "is_montreal": 0.0055701254700365075,
98 + "Chalet/cottage/cabin": 0.19021453349049058,
99 + "House": 0.13678142769510965,
100 + "Condo/loft/apartment": 0.05654554716446807,
101 + "Hotel/B&B/hostel": 0.26227319742372623,
102 + "Other/unconventional": 0.4636548534073407
103 + },
104 + "n_stay_le1000": 83,
105 + "n_nightly_gt1000": 22,
106 + "n_ambiguous_25_75": 7,
107 + "entropy_R2": 0.9959369257734693
108 + },
109 + "logit": {
110 + "ln_bedrooms": [
111 + 0.9142104715715227,
112 + 0.16919856561943578,
113 + 6.546934369977573e-08,
114 + 0.1466274047082403
115 + ],
116 + "ln_bathrooms": [
117 + -0.2700324680607087,
118 + 0.20364342505533886,
119 + 0.18483760494750345,
120 + -0.04330967672098573
121 + ],
122 + "ln_guests": [
123 + -1.4507877614598306,
124 + 0.13761522708991003,
125 + 5.510498439536974e-26,
126 + -0.23268738530161331
127 + ],
128 + "ln_amenities": [
129 + 0.01581977725984349,
130 + 0.1289453866275109,
131 + 0.9023558514775671,
132 + 0.0025372854006866547
133 + ],
134 + "is_superhost": [
135 + -0.41717732437458394,
136 + 0.09268762451407359,
137 + 6.766772752227413e-06,
138 + -0.06690978749239514
139 + ],
140 + "is_guest_favorite": [
141 + -0.6087445344185878,
142 + 0.11327858490770687,
143 + 7.706387986311999e-08,
144 + -0.09763466290064295
145 + ],
146 + "rated": [
147 + 0.11343904375394957,
148 + 0.15325021527490318,
149 + 0.4591658432863789,
150 + 0.018194139200389606
151 + ],
152 + "ln_reviews": [
153 + -0.3141566612339408,
154 + 0.03669997013689006,
155 + 1.1273643628443015e-17,
156 + -0.05038662030347871
157 + ],
158 + "is_montreal": [
159 + 0.3653523490195677,
160 + 0.11370858156542563,
161 + 0.001313294385790803,
162 + 0.058597739149400405
163 + ],
164 + "ln_dist": [
165 + -0.059125183325821895,
166 + 0.03971098345545579,
167 + 0.13651701927456716,
168 + -0.009482906238277456
169 + ],
170 + "Chalet/cottage/cabin": [
171 + -0.41943663547274096,
172 + 0.15242844981710332,
173 + 0.005928767212603852,
174 + -0.06727215144801887
175 + ],
176 + "House": [
177 + -0.306174008603945,
178 + 0.13740679750724802,
179 + 0.025865152307288905,
180 + -0.049106307209042487
181 + ],
182 + "Condo/loft/apartment": [
183 + -0.021507390209264135,
184 + 0.13537251144997908,
185 + 0.8737668777263425,
186 + -0.0034495041420941597
187 + ],
188 + "Hotel/B&B/hostel": [
189 + -0.9772041792025483,
190 + 0.20911201983905678,
191 + 2.9666787477180154e-06,
192 + -0.1567307716572195
193 + ],
194 + "Other/unconventional": [
195 + -0.34630836157262995,
196 + 0.2740484436435783,
197 + 0.20634644691466075,
198 + -0.05554333259700015
199 + ]
200 + },
201 + "N_A": 2480,
202 + "N_priced": 3456,
203 + "N_scraped": 5000,
204 + "A_price_median": 161.535,
205 + "A_price_mean": 205.94020262096774,
206 + "A_share_montreal": 0.20403225806451614,
207 + "A_n_cities": 438,
208 + "A_unrated_share": 0.09435483870967742,
209 + "A_superhost": 0.5903225806451613,
210 + "A_guestfav": 0.40846774193548385,
211 + "A_cat_shares": {
212 + "Chalet/cottage/cabin": 0.302,
213 + "Rental unit": 0.281,
214 + "House": 0.202,
215 + "Condo/loft/apartment": 0.123,
216 + "Hotel/B&B/hostel": 0.058,
217 + "Other/unconventional": 0.033
218 + },
219 + "A_p1_clip_n": 35,
220 + "A_price_max": 1883.0,
221 + "A_share_gt1000": 0.008870967741935484,
222 + "n_city_fe": 26,
223 + "n_cell_fe": 25,
224 + "share_in_city_fe": 0.5447580645161291,
225 + "n_fe_groups": 51,
226 + "vif_max": 4.162945773930223,
227 + "vif_argmax": "ln_bedrooms",
228 + "vif": {
229 + "ln_bedrooms": 4.162945773930223,
230 + "ln_bathrooms": 1.8035029907471043,
231 + "ln_guests": 3.779433227681465,
232 + "shared_bath": 1.2695350734665483,
233 + "studio": 1.0776041288380251,
234 + "Chalet/cottage/cabin": 2.5434732534069404,
235 + "House": 1.97634633911515,
236 + "Condo/loft/apartment": 1.3019128378679352,
237 + "Hotel/B&B/hostel": 1.328059585081074,
238 + "Other/unconventional": 1.2438815200158295,
239 + "ln_amenities": 1.5507566528332453,
240 + "pets_allowed": 1.1132502563952975,
241 + "ln_images": 1.6227049713111497,
242 + "is_superhost": 1.3630867917844613,
243 + "is_guest_favorite": 1.6928535457606315,
244 + "ln_reviews": 1.8676953310461935,
245 + "rated": 1.6734659457935754,
246 + "rating_c": 1.5252112432309566,
247 + "ln_dist": 2.155322601073838,
248 + "ln_density_1km": 2.2470498022617575
249 + },
250 + "ols": {
251 + "M1": {
252 + "n": 2480,
253 + "r2": 0.44263822400564756,
254 + "adj": 0.4403807846537061,
255 + "rmse": 0.5064864421359869,
256 + "aic": 3685.8568166362725,
257 + "params": {
258 + "ln_bedrooms": [
259 + 0.16761240925175003,
260 + 0.04260921959409954,
261 + 8.364390893110487e-05
262 + ],
263 + "ln_bathrooms": [
264 + 0.5597109843360168,
265 + 0.06339217380770512,
266 + 1.0529625387052362e-18
267 + ],
268 + "ln_guests": [
269 + 0.3507958539945729,
270 + 0.037508776861682906,
271 + 8.570764217280655e-21
272 + ],
273 + "shared_bath": [
274 + -0.4411048180825041,
275 + 0.052869832440709134,
276 + 7.229246978477407e-17
277 + ],
278 + "studio": [
279 + 0.18909367108686725,
280 + 0.06138178135256848,
281 + 0.0020657317259215884
282 + ],
283 + "Chalet/cottage/cabin": [
284 + 0.0447058050991084,
285 + 0.028082635821788077,
286 + 0.11139871622747118
287 + ],
288 + "House": [
289 + -0.028247273625961827,
290 + 0.031244978849344775,
291 + 0.3659646383506927
292 + ],
293 + "Condo/loft/apartment": [
294 + -0.05177631147371159,
295 + 0.03665819398966698,
296 + 0.15782998253510783
297 + ],
298 + "Hotel/B&B/hostel": [
299 + 0.007504293622442135,
300 + 0.04602944439969795,
301 + 0.8704928760009069
302 + ],
303 + "Other/unconventional": [
304 + 0.041553219719628165,
305 + 0.08016632246089596,
306 + 0.6042227387643477
307 + ]
308 + }
309 + },
310 + "M2": {
311 + "n": 2480,
312 + "r2": 0.4542912071011792,
313 + "adj": 0.45141439675743034,
314 + "rmse": 0.5011638184479476,
315 + "aic": 3639.4567725592315,
316 + "params": {
317 + "ln_bedrooms": [
318 + 0.15421043710158608,
319 + 0.041979628568790096,
320 + 0.00023928924943983953
321 + ],
322 + "ln_bathrooms": [
323 + 0.5135180679521034,
324 + 0.06419749997049821,
325 + 1.253977753842558e-15
326 + ],
327 + "ln_guests": [
328 + 0.3241872233078001,
329 + 0.037325824539973816,
330 + 3.776337789080514e-18
331 + ],
332 + "shared_bath": [
333 + -0.42863071109305373,
334 + 0.05244589470580936,
335 + 3.0127025031782064e-16
336 + ],
337 + "studio": [
338 + 0.2101732278585008,
339 + 0.06274423797274907,
340 + 0.000809044627373432
341 + ],
342 + "Chalet/cottage/cabin": [
343 + 0.009908533380073692,
344 + 0.028572607727770215,
345 + 0.7287533305171656
346 + ],
347 + "House": [
348 + -0.034755979138617665,
349 + 0.030969972430008208,
350 + 0.26175715280358025
351 + ],
352 + "Condo/loft/apartment": [
353 + -0.06340564677742885,
354 + 0.036465395529084066,
355 + 0.08207179659332967
356 + ],
357 + "Hotel/B&B/hostel": [
358 + 0.02380391546629869,
359 + 0.04695222424158648,
360 + 0.6121677036952544
361 + ],
362 + "Other/unconventional": [
363 + 0.06264506796695338,
364 + 0.08010034522301403,
365 + 0.4341661660057031
366 + ],
367 + "ln_amenities": [
368 + 0.07127875561296688,
369 + 0.03491233806132408,
370 + 0.041186316922570146
371 + ],
372 + "pets_allowed": [
373 + -0.048415561217792266,
374 + 0.02295055188466095,
375 + 0.034896291643041026
376 + ],
377 + "ln_images": [
378 + 0.11457894698106443,
379 + 0.022013040151773678,
380 + 1.939456916275183e-07
381 + ]
382 + }
383 + },
384 + "M3": {
385 + "n": 2480,
386 + "r2": 0.46084658671510614,
387 + "adj": 0.45690316475690695,
388 + "rmse": 0.49814458444122245,
389 + "aic": 3619.485151791433,
390 + "params": {
391 + "ln_bedrooms": [
392 + 0.1582463545175472,
393 + 0.04194390707074003,
394 + 0.00016141979277414553
395 + ],
396 + "ln_bathrooms": [
397 + 0.5072839079433789,
398 + 0.06501803682949893,
399 + 6.0835784888835145e-15
400 + ],
401 + "ln_guests": [
402 + 0.3271636602665066,
403 + 0.03760067707643028,
404 + 3.2895923429040145e-18
405 + ],
406 + "shared_bath": [
407 + -0.42339392775641405,
408 + 0.052639039021301154,
409 + 8.741908061624572e-16
410 + ],
411 + "studio": [
412 + 0.21348967523929196,
413 + 0.06283093732060907,
414 + 0.0006791932808481804
415 + ],
416 + "Chalet/cottage/cabin": [
417 + 0.0030055979495089424,
418 + 0.028651202898795133,
419 + 0.9164527559661699
420 + ],
421 + "House": [
422 + -0.03701716688064258,
423 + 0.0315724990864286,
424 + 0.24101655816831902
425 + ],
426 + "Condo/loft/apartment": [
427 + -0.07088769222114899,
428 + 0.036460475130595464,
429 + 0.051867249994961395
430 + ],
431 + "Hotel/B&B/hostel": [
432 + 0.04405502626850119,
433 + 0.04748204160916038,
434 + 0.3534983426252033
435 + ],
436 + "Other/unconventional": [
437 + 0.0468513026623531,
438 + 0.08099991681065936,
439 + 0.562986170990881
440 + ],
441 + "ln_amenities": [
442 + 0.048037000278275135,
443 + 0.03728303213070741,
444 + 0.1975923723253863
445 + ],
446 + "pets_allowed": [
447 + -0.04355280720371399,
448 + 0.02287244029032874,
449 + 0.0568892281861587
450 + ],
451 + "ln_images": [
452 + 0.1043261532732484,
453 + 0.021919887146859156,
454 + 1.941411073577041e-06
455 + ],
456 + "is_superhost": [
457 + 0.004975649171436142,
458 + 0.024142293047871563,
459 + 0.8367153038602886
460 + ],
461 + "is_guest_favorite": [
462 + -0.05501702758246663,
463 + 0.026931610515879896,
464 + 0.041068072219363747
465 + ],
466 + "ln_reviews": [
467 + 0.019896112887316332,
468 + 0.00979230709290444,
469 + 0.04217283847047334
470 + ],
471 + "rated": [
472 + -0.055907170523356586,
473 + 0.049056818204559025,
474 + 0.25443581883499033
475 + ],
476 + "rating_c": [
477 + 0.30957784831030044,
478 + 0.06919477354991768,
479 + 7.676750161631797e-06
480 + ]
481 + }
482 + },
483 + "M4": {
484 + "n": 2480,
485 + "r2": 0.4788241456155925,
486 + "adj": 0.47458522040709794,
487 + "rmse": 0.48976909512964445,
488 + "aic": 3539.3818071670853,
489 + "params": {
490 + "ln_bedrooms": [
491 + 0.16369982823164833,
492 + 0.04179148565877393,
493 + 8.963481007649491e-05
494 + ],
495 + "ln_bathrooms": [
496 + 0.46445640411565225,
497 + 0.06659940538644056,
498 + 3.0831239361149896e-12
499 + ],
500 + "ln_guests": [
501 + 0.3206923540920547,
502 + 0.03711451112645845,
503 + 5.590921831492282e-18
504 + ],
505 + "shared_bath": [
506 + -0.402578903366514,
507 + 0.05206549606067415,
508 + 1.0573441917958251e-14
509 + ],
510 + "studio": [
511 + 0.17945423777688385,
512 + 0.061712357531194986,
513 + 0.003638482064490805
514 + ],
515 + "Chalet/cottage/cabin": [
516 + 0.15350745018386805,
517 + 0.03280731723589922,
518 + 2.881912041330007e-06
519 + ],
520 + "House": [
521 + 0.0946262210591518,
522 + 0.0328849564670004,
523 + 0.004008492277568609
524 + ],
525 + "Condo/loft/apartment": [
526 + -0.04344489863200132,
527 + 0.035081937256192346,
528 + 0.21557382829132732
529 + ],
530 + "Hotel/B&B/hostel": [
531 + 0.1222053248080851,
532 + 0.04867165257009721,
533 + 0.012045413903418845
534 + ],
535 + "Other/unconventional": [
536 + 0.18764993471194438,
537 + 0.09177471145804265,
538 + 0.04088639763504444
539 + ],
540 + "ln_amenities": [
541 + 0.06715839313969603,
542 + 0.036967801508005604,
543 + 0.06926725523736736
544 + ],
545 + "pets_allowed": [
546 + -0.031767342559650226,
547 + 0.022705991571961397,
548 + 0.16179105620995815
549 + ],
550 + "ln_images": [
551 + 0.09195758519663523,
552 + 0.021558987227366554,
553 + 1.9954930575653047e-05
554 + ],
555 + "is_superhost": [
556 + 0.00807498846605803,
557 + 0.02402503717169913,
558 + 0.7367900136867855
559 + ],
560 + "is_guest_favorite": [
561 + -0.03435288422984997,
562 + 0.027019279725350866,
563 + 0.20357885537057896
564 + ],
565 + "ln_reviews": [
566 + 0.015198091748896286,
567 + 0.009965270658419158,
568 + 0.1272327190814888
569 + ],
570 + "rated": [
571 + -0.03320092860989346,
572 + 0.04972913732680003,
573 + 0.5043664049694842
574 + ],
575 + "rating_c": [
576 + 0.32838012791299664,
577 + 0.06772806751654992,
578 + 1.2439304575485863e-06
579 + ],
580 + "ln_dist": [
581 + -0.0024893565274826668,
582 + 0.009886931599817112,
583 + 0.8012091711789058
584 + ],
585 + "ln_density_1km": [
586 + 0.06743464418175753,
587 + 0.009110985111266116,
588 + 1.3468942782095781e-13
589 + ]
590 + }
591 + },
592 + "M5": {
593 + "n": 2480,
594 + "r2": 0.5092128435240746,
595 + "adj": 0.49495169742473266,
596 + "rmse": 0.4752759387162895,
597 + "aic": 3490.3909134700953,
598 + "params": {
599 + "ln_bedrooms": [
600 + 0.16037959113473327,
601 + 0.042256614765418136,
602 + 0.00014742197812739
603 + ],
604 + "ln_bathrooms": [
605 + 0.4370493241677571,
606 + 0.06985669083618966,
607 + 3.9404057286738434e-10
608 + ],
609 + "ln_guests": [
610 + 0.33054607122260554,
611 + 0.03715745952465234,
612 + 5.798951153381131e-19
613 + ],
614 + "shared_bath": [
615 + -0.3852156802298401,
616 + 0.053030086267547565,
617 + 3.7553900184973707e-13
618 + ],
619 + "studio": [
620 + 0.14700116306818783,
621 + 0.061764579308518204,
622 + 0.0173115242344519
623 + ],
624 + "Chalet/cottage/cabin": [
625 + 0.09895574360559198,
626 + 0.03714850781859669,
627 + 0.007726627556012316
628 + ],
629 + "House": [
630 + 0.07878810705082637,
631 + 0.03367147902115612,
632 + 0.01928857666987974
633 + ],
634 + "Condo/loft/apartment": [
635 + -0.03222439725966181,
636 + 0.03713260008102348,
637 + 0.3854931115762338
638 + ],
639 + "Hotel/B&B/hostel": [
640 + 0.07942050532332262,
641 + 0.0514124530282895,
642 + 0.12240148139667233
643 + ],
644 + "Other/unconventional": [
645 + 0.13545114955811516,
646 + 0.09393782551400624,
647 + 0.1493239816884043
648 + ],
649 + "ln_amenities": [
650 + 0.09381153603820874,
651 + 0.037886817409241574,
652 + 0.013282649237946293
653 + ],
654 + "pets_allowed": [
655 + -0.04369185869123088,
656 + 0.022769263028120063,
657 + 0.054997436126974254
658 + ],
659 + "ln_images": [
660 + 0.0868346519710263,
661 + 0.022108590277562557,
662 + 8.578238286157527e-05
663 + ],
664 + "is_superhost": [
665 + 0.023486383134939143,
666 + 0.024818511551896794,
667 + 0.3439827392898118
668 + ],
669 + "is_guest_favorite": [
670 + -0.034839398616947514,
671 + 0.027213851826825244,
672 + 0.20047189237331287
673 + ],
674 + "ln_reviews": [
675 + 0.015229397552798299,
676 + 0.010074419286461555,
677 + 0.13061277758192388
678 + ],
679 + "rated": [
680 + -0.04148667846287993,
681 + 0.04957636440445212,
682 + 0.4026916534816066
683 + ],
684 + "rating_c": [
685 + 0.33711305141158954,
686 + 0.06776193219331096,
687 + 6.526037251407198e-07
688 + ],
689 + "ln_dist": [
690 + -0.034582568741214244,
691 + 0.018810864701210992,
692 + 0.06599820100926677
693 + ],
694 + "ln_density_1km": [
695 + 0.06433942862434755,
696 + 0.013000869205396785,
697 + 7.465097722387647e-07
698 + ]
699 + }
700 + },
701 + "M5_cluster_city": {
702 + "ln_bedrooms": [
703 + 0.16037959113473327,
704 + 0.0679774691845062,
705 + 0.018309194663742357
706 + ],
707 + "ln_bathrooms": [
708 + 0.4370493241677571,
709 + 0.08916855885162871,
710 + 9.516396281188445e-07
711 + ],
712 + "ln_guests": [
713 + 0.33054607122260554,
714 + 0.03496768047927685,
715 + 3.295631469442305e-21
716 + ],
717 + "shared_bath": [
718 + -0.3852156802298401,
719 + 0.06053312554998042,
720 + 1.969288360065427e-10
721 + ],
722 + "studio": [
723 + 0.14700116306818783,
724 + 0.08881662302948402,
725 + 0.09790245594371205
726 + ],
727 + "Chalet/cottage/cabin": [
728 + 0.09895574360559198,
729 + 0.03942838356819626,
730 + 0.012081355603610825
731 + ],
732 + "House": [
733 + 0.07878810705082637,
734 + 0.048976918624827975,
735 + 0.10768669930182011
736 + ],
737 + "Condo/loft/apartment": [
738 + -0.03222439725966181,
739 + 0.03798793379487528,
740 + 0.39628215897449026
741 + ],
742 + "Hotel/B&B/hostel": [
743 + 0.07942050532332262,
744 + 0.04543994974480786,
745 + 0.0804965261807161
746 + ],
747 + "Other/unconventional": [
748 + 0.13545114955811516,
749 + 0.10211585917337165,
750 + 0.1846920863609659
751 + ],
752 + "ln_amenities": [
753 + 0.09381153603820874,
754 + 0.0384940124902476,
755 + 0.014807947788072652
756 + ],
757 + "pets_allowed": [
758 + -0.04369185869123088,
759 + 0.028947548400884603,
760 + 0.13121045301027817
761 + ],
762 + "ln_images": [
763 + 0.0868346519710263,
764 + 0.02375960812817445,
765 + 0.0002574654716418752
766 + ],
767 + "is_superhost": [
768 + 0.023486383134939143,
769 + 0.032071332422060395,
770 + 0.463975082892472
771 + ],
772 + "is_guest_favorite": [
773 + -0.034839398616947514,
774 + 0.032187144003189186,
775 + 0.27907435984501083
776 + ],
777 + "ln_reviews": [
778 + 0.015229397552798299,
779 + 0.026437515946571854,
780 + 0.5645796861121621
781 + ],
782 + "rated": [
783 + -0.04148667846287993,
784 + 0.04393327153615789,
785 + 0.3450106663565041
786 + ],
787 + "rating_c": [
788 + 0.33711305141158954,
789 + 0.06536195507705876,
790 + 2.5008966748240215e-07
791 + ],
792 + "ln_dist": [
793 + -0.034582568741214244,
794 + 0.024222171258651365,
795 + 0.1533713926404969
796 + ],
797 + "ln_density_1km": [
798 + 0.06433942862434755,
799 + 0.022596714383060296,
800 + 0.0044092992582498705
801 + ]
802 + },
803 + "M5_cluster_cell60": {
804 + "ln_bedrooms": [
805 + 0.16037959113473327,
806 + 0.07100447295121669,
807 + 0.02390048499313011
808 + ],
809 + "ln_bathrooms": [
810 + 0.4370493241677571,
811 + 0.10000149238527126,
812 + 1.2400322825566377e-05
813 + ],
814 + "ln_guests": [
815 + 0.33054607122260554,
816 + 0.032291437757482264,
817 + 1.3629796935705864e-24
818 + ],
819 + "shared_bath": [
820 + -0.3852156802298401,
821 + 0.04467013728153148,
822 + 6.4903241098446585e-18
823 + ],
824 + "studio": [
825 + 0.14700116306818783,
826 + 0.08907556426872236,
827 + 0.0988821445781848
828 + ],
829 + "Chalet/cottage/cabin": [
830 + 0.09895574360559198,
831 + 0.04064330104239242,
832 + 0.014902622311480785
833 + ],
834 + "House": [
835 + 0.07878810705082637,
836 + 0.039558719211898734,
837 + 0.04640674241392626
838 + ],
839 + "Condo/loft/apartment": [
840 + -0.03222439725966181,
841 + 0.04596538870351961,
842 + 0.48326690421854557
843 + ],
844 + "Hotel/B&B/hostel": [
845 + 0.07942050532332262,
846 + 0.046718500509667096,
847 + 0.08913473253084452
848 + ],
849 + "Other/unconventional": [
850 + 0.13545114955811516,
851 + 0.10219903615984086,
852 + 0.1850497174878818
853 + ],
854 + "ln_amenities": [
855 + 0.09381153603820874,
856 + 0.04073692280432999,
857 + 0.021286574924811914
858 + ],
859 + "pets_allowed": [
860 + -0.04369185869123088,
861 + 0.02065143599420342,
862 + 0.034371914884304855
863 + ],
864 + "ln_images": [
865 + 0.0868346519710263,
866 + 0.025662994476687698,
867 + 0.0007152850682130997
868 + ],
869 + "is_superhost": [
870 + 0.023486383134939143,
871 + 0.034131920841476676,
872 + 0.4913859657273255
873 + ],
874 + "is_guest_favorite": [
875 + -0.034839398616947514,
876 + 0.03287593736238796,
877 + 0.2892704747794784
878 + ],
879 + "ln_reviews": [
880 + 0.015229397552798299,
881 + 0.026031221423011057,
882 + 0.558518450689278
883 + ],
884 + "rated": [
885 + -0.04148667846287993,
886 + 0.03769519726766716,
887 + 0.2710783590238732
888 + ],
889 + "rating_c": [
890 + 0.33711305141158954,
891 + 0.05557077514774109,
892 + 1.3083106836832654e-09
893 + ],
894 + "ln_dist": [
895 + -0.034582568741214244,
896 + 0.02065083185793459,
897 + 0.09400622015560971
898 + ],
899 + "ln_density_1km": [
900 + 0.06433942862434755,
901 + 0.022784810615651296,
902 + 0.004746006558813734
903 + ]
904 + }
905 + },
906 + "premia_M5": {
907 + "Chalet/cottage/cabin": 10.325592294756692,
908 + "House": 8.136185410972342,
909 + "Condo/loft/apartment": -3.2378046849697806,
910 + "Hotel/B&B/hostel": 8.122957094323692,
911 + "Other/unconventional": 14.001223183306099,
912 + "shared_bath": -32.06520074374303,
913 + "studio": 15.614793259958692,
914 + "pets_allowed": -4.299922562540348,
915 + "is_superhost": 2.3449110550396224,
916 + "is_guest_favorite": -3.4597045607760224,
917 + "rated": -4.181612817507974
918 + },
919 + "ftests_M5": {
920 + "category": [
921 + 2.541458091083649,
922 + 0.026550517115463683
923 + ],
924 + "host": [
925 + 7.139633739661828,
926 + 1.2187879220839864e-06
927 + ],
928 + "amenities": [
929 + 10.13106075293794,
930 + 1.2469917747095749e-06
931 + ],
932 + "location": [
933 + 19.95278637142414,
934 + 2.5445091476727245e-09
935 + ],
936 + "city_fe": [
937 + 3.696388393601828,
938 + 1.5198501250827734e-16
939 + ]
940 + },
941 + "r2_within_fe_only": 0.1303295748225758,
942 + "quantile": {
943 + "0.1": {
944 + "ln_bedrooms": [
945 + 0.014388835246791132,
946 + 0.053370453477507726,
947 + 0.7874887699558268
948 + ],
949 + "ln_bathrooms": [
950 + 0.24056145502254367,
951 + 0.0775806860933295,
952 + 0.0019523821960107381
953 + ],
954 + "ln_guests": [
955 + 0.37379323977802414,
956 + 0.04836205506570821,
957 + 1.5787422432466235e-14
958 + ],
959 + "shared_bath": [
960 + -0.26714970173998154,
961 + 0.06696453862906604,
962 + 6.821086813223068e-05
963 + ],
964 + "Chalet/cottage/cabin": [
965 + 0.02377185879595345,
966 + 0.05308386235183899,
967 + 0.6543255020459158
968 + ],
969 + "House": [
970 + 0.01662008991388575,
971 + 0.048472664608211855,
972 + 0.731722027149276
973 + ],
974 + "Condo/loft/apartment": [
975 + -0.18321777953588025,
976 + 0.048912943724495866,
977 + 0.00018404346939137576
978 + ],
979 + "Hotel/B&B/hostel": [
980 + -0.09128192915522959,
981 + 0.0688995690356892,
982 + 0.18534494848282906
983 + ],
984 + "ln_amenities": [
985 + 0.05293063879071269,
986 + 0.04782289005536768,
987 + 0.2684885276362751
988 + ],
989 + "ln_images": [
990 + 0.08500441657452029,
991 + 0.027995401464587,
992 + 0.0024200976139148525
993 + ],
994 + "is_superhost": [
995 + 0.08056781868253893,
996 + 0.03157595345407988,
997 + 0.010785578974259757
998 + ],
999 + "is_guest_favorite": [
1000 + -0.04986095681670122,
1001 + 0.03625957049357945,
1002 + 0.16922471015797597
1003 + ],
1004 + "ln_reviews": [
1005 + 0.04192779592176521,
1006 + 0.014582769102391478,
1007 + 0.0040736684041473605
1008 + ],
1009 + "rated": [
1010 + -0.0516142862761626,
1011 + 0.06367254291423337,
1012 + 0.41766355350666906
1013 + ],
1014 + "rating_c": [
1015 + 0.35511187111842446,
1016 + 0.08410141071925122,
1017 + 2.506581436137723e-05
1018 + ],
1019 + "ln_dist": [
1020 + 0.008447302781860344,
1021 + 0.02689551560122966,
1022 + 0.7534886254451889
1023 + ],
1024 + "ln_density_1km": [
1025 + 0.09990591703171958,
1026 + 0.016823902674955312,
1027 + 3.295498906094871e-09
1028 + ]
1029 + },
1030 + "0.25": {
1031 + "ln_bedrooms": [
1032 + 0.09850155502658708,
1033 + 0.039356212243069906,
1034 + 0.01238652860616468
1035 + ],
1036 + "ln_bathrooms": [
1037 + 0.2983448893901368,
1038 + 0.053046939334582884,
1039 + 2.07948679979627e-08
1040 + ],
1041 + "ln_guests": [
1042 + 0.39868330813806097,
1043 + 0.03560558353702885,
1044 + 2.088479427355765e-28
1045 + ],
1046 + "shared_bath": [
1047 + -0.3324508718214929,
1048 + 0.05074031902365573,
1049 + 6.918243368262528e-11
1050 + ],
1051 + "Chalet/cottage/cabin": [
1052 + 0.06840752186963073,
1053 + 0.040001505727625106,
1054 + 0.08737177210101625
1055 + ],
1056 + "House": [
1057 + 0.04047899265788146,
1058 + 0.037234344303931466,
1059 + 0.27708313811913987
1060 + ],
1061 + "Condo/loft/apartment": [
1062 + -0.03230464987427695,
1063 + 0.03712458867475345,
1064 + 0.3842949915202587
1065 + ],
1066 + "Hotel/B&B/hostel": [
1067 + 0.10074631205770856,
1068 + 0.05251769049839844,
1069 + 0.05518713499534293
1070 + ],
1071 + "ln_amenities": [
1072 + 0.10990580401266925,
1073 + 0.03618609972262262,
1074 + 0.00241316998072353
1075 + ],
1076 + "ln_images": [
1077 + 0.09952742358495925,
1078 + 0.021547014118734217,
1079 + 4.057301575510199e-06
1080 + ],
1081 + "is_superhost": [
1082 + 0.05244454099829454,
1083 + 0.024870219990921687,
1084 + 0.035071003113615565
1085 + ],
1086 + "is_guest_favorite": [
1087 + -0.033740271706165004,
1088 + 0.02762290749963924,
1089 + 0.22203148846702506
1090 + ],
1091 + "ln_reviews": [
1092 + 0.03725659229326084,
1093 + 0.010354375004824484,
1094 + 0.0003269469158160094
1095 + ],
1096 + "rated": [
1097 + -0.055836991745309206,
1098 + 0.04842568533342118,
1099 + 0.24900633147286588
1100 + ],
1101 + "rating_c": [
1102 + 0.34028654593930696,
1103 + 0.06546114834597577,
1104 + 2.180282436263711e-07
1105 + ],
1106 + "ln_dist": [
1107 + -0.013992047137435293,
1108 + 0.021292830521128597,
1109 + 0.5111634432636584
1110 + ],
1111 + "ln_density_1km": [
1112 + 0.0796845493409819,
1113 + 0.013482274523940388,
1114 + 3.898345108944167e-09
1115 + ]
1116 + },
1117 + "0.5": {
1118 + "ln_bedrooms": [
1119 + 0.16887310600122873,
1120 + 0.03349171192038829,
1121 + 4.94367312600157e-07
1122 + ],
1123 + "ln_bathrooms": [
1124 + 0.4007514272871049,
1125 + 0.04442418215010478,
1126 + 3.710347560274951e-19
1127 + ],
1128 + "ln_guests": [
1129 + 0.3459038093305935,
1130 + 0.030582064704443652,
1131 + 6.150156330460204e-29
1132 + ],
1133 + "shared_bath": [
1134 + -0.4137221154460349,
1135 + 0.04536313307843552,
1136 + 1.5382420743132541e-19
1137 + ],
1138 + "Chalet/cottage/cabin": [
1139 + 0.11685191250489879,
1140 + 0.03584445459817927,
1141 + 0.001129749588182396
1142 + ],
1143 + "House": [
1144 + 0.09913228032792176,
1145 + 0.03347158567309428,
1146 + 0.003089527757216528
1147 + ],
1148 + "Condo/loft/apartment": [
1149 + -0.017134034279479238,
1150 + 0.03356665321169777,
1151 + 0.6097843358017156
1152 + ],
1153 + "Hotel/B&B/hostel": [
1154 + 0.18103548736098674,
1155 + 0.04683964737521061,
1156 + 0.00011402283238731465
1157 + ],
1158 + "ln_amenities": [
1159 + 0.08639579682403564,
1160 + 0.03254437010771091,
1161 + 0.007989950186892492
1162 + ],
1163 + "ln_images": [
1164 + 0.10395163279463304,
1165 + 0.01946980087806192,
1166 + 1.0213974977428484e-07
1167 + ],
1168 + "is_superhost": [
1169 + 0.00618276486875402,
1170 + 0.022510648889621,
1171 + 0.7836013562633211
1172 + ],
1173 + "is_guest_favorite": [
1174 + 3.055566867260495e-05,
1175 + 0.02479431225251937,
1176 + 0.9990168164414377
1177 + ],
1178 + "ln_reviews": [
1179 + 0.006569828404735745,
1180 + 0.008090338700048423,
1181 + 0.4168382917907216
1182 + ],
1183 + "rated": [
1184 + 0.05417870626479271,
1185 + 0.04128297567575003,
1186 + 0.18951898053610675
1187 + ],
1188 + "rating_c": [
1189 + 0.2565024167961383,
1190 + 0.06141986044334217,
1191 + 3.069453557130273e-05
1192 + ],
1193 + "ln_dist": [
1194 + -0.04857847040693741,
1195 + 0.019557754121710395,
1196 + 0.013064674386103446
1197 + ],
1198 + "ln_density_1km": [
1199 + 0.04554650835461871,
1200 + 0.01187840761927125,
1201 + 0.0001291012626936838
1202 + ]
1203 + },
1204 + "0.75": {
1205 + "ln_bedrooms": [
1206 + 0.21371495782386773,
1207 + 0.03220401006565902,
1208 + 3.9600189307230787e-11
1209 + ],
1210 + "ln_bathrooms": [
1211 + 0.551491213052941,
1212 + 0.04681598693367102,
1213 + 3.489186062129805e-31
1214 + ],
1215 + "ln_guests": [
1216 + 0.3050868521540906,
1217 + 0.030619124657832897,
1218 + 6.053389045992983e-23
1219 + ],
1220 + "shared_bath": [
1221 + -0.38813499398025897,
1222 + 0.04657250153161377,
1223 + 1.295513187884936e-16
1224 + ],
1225 + "Chalet/cottage/cabin": [
1226 + 0.16576774586496867,
1227 + 0.035844284885418326,
1228 + 3.950510818773845e-06
1229 + ],
1230 + "House": [
1231 + 0.08669290145644482,
1232 + 0.033311287046845404,
1233 + 0.009311189645266322
1234 + ],
1235 + "Condo/loft/apartment": [
1236 + 0.013999605443018481,
1237 + 0.03429482334232286,
1238 + 0.6831533115661171
1239 + ],
1240 + "Hotel/B&B/hostel": [
1241 + 0.10748360189063533,
1242 + 0.04733886109896325,
1243 + 0.023264288311537703
1244 + ],
1245 + "ln_amenities": [
1246 + 0.031598088186001405,
1247 + 0.0337046806938865,
1248 + 0.3485961634305912
1249 + ],
1250 + "ln_images": [
1251 + 0.10040009546639794,
1252 + 0.02132043274395542,
1253 + 2.6293827073220384e-06
1254 + ],
1255 + "is_superhost": [
1256 + 0.024716105907373276,
1257 + 0.02324114037561433,
1258 + 0.28767836983631545
1259 + ],
1260 + "is_guest_favorite": [
1261 + -0.024206663716654475,
1262 + 0.025026895858464494,
1263 + 0.33352817151796277
1264 + ],
1265 + "ln_reviews": [
1266 + -0.025888147785167348,
1267 + 0.0075555292373471,
1268 + 0.0006219298743773638
1269 + ],
1270 + "rated": [
1271 + 0.05553484433403355,
1272 + 0.040740934700908726,
1273 + 0.1729716075155256
1274 + ],
1275 + "rating_c": [
1276 + 0.3422118129401497,
1277 + 0.06399122959859792,
1278 + 9.742140745232918e-08
1279 + ],
1280 + "ln_dist": [
1281 + -0.08233637353623635,
1282 + 0.018396223163780485,
1283 + 7.969723830283939e-06
1284 + ],
1285 + "ln_density_1km": [
1286 + 0.03287919002650597,
1287 + 0.01152315838088575,
1288 + 0.004363518381459732
1289 + ]
1290 + },
1291 + "0.9": {
1292 + "ln_bedrooms": [
1293 + 0.18737624716141,
1294 + 0.036812786882169025,
1295 + 3.857779276711292e-07
1296 + ],
1297 + "ln_bathrooms": [
1298 + 0.5508723393650143,
1299 + 0.057937213448807055,
1300 + 4.524559917778523e-21
1301 + ],
1302 + "ln_guests": [
1303 + 0.3069477833705605,
1304 + 0.03676509831958305,
1305 + 1.1462049012941908e-16
1306 + ],
1307 + "shared_bath": [
1308 + -0.3092654504762322,
1309 + 0.05630920769789687,
1310 + 4.384362128792153e-08
1311 + ],
1312 + "Chalet/cottage/cabin": [
1313 + 0.21352166005817708,
1314 + 0.04293417328990873,
1315 + 7.048428879142281e-07
1316 + ],
1317 + "House": [
1318 + 0.12112212008651113,
1319 + 0.03885481516038148,
1320 + 0.0018466945713876085
1321 + ],
1322 + "Condo/loft/apartment": [
1323 + 0.07741908296793554,
1324 + 0.03936581079928403,
1325 + 0.049337293911374466
1326 + ],
1327 + "Hotel/B&B/hostel": [
1328 + 0.06273857261112425,
1329 + 0.05760773001719728,
1330 + 0.2762340791065775
1331 + ],
1332 + "ln_amenities": [
1333 + 0.017071969457902014,
1334 + 0.04174668332989659,
1335 + 0.6826186250186822
1336 + ],
1337 + "ln_images": [
1338 + 0.1334138483471179,
1339 + 0.026882700299017605,
1340 + 7.433336129148411e-07
1341 + ],
1342 + "is_superhost": [
1343 + -0.0029823180302628316,
1344 + 0.027778005294255212,
1345 + 0.9145102880690449
1346 + ],
1347 + "is_guest_favorite": [
1348 + -0.08048814318317454,
1349 + 0.02932911750320333,
1350 + 0.0061088161476355995
1351 + ],
1352 + "ln_reviews": [
1353 + -0.042133774964895565,
1354 + 0.0083998051021746,
1355 + 5.659176352630538e-07
1356 + ],
1357 + "rated": [
1358 + 0.07153464204748161,
1359 + 0.0465945554809441,
1360 + 0.12485190103658608
1361 + ],
1362 + "rating_c": [
1363 + 0.38284558361192467,
1364 + 0.07601105233779093,
1365 + 5.086957208838833e-07
1366 + ],
1367 + "ln_dist": [
1368 + -0.07161137437799425,
1369 + 0.022227264326506874,
1370 + 0.0012909476090810772
1371 + ],
1372 + "ln_density_1km": [
1373 + 0.036828475265792804,
1374 + 0.013546330470160078,
1375 + 0.0066007864782477565
1376 + ]
1377 + }
1378 + },
1379 + "quantile_pseudoR2": {
1380 + "0.1": 0.27848434835535285,
1381 + "0.25": 0.29381360011105195,
1382 + "0.5": 0.3276689716742135,
1383 + "0.75": 0.3585111357552504,
1384 + "0.9": 0.40504935527032826
1385 + },
1386 + "iq_bootstrap_B": 100,
1387 + "iq_diff_90_10": {
1388 + "ln_bedrooms": [
1389 + 0.17298741191461886,
1390 + 0.09720166456170012,
1391 + 0.07512909753440322
1392 + ],
1393 + "ln_guests": [
1394 + -0.06684545640746364,
1395 + 0.0742160492847135,
1396 + 0.3677545789566954
1397 + ],
1398 + "is_superhost": [
1399 + -0.08355013671280176,
1400 + 0.05860190410429907,
1401 + 0.15394804776771776
1402 + ],
1403 + "rating_c": [
1404 + 0.027733712493500207,
1405 + 0.15634928426876507,
1406 + 0.8592075224249187
1407 + ],
1408 + "ln_reviews": [
1409 + -0.08406157088666077,
1410 + 0.023099002112665783,
1411 + 0.0002735009401002575
1412 + ],
1413 + "ln_dist": [
1414 + -0.0800586771598546,
1415 + 0.05865845886409837,
1416 + 0.1723072765864484
1417 + ]
1418 + },
1419 + "moran": {
1420 + "M4_k5": [
1421 + 0.12621953066927755,
1422 + 10.8141309341243,
1423 + 2.9507608653964498e-27
1424 + ],
1425 + "M5_k5": [
1426 + 0.07178364115302077,
1427 + 6.165076554569668,
1428 + 7.044904897769932e-10
1429 + ],
1430 + "lnp_k5": [
1431 + 0.24360986834309786,
1432 + 20.83976050185437,
1433 + 1.8878082316449425e-96
1434 + ],
1435 + "M4_k10": [
1436 + 0.09433955696935323,
1437 + 11.394076473836162,
1438 + 4.47550315626193e-30
1439 + ]
1440 + },
1441 + "spatial": {
1442 + "rho_sar": [
1443 + 0.19994873089039214,
1444 + 0.021990330146539075,
1445 + 9.672050865824256e-20
1446 + ],
1447 + "lam_sem": [
1448 + 0.2835601945529212,
1449 + 0.027710029414064672,
1450 + 1.4089794807825548e-24
1451 + ],
1452 + "rho_sdm": [
1453 + 0.26083834678726064,
1454 + 0.028209174612208125,
1455 + 2.3179377808444977e-20
1456 + ],
1457 + "rho_sar_k10": [
1458 + 0.2149746838436125,
1459 + 0.027287527083404216,
1460 + 3.3231706342858677e-15
1461 + ],
1462 + "ll": {
1463 + "ols": -1748.6909035835426,
1464 + "sar": -1710.6488821750415,
1465 + "sem": -1702.131247606501,
1466 + "sdm": -1684.2645920174623
1467 + },
1468 + "aic": {
1469 + "ols": 3539.3818071670853,
1470 + "sar": 3465.297764350083,
1471 + "sem": 3446.262495213002,
1472 + "sdm": 3452.5291840349246
1473 + },
1474 + "lr_sdm_vs_sar": [
1475 + 52.76858031515849,
1476 + 20,
1477 + 8.789011760368393e-05
1478 + ],
1479 + "sar_multiplier": 1.2499198971497403,
1480 + "sar_direct_ratio": 1.0064988248320483
1481 + },
1482 + "impacts": {
1483 + "ln_bedrooms": {
1484 + "sar": [
1485 + 0.1664738709911587,
1486 + 0.04026159513530178,
1487 + 0.2067354661264605
1488 + ],
1489 + "sar_se": [
1490 + 0.03213266240601395,
1491 + 0.009589703447441367,
1492 + 0.04024043427471471
1493 + ],
1494 + "sdm": [
1495 + 0.154459317003152,
1496 + 0.09767729409247675,
1497 + 0.25213661109562874
1498 + ],
1499 + "sdm_se": [
1500 + 0.03450738627270534,
1501 + 0.08605942606958929,
1502 + 0.09493570807987559
1503 + ]
1504 + },
1505 + "ln_bathrooms": {
1506 + "sar": [
1507 + 0.4468018088723599,
1508 + 0.10805872073158451,
1509 + 0.5548605296039444
1510 + ],
1511 + "sar_se": [
1512 + 0.04202366704744907,
1513 + 0.01816207726893526,
1514 + 0.05448338685949581
1515 + ],
1516 + "sdm": [
1517 + 0.44497992859761315,
1518 + 0.2534479307588752,
1519 + 0.6984278593564883
1520 + ],
1521 + "sdm_se": [
1522 + 0.042878474147017176,
1523 + 0.1167793874195416,
1524 + 0.12284800480065626
1525 + ]
1526 + },
1527 + "ln_guests": {
1528 + "sar": [
1529 + 0.3026145145643223,
1530 + 0.07318711936542699,
1531 + 0.3758016339297493
1532 + ],
1533 + "sar_se": [
1534 + 0.030464042768307917,
1535 + 0.012039545987565844,
1536 + 0.038285697281059204
1537 + ],
1538 + "sdm": [
1539 + 0.3301678811076552,
1540 + -0.0859806303787197,
1541 + 0.24418725072893552
1542 + ],
1543 + "sdm_se": [
1544 + 0.03204131473743363,
1545 + 0.07525768316312281,
1546 + 0.08128385738246101
1547 + ]
1548 + },
1549 + "shared_bath": {
1550 + "sar": [
1551 + -0.3853441747883372,
1552 + -0.0931952327455578,
1553 + -0.478539407533895
1554 + ],
1555 + "sar_se": [
1556 + 0.04410124603465046,
1557 + 0.016280839883745776,
1558 + 0.0558594551508529
1559 + ],
1560 + "sdm": [
1561 + -0.39144384598982757,
1562 + -0.14486943017316795,
1563 + -0.5363132761629955
1564 + ],
1565 + "sdm_se": [
1566 + 0.04832561042981522,
1567 + 0.1158529155514043,
1568 + 0.12018898566106392
1569 + ]
1570 + },
1571 + "Chalet/cottage/cabin": {
1572 + "sar": [
1573 + 0.09808431069395727,
1574 + 0.02372162539846863,
1575 + 0.1218059360924259
1576 + ],
1577 + "sar_se": [
1578 + 0.03440057193954418,
1579 + 0.008225609213664796,
1580 + 0.04207712000561669
1581 + ],
1582 + "sdm": [
1583 + 0.11484729258437702,
1584 + 0.02357504615375884,
1585 + 0.13842233873813586
1586 + ],
1587 + "sdm_se": [
1588 + 0.037104816105478146,
1589 + 0.07227562723210401,
1590 + 0.07628311649116383
1591 + ]
1592 + },
1593 + "House": {
1594 + "sar": [
1595 + 0.07305398123099514,
1596 + 0.01766805684178792,
1597 + 0.09072203807278306
1598 + ],
1599 + "sar_se": [
1600 + 0.032471564064442,
1601 + 0.00800406737649911,
1602 + 0.04011956460189813
1603 + ],
1604 + "sdm": [
1605 + 0.08922638159124176,
1606 + -0.05303514620483505,
1607 + 0.03619123538640671
1608 + ],
1609 + "sdm_se": [
1610 + 0.035178545802557,
1611 + 0.08752802717501458,
1612 + 0.09202639914011716
1613 + ]
1614 + },
1615 + "Condo/loft/apartment": {
1616 + "sar": [
1617 + -0.0410820585324856,
1618 + -0.009935668571361272,
1619 + -0.051017727103846874
1620 + ],
1621 + "sar_se": [
1622 + 0.035117559006744216,
1623 + 0.008730959763685526,
1624 + 0.04369292977074167
1625 + ],
1626 + "sdm": [
1627 + -0.018562699229839472,
1628 + -0.07644038752159098,
1629 + -0.09500308675143045
1630 + ],
1631 + "sdm_se": [
1632 + 0.03306048288905836,
1633 + 0.08109636324101674,
1634 + 0.08606906565050355
1635 + ]
1636 + },
1637 + "Hotel/B&B/hostel": {
1638 + "sar": [
1639 + 0.10902967455867185,
1640 + 0.02636875437976746,
1641 + 0.1353984289384393
1642 + ],
1643 + "sar_se": [
1644 + 0.04825523116419653,
1645 + 0.01250353042336137,
1646 + 0.06019869316528668
1647 + ],
1648 + "sdm": [
1649 + 0.10035133051792194,
1650 + 0.13532114839745732,
1651 + 0.23567247891537926
1652 + ],
1653 + "sdm_se": [
1654 + 0.04697489164337976,
1655 + 0.11743582430132747,
1656 + 0.12423684235797194
1657 + ]
1658 + },
1659 + "ln_amenities": {
1660 + "sar": [
1661 + 0.06372642312312618,
1662 + 0.01541219310831371,
1663 + 0.07913861623143989
1664 + ],
1665 + "sar_se": [
1666 + 0.03408678204179821,
1667 + 0.008406563265211234,
1668 + 0.04222641482666082
1669 + ],
1670 + "sdm": [
1671 + 0.057840412774480716,
1672 + 0.08237705907468329,
1673 + 0.140217471849164
1674 + ],
1675 + "sdm_se": [
1676 + 0.03132505833925128,
1677 + 0.08024444780358034,
1678 + 0.08562382520253313
1679 + ]
1680 + },
1681 + "ln_images": {
1682 + "sar": [
1683 + 0.08066625151667658,
1684 + 0.01950907935467748,
1685 + 0.10017533087135407
1686 + ],
1687 + "sar_se": [
1688 + 0.02124567416016278,
1689 + 0.005885366012170214,
1690 + 0.026569067636871554
1691 + ],
1692 + "sdm": [
1693 + 0.09299023074349302,
1694 + -0.00691353566495502,
1695 + 0.086076695078538
1696 + ],
1697 + "sdm_se": [
1698 + 0.0202700054827316,
1699 + 0.04737226661725533,
1700 + 0.05090805456122752
1701 + ]
1702 + },
1703 + "is_superhost": {
1704 + "sar": [
1705 + 0.002214223127624657,
1706 + 0.0005355083928358958,
1707 + 0.0027497315204605527
1708 + ],
1709 + "sar_se": [
1710 + 0.022802865982583794,
1711 + 0.0056132449271424755,
1712 + 0.02837673667600918
1713 + ],
1714 + "sdm": [
1715 + 0.0059232991267106115,
1716 + 0.046227159381386676,
1717 + 0.05215045850809729
1718 + ],
1719 + "sdm_se": [
1720 + 0.022230846160889876,
1721 + 0.05803489428837962,
1722 + 0.06213027731495499
1723 + ]
1724 + },
1725 + "is_guest_favorite": {
1726 + "sar": [
1727 + -0.03369119259641258,
1728 + -0.008148192553378425,
1729 + -0.041839385149791006
1730 + ],
1731 + "sar_se": [
1732 + 0.02553928520752126,
1733 + 0.00622522363358247,
1734 + 0.03163189088377665
1735 + ],
1736 + "sdm": [
1737 + -0.0302270767031475,
1738 + 0.016043950032576092,
1739 + -0.014183126670571408
1740 + ],
1741 + "sdm_se": [
1742 + 0.025774498134222914,
1743 + 0.0719119458029245,
1744 + 0.07889336109934597
1745 + ]
1746 + },
1747 + "ln_reviews": {
1748 + "sar": [
1749 + 0.016934324870347354,
1750 + 0.004095555222932295,
1751 + 0.02102988009327965
1752 + ],
1753 + "sar_se": [
1754 + 0.00855226069785778,
1755 + 0.0022389668264378277,
1756 + 0.010713756196528836
1757 + ],
1758 + "sdm": [
1759 + 0.015774727317045465,
1760 + 0.012209064640913557,
1761 + 0.027983791957959022
1762 + ],
1763 + "sdm_se": [
1764 + 0.008166887574770083,
1765 + 0.02267421210189225,
1766 + 0.024853790377326358
1767 + ]
1768 + },
1769 + "rated": {
1770 + "sar": [
1771 + -0.036720611098730836,
1772 + -0.008880855406170549,
1773 + -0.045601466504901385
1774 + ],
1775 + "sar_se": [
1776 + 0.043047812464137254,
1777 + 0.01080805675529796,
1778 + 0.053747785611336765
1779 + ],
1780 + "sdm": [
1781 + -0.0373726624379663,
1782 + -0.027962527342726418,
1783 + -0.06533518978069272
1784 + ],
1785 + "sdm_se": [
1786 + 0.041685975329296854,
1787 + 0.12079597465195477,
1788 + 0.136882890290769
1789 + ]
1790 + },
1791 + "rating_c": {
1792 + "sar": [
1793 + 0.31740315681566084,
1794 + 0.07676374267201086,
1795 + 0.3941668994876717
1796 + ],
1797 + "sar_se": [
1798 + 0.05821723486634543,
1799 + 0.016087208958353392,
1800 + 0.07127558667671817
1801 + ],
1802 + "sdm": [
1803 + 0.3214404414908519,
1804 + -0.2716699337075289,
1805 + 0.049770507783323
1806 + ],
1807 + "sdm_se": [
1808 + 0.06450695754348656,
1809 + 0.1650404418188383,
1810 + 0.18963521243803705
1811 + ]
1812 + },
1813 + "ln_dist": {
1814 + "sar": [
1815 + -0.006294229552224218,
1816 + -0.001522255236881962,
1817 + -0.00781648478910618
1818 + ],
1819 + "sar_se": [
1820 + 0.009882201268661605,
1821 + 0.002506050054202594,
1822 + 0.012366614841451889
1823 + ],
1824 + "sdm": [
1825 + -0.023785157099951975,
1826 + 0.019573335181914585,
1827 + -0.0042118219180373884
1828 + ],
1829 + "sdm_se": [
1830 + 0.06221472575064102,
1831 + 0.06074351355287473,
1832 + 0.015128526962461173
1833 + ]
1834 + },
1835 + "ln_density_1km": {
1836 + "sar": [
1837 + 0.05366647237441935,
1838 + 0.012979200701072682,
1839 + 0.06664567307549203
1840 + ],
1841 + "sar_se": [
1842 + 0.009432883186007756,
1843 + 0.002472611729435093,
1844 + 0.011313051642730755
1845 + ],
1846 + "sdm": [
1847 + 0.04499891408494058,
1848 + 0.025045122597374667,
1849 + 0.07004403668231525
1850 + ],
1851 + "sdm_se": [
1852 + 0.019005566161677763,
1853 + 0.022480174823258724,
1854 + 0.013981070601550476
1855 + ]
1856 + }
1857 + },
1858 + "ml_n_blocks": 20,
1859 + "ml": {
1860 + "random": {
1861 + "OLS (M5)": [
1862 + 0.4727957697954267,
1863 + 0.49259350011224473,
1864 + 0.3743486643580567,
1865 + 28.46947311018222
1866 + ],
1867 + "Elastic net": [
1868 + 0.47592488542117495,
1869 + 0.4911294792603075,
1870 + 0.3731853375668413,
1871 + 28.66619611008847
1872 + ],
1873 + "Random forest": [
1874 + 0.5426256837846664,
1875 + 0.45881237212570525,
1876 + 0.3464065073056492,
1877 + 26.6837736325807
1878 + ],
1879 + "Gradient boosting": [
1880 + 0.5568599483826546,
1881 + 0.4516164324753874,
1882 + 0.34158316977243,
1883 + 26.686037558981546
1884 + ],
1885 + "XGBoost": [
1886 + 0.5594877725168974,
1887 + 0.4502753968601619,
1888 + 0.33919124653459687,
1889 + 26.42920584799749
1890 + ],
1891 + "LightGBM": [
1892 + 0.5519979883853359,
1893 + 0.4540871537875395,
1894 + 0.3412024691641432,
1895 + 26.08770422992836
1896 + ]
1897 + },
1898 + "blocked": {
1899 + "OLS (M5)": [
1900 + 0.406854862354162,
1901 + 0.5224920912106477,
1902 + 0.4009752103669443,
1903 + 30.492427710448915
1904 + ],
1905 + "Elastic net": [
1906 + 0.4259671702822796,
1907 + 0.5140053025575245,
1908 + 0.3927473159669005,
1909 + 29.560113896561823
1910 + ],
1911 + "Random forest": [
1912 + 0.4831803950545388,
1913 + 0.4877179319837926,
1914 + 0.37181955844941794,
1915 + 28.500230412620642
1916 + ],
1917 + "Gradient boosting": [
1918 + 0.47958934798986863,
1919 + 0.4894094179355107,
1920 + 0.376425392999458,
1921 + 29.486707449650414
1922 + ],
1923 + "XGBoost": [
1924 + 0.4825518892879659,
1925 + 0.4880143994478097,
1926 + 0.37510593209240306,
1927 + 28.840942048267728
1928 + ],
1929 + "LightGBM": [
1930 + 0.48211794916861384,
1931 + 0.4882189848378778,
1932 + 0.3723721104951233,
1933 + 28.52026256467786
1934 + ]
1935 + }
1936 + },
1937 + "shap_bias": 5.084221363067627,
1938 + "shap_top": {
1939 + "ln_guests": 0.18650798499584198,
1940 + "ln_bedrooms": 0.08733006566762924,
1941 + "ln_density_1km": 0.07956205308437347,
1942 + "City / cell fixed effects (all)": 0.07888496667146683,
1943 + "ln_bathrooms": 0.07876178622245789,
1944 + "ln_reviews": 0.07710228115320206,
1945 + "rating_c": 0.05912625044584274,
1946 + "ln_images": 0.04552251473069191,
1947 + "ln_dist": 0.043074820190668106,
1948 + "ln_amenities": 0.036877501755952835
1949 + },
1950 + "shap_total": 0.8921452164649963,
1951 + "shap_fe_share": 0.08842166513204575,
1952 + "robust": {
1953 + "Baseline: nightly regime ($\\hat{p}_i < 0.5$)": {
1954 + "n": 2480,
1955 + "r2": 0.5092128435240746,
1956 + "ln_bedrooms": [
1957 + 0.16037959113473327,
1958 + 0.042256614765418136,
1959 + 0.00014742197812739
1960 + ],
1961 + "ln_bathrooms": [
1962 + 0.4370493241677571,
1963 + 0.06985669083618966,
1964 + 3.9404057286738434e-10
1965 + ],
1966 + "ln_guests": [
1967 + 0.33054607122260554,
1968 + 0.03715745952465234,
1969 + 5.798951153381131e-19
1970 + ],
1971 + "is_superhost": [
1972 + 0.023486383134939143,
1973 + 0.024818511551896794,
1974 + 0.3439827392898118
1975 + ],
1976 + "is_guest_favorite": [
1977 + -0.034839398616947514,
1978 + 0.027213851826825244,
1979 + 0.20047189237331287
1980 + ],
1981 + "ln_reviews": [
1982 + 0.015229397552798299,
1983 + 0.010074419286461555,
1984 + 0.13061277758192388
1985 + ],
1986 + "rating_c": [
1987 + 0.33711305141158954,
1988 + 0.06776193219331096,
1989 + 6.526037251407198e-07
1990 + ],
1991 + "ln_dist": [
1992 + -0.034582568741214244,
1993 + 0.018810864701210992,
1994 + 0.06599820100926677
1995 + ]
1996 + },
1997 + "Nightly regime, strict ($\\hat{p}_i < 0.25$)": {
1998 + "n": 2475,
1999 + "r2": 0.5157466404855445,
2000 + "ln_bedrooms": [
2001 + 0.161473232289044,
2002 + 0.04159382674433625,
2003 + 0.00010353945574197473
2004 + ],
2005 + "ln_bathrooms": [
2006 + 0.4441074743500952,
2007 + 0.06806154767459759,
2008 + 6.796237787885231e-11
2009 + ],
2010 + "ln_guests": [
2011 + 0.3292577066543429,
2012 + 0.03694812617854325,
2013 + 5.041461624427621e-19
2014 + ],
2015 + "is_superhost": [
2016 + 0.02202412992080332,
2017 + 0.024725074321236305,
2018 + 0.37305744540404706
2019 + ],
2020 + "is_guest_favorite": [
2021 + -0.03564472847842111,
2022 + 0.027034648782491538,
2023 + 0.18734196708132766
2024 + ],
2025 + "ln_reviews": [
2026 + 0.016760105845412383,
2027 + 0.01001906393957633,
2028 + 0.09436243557541936
2029 + ],
2030 + "rating_c": [
2031 + 0.34333100040812803,
2032 + 0.06660453638579857,
2033 + 2.539437578774317e-07
2034 + ],
2035 + "ln_dist": [
2036 + -0.0341834901426524,
2037 + 0.01865089681564205,
2038 + 0.06683131048604907
2039 + ]
2040 + },
2041 + "Nightly regime, lenient ($\\hat{p}_i < 0.75$)": {
2042 + "n": 2482,
2043 + "r2": 0.5072411668207524,
2044 + "ln_bedrooms": [
2045 + 0.15987703987384994,
2046 + 0.04223863463173832,
2047 + 0.00015365286900184246
2048 + ],
2049 + "ln_bathrooms": [
2050 + 0.43810892427018555,
2051 + 0.06988103852174395,
2052 + 3.6255051947462807e-10
2053 + ],
2054 + "ln_guests": [
2055 + 0.32914340846973483,
2056 + 0.037166866059783296,
2057 + 8.306417392460956e-19
2058 + ],
2059 + "is_superhost": [
2060 + 0.01950166745701898,
2061 + 0.02495510166060044,
2062 + 0.43452601649463074
2063 + ],
2064 + "is_guest_favorite": [
2065 + -0.039258362852700034,
2066 + 0.027372837494679732,
2067 + 0.1515127028447263
2068 + ],
2069 + "ln_reviews": [
2070 + 0.014199485603516901,
2071 + 0.01011745580407032,
2072 + 0.16047850187120738
2073 + ],
2074 + "rating_c": [
2075 + 0.35382589377199486,
2076 + 0.06874689242998215,
2077 + 2.649801371058865e-07
2078 + ],
2079 + "ln_dist": [
2080 + -0.031233677216054995,
2081 + 0.01898669112135874,
2082 + 0.09996361675497241
2083 + ]
2084 + },
2085 + "Price $\\leq$ \\$1{,}000 rule": {
2086 + "n": 2541,
2087 + "r2": 0.28165770643361177,
2088 + "ln_bedrooms": [
2089 + 0.30319745818582955,
2090 + 0.05666151997589877,
2091 + 8.74553197362219e-08
2092 + ],
2093 + "ln_bathrooms": [
2094 + 0.4086472107923103,
2095 + 0.08300315992457691,
2096 + 8.510861806755366e-07
2097 + ],
2098 + "ln_guests": [
2099 + 0.015480535565630893,
2100 + 0.05503037729761993,
2101 + 0.778473475399122
2102 + ],
2103 + "is_superhost": [
2104 + 0.01638021789354347,
2105 + 0.029696499771722652,
2106 + 0.5812310065274112
2107 + ],
2108 + "is_guest_favorite": [
2109 + -0.02287204830350037,
2110 + 0.032581919870548905,
2111 + 0.4826879574915641
2112 + ],
2113 + "ln_reviews": [
2114 + -0.005066889266837293,
2115 + 0.012128486459256155,
2116 + 0.6761170065011954
2117 + ],
2118 + "rating_c": [
2119 + 0.09512440899414026,
2120 + 0.10138844813921384,
2121 + 0.3481326840163721
2122 + ],
2123 + "ln_dist": [
2124 + -0.02092748832805769,
2125 + 0.025086302905851083,
2126 + 0.404157186461627
2127 + ]
2128 + },
2129 + "Price $\\leq$ \\$600 rule": {
2130 + "n": 2402,
2131 + "r2": 0.4168136137734205,
2132 + "ln_bedrooms": [
2133 + 0.13821161544235228,
2134 + 0.04214880055180723,
2135 + 0.001041257381045674
2136 + ],
2137 + "ln_bathrooms": [
2138 + 0.24683828508189917,
2139 + 0.07175183755058868,
2140 + 0.000581355907085392
2141 + ],
2142 + "ln_guests": [
2143 + 0.2733208007696709,
2144 + 0.0398550518608979,
2145 + 6.989437264626784e-12
2146 + ],
2147 + "is_superhost": [
2148 + 0.019914055917728574,
2149 + 0.024315703370118392,
2150 + 0.412798266274924
2151 + ],
2152 + "is_guest_favorite": [
2153 + -0.001384938671598196,
2154 + 0.027080251174232538,
2155 + 0.9592123548890934
2156 + ],
2157 + "ln_reviews": [
2158 + 0.015035269153378952,
2159 + 0.010063572296080995,
2160 + 0.13516803186669446
2161 + ],
2162 + "rating_c": [
2163 + 0.2542875452687652,
2164 + 0.07678680057638522,
2165 + 0.000927624536440412
2166 + ],
2167 + "ln_dist": [
2168 + -0.03410272882660198,
2169 + 0.0199023620032591,
2170 + 0.08662030211869054
2171 + ]
2172 + },
2173 + "All priced listings (bimodal)": {
2174 + "n": 3456,
2175 + "r2": 0.15826732226348428,
2176 + "ln_bedrooms": [
2177 + 0.603564041343813,
2178 + 0.09502663393765452,
2179 + 2.131907557201615e-10
2180 + ],
2181 + "ln_bathrooms": [
2182 + 0.2808029502773533,
2183 + 0.12526735175651146,
2184 + 0.024985348816850373
2185 + ],
2186 + "ln_guests": [
2187 + -0.278981798812396,
2188 + 0.08006093670637596,
2189 + 0.0004928396918963809
2190 + ],
2191 + "is_superhost": [
2192 + -0.2404277037651379,
2193 + 0.05676702278482215,
2194 + 2.2820504727484388e-05
2195 + ],
2196 + "is_guest_favorite": [
2197 + -0.35105793032533866,
2198 + 0.06302896703339876,
2199 + 2.5505072968354994e-08
2200 + ],
2201 + "ln_reviews": [
2202 + -0.13140976669847346,
2203 + 0.022752582270728915,
2204 + 7.668029230019623e-09
2205 + ],
2206 + "rating_c": [
2207 + 0.7936126319663759,
2208 + 0.17610684058700568,
2209 + 6.592833342624054e-06
2210 + ],
2211 + "ln_dist": [
2212 + -0.0837110241648672,
2213 + 0.04823665435231963,
2214 + 0.0826658182970486
2215 + ]
2216 + },
2217 + "Excluding hotels, B\\&Bs, hostels": {
2218 + "n": 2335,
2219 + "r2": 0.5130703267614852,
2220 + "ln_bedrooms": [
2221 + 0.12160606915466368,
2222 + 0.039934582343620004,
2223 + 0.0023257831390082625
2224 + ],
2225 + "ln_bathrooms": [
2226 + 0.5441900200375371,
2227 + 0.06314965160829476,
2228 + 6.845166061007939e-18
2229 + ],
2230 + "ln_guests": [
2231 + 0.32655333906863715,
2232 + 0.03573398710671161,
2233 + 6.335242731105814e-20
2234 + ],
2235 + "is_superhost": [
2236 + 0.027517103673678434,
2237 + 0.025670287792248433,
2238 + 0.2837453134704585
2239 + ],
2240 + "is_guest_favorite": [
2241 + -0.03980044717664466,
2242 + 0.02811272480861766,
2243 + 0.15685020300398075
2244 + ],
2245 + "ln_reviews": [
2246 + 0.014926495737411692,
2247 + 0.010421603392542876,
2248 + 0.15206805181290178
2249 + ],
2250 + "rating_c": [
2251 + 0.37795609155288723,
2252 + 0.07371348662059517,
2253 + 2.9382256024381694e-07
2254 + ],
2255 + "ln_dist": [
2256 + -0.040303444212705763,
2257 + 0.019607538588186996,
2258 + 0.039830004192268786
2259 + ]
2260 + },
2261 + "Rated listings only": {
2262 + "n": 2246,
2263 + "r2": 0.5090679254077082,
2264 + "ln_bedrooms": [
2265 + 0.17453536579483347,
2266 + 0.045349540204460956,
2267 + 0.00011876139115227787
2268 + ],
2269 + "ln_bathrooms": [
2270 + 0.4269729950183302,
2271 + 0.07524572384058269,
2272 + 1.3919006910579457e-08
2273 + ],
2274 + "ln_guests": [
2275 + 0.31412795544657135,
2276 + 0.03686342718095359,
2277 + 1.5763804140896216e-17
2278 + ],
2279 + "is_superhost": [
2280 + 0.004274029503079764,
2281 + 0.026207086633961953,
2282 + 0.8704501045451327
2283 + ],
2284 + "is_guest_favorite": [
2285 + -0.02333832472082728,
2286 + 0.027294703577700762,
2287 + 0.3925237028162739
2288 + ],
2289 + "ln_reviews": [
2290 + 0.009568224576977584,
2291 + 0.010520081941210301,
2292 + 0.3630757231511792
2293 + ],
2294 + "rating_c": [
2295 + 0.36741702516177144,
2296 + 0.06861511712107521,
2297 + 8.567322390980824e-08
2298 + ],
2299 + "ln_dist": [
2300 + -0.03236678860554232,
2301 + 0.02071271705549174,
2302 + 0.11813424442160088
2303 + ]
2304 + },
2305 + "Montreal only": {
2306 + "n": 506,
2307 + "r2": 0.5430220457867572,
2308 + "ln_bedrooms": [
2309 + 0.09561443119203653,
2310 + 0.08561790831987018,
2311 + 0.2640980753473796
2312 + ],
2313 + "ln_bathrooms": [
2314 + 0.4852247294142932,
2315 + 0.16695473670860675,
2316 + 0.003657013651114333
2317 + ],
2318 + "ln_guests": [
2319 + 0.3128792865408127,
2320 + 0.078803682373018,
2321 + 7.176297536579175e-05
2322 + ],
2323 + "is_superhost": [
2324 + -0.05333719452044561,
2325 + 0.05948942841852201,
2326 + 0.36994161340929177
2327 + ],
2328 + "is_guest_favorite": [
2329 + 0.07674588568506674,
2330 + 0.06425536822345948,
2331 + 0.23232595521200494
2332 + ],
2333 + "ln_reviews": [
2334 + 0.11202864784366381,
2335 + 0.020883993328986793,
2336 + 8.124989804280472e-08
2337 + ],
2338 + "rating_c": [
2339 + 0.33560852199374,
2340 + 0.14748991316035295,
2341 + 0.02287789283721409
2342 + ],
2343 + "ln_dist": [
2344 + -0.17331583962627983,
2345 + 0.09093671689329871,
2346 + 0.05666382193413242
2347 + ]
2348 + },
2349 + "Outside Montreal": {
2350 + "n": 1974,
2351 + "r2": 0.5403018014349459,
2352 + "ln_bedrooms": [
2353 + 0.2212449069883307,
2354 + 0.0481147463879697,
2355 + 4.260004105068965e-06
2356 + ],
2357 + "ln_bathrooms": [
2358 + 0.3694547538859958,
2359 + 0.0751335992311521,
2360 + 8.774420150069522e-07
2361 + ],
2362 + "ln_guests": [
2363 + 0.32174187140515376,
2364 + 0.04321017991023912,
2365 + 9.623183868037728e-14
2366 + ],
2367 + "is_superhost": [
2368 + 0.030066659155849274,
2369 + 0.027110711913192607,
2370 + 0.26741618504544395
2371 + ],
2372 + "is_guest_favorite": [
2373 + -0.04120253390368266,
2374 + 0.029802348790111777,
2375 + 0.16681013100313602
2376 + ],
2377 + "ln_reviews": [
2378 + -0.016994101245676015,
2379 + 0.011005410421789909,
2380 + 0.12254986935446908
2381 + ],
2382 + "rating_c": [
2383 + 0.30929458632075,
2384 + 0.07923868013459208,
2385 + 9.487884755724175e-05
2386 + ],
2387 + "ln_dist": [
2388 + -0.031067753284784352,
2389 + 0.018909124989092613,
2390 + 0.10038226660077325
2391 + ]
2392 + },
2393 + "Trimmed 1\\%/99\\% within sample": {
2394 + "n": 2420,
2395 + "r2": 0.5122607281675626,
2396 + "ln_bedrooms": [
2397 + 0.1808334062392295,
2398 + 0.037344535586395854,
2399 + 1.283454581272024e-06
2400 + ],
2401 + "ln_bathrooms": [
2402 + 0.30107535895681736,
2403 + 0.06551312553792613,
2404 + 4.3140346511996e-06
2405 + ],
2406 + "ln_guests": [
2407 + 0.32623834013567143,
2408 + 0.03212427805185106,
2409 + 3.1317718392361764e-24
2410 + ],
2411 + "is_superhost": [
2412 + 0.018915240796660834,
2413 + 0.022858981996437624,
2414 + 0.4079677705427355
2415 + ],
2416 + "is_guest_favorite": [
2417 + -0.012232479245575745,
2418 + 0.02484056552511691,
2419 + 0.6224085794976661
2420 + ],
2421 + "ln_reviews": [
2422 + 0.008745970970801688,
2423 + 0.009699726998786984,
2424 + 0.3672312008369255
2425 + ],
2426 + "rating_c": [
2427 + 0.3419501478418975,
2428 + 0.0658354251111683,
2429 + 2.0580718154859754e-07
2430 + ],
2431 + "ln_dist": [
2432 + -0.03132393496102395,
2433 + 0.017435827274915487,
2434 + 0.0724107380864959
2435 + ]
2436 + },
2437 + "Weighted by $1 - \\hat{p}_i$": {
2438 + "n": 2480,
2439 + "r2": 0.5123547059207252,
2440 + "ln_bedrooms": [
2441 + 0.15984356459523122,
2442 + 0.04177933496407706,
2443 + 0.00013029508960027937
2444 + ],
2445 + "ln_bathrooms": [
2446 + 0.4424229049841695,
2447 + 0.06849902810060542,
2448 + 1.0552240790153703e-10
2449 + ],
2450 + "ln_guests": [
2451 + 0.32948971576305264,
2452 + 0.03694122363029665,
2453 + 4.69260735097354e-19
2454 + ],
2455 + "is_superhost": [
2456 + 0.023381801608191366,
2457 + 0.024699970091581883,
2458 + 0.3438259290533999
2459 + ],
2460 + "is_guest_favorite": [
2461 + -0.03527669582646166,
2462 + 0.027021397105292378,
2463 + 0.19171934889909936
2464 + ],
2465 + "ln_reviews": [
2466 + 0.016107847009709884,
2467 + 0.010022656494333988,
2468 + 0.1080228977702999
2469 + ],
2470 + "rating_c": [
2471 + 0.34020807858268476,
2472 + 0.0666504190703677,
2473 + 3.3190679065366963e-07
2474 + ],
2475 + "ln_dist": [
2476 + -0.034038484554893084,
2477 + 0.018634440080809986,
2478 + 0.06775334236224187
2479 + ]
2480 + },
2481 + "cell60": {
2482 + "n": 2480,
2483 + "r2": 0.5049490486609713,
2484 + "ln_bedrooms": [
2485 + 0.1731350392068034,
2486 + 0.04366462277577966,
2487 + 7.336206025755362e-05
2488 + ],
2489 + "ln_bathrooms": [
2490 + 0.4586952851969404,
2491 + 0.07064308230142412,
2492 + 8.406659163536431e-11
2493 + ],
2494 + "ln_guests": [
2495 + 0.307085210243305,
2496 + 0.03834582272576223,
2497 + 1.1629608233053086e-15
2498 + ],
2499 + "is_superhost": [
2500 + 0.007831290485957779,
2501 + 0.02451955330086037,
2502 + 0.7494310910822546
2503 + ],
2504 + "is_guest_favorite": [
2505 + -0.03968222868596466,
2506 + 0.02756119933040584,
2507 + 0.1499279558625775
2508 + ],
2509 + "ln_reviews": [
2510 + 0.01834954543440323,
2511 + 0.010298251643511542,
2512 + 0.07477994101719677
2513 + ],
2514 + "rating_c": [
2515 + 0.33001340894757736,
2516 + 0.06840265754811334,
2517 + 1.4030564135047248e-06
2518 + ],
2519 + "ln_dist": [
2520 + -0.021416425164692575,
2521 + 0.02151510373462547,
2522 + 0.3195351851490056
2523 + ]
2524 + }
2525 + },
2526 + "runtime_s": 172.22548424999695
2527 +}
\ No newline at end of file
added results/tables/rev_mixture.tex +26 −0
@@ -0,0 +1,26 @@
1 +\begin{tabular}{lr}
2 +\toprule
3 +Parameter & Estimate \\
4 +\midrule
5 +Intercept shift of the stay regime, $\delta$ (log points) & 3.154 \\
6 +Implied stay length, $\exp(\delta)$ (nights) & 23.4 \\
7 +Residual s.d., nightly regime, $\sigma_0$ & 0.493 \\
8 +Residual s.d., stay regime, $\sigma_1$ & 0.568 \\
9 +Mean posterior probability of the stay regime & 0.283 \\
10 +Listings classified in the stay regime ($\hat{p}_i \geq 0.5$) & 976 \\
11 +\quad of which displayed price $\leq$ \$1{,}000 & 83 \\
12 +Listings classified nightly with displayed price $>$ \$1{,}000 & 22 \\
13 +Listings with $0.25 < \hat{p}_i < 0.75$ & 7 \\
14 +Log-likelihood & -4,323.4 \\
15 +EM iterations & 16 \\
16 +\midrule
17 +\multicolumn{2}{l}{\textit{Regime equation (logit coefficients, SE)}} \\
18 +Constant & 1.466*** (0.141) \\
19 +Montreal & 0.622*** (0.096) \\
20 +ln(1 + reviews) & -0.331*** (0.027) \\
21 +ln(guests) & -0.889*** (0.073) \\
22 +Superhost & -0.588*** (0.087) \\
23 +Hotel/B\&B/hostel & -0.947*** (0.191) \\
24 +Chalet/cottage/cabin & -0.255** (0.121) \\
25 +\bottomrule
26 +\end{tabular}
\ No newline at end of file
added results/tables/rev_ml_cv.tex +14 −0
@@ -0,0 +1,14 @@
1 +\begin{tabular}{lrrrrrrrr}
2 +\toprule
3 + & \multicolumn{4}{c}{Random 5-fold CV} & \multicolumn{4}{c}{Spatially blocked 5-fold CV} \\
4 +\cmidrule(lr){2-5}\cmidrule(lr){6-9}
5 +Model & $R^2$ & RMSE & MAE & MdAPE (\%) & $R^2$ & RMSE & MAE & MdAPE (\%) \\
6 +\midrule
7 +OLS (M5) & 0.473 & 0.493 & 0.374 & 28.5 & 0.407 & 0.522 & 0.401 & 30.5 \\
8 +Elastic net & 0.476 & 0.491 & 0.373 & 28.7 & 0.426 & 0.514 & 0.393 & 29.6 \\
9 +Random forest & 0.543 & 0.459 & 0.346 & 26.7 & 0.483 & 0.488 & 0.372 & 28.5 \\
10 +Gradient boosting & 0.557 & 0.452 & 0.342 & 26.7 & 0.480 & 0.489 & 0.376 & 29.5 \\
11 +XGBoost & 0.559 & 0.450 & 0.339 & 26.4 & 0.483 & 0.488 & 0.375 & 28.8 \\
12 +LightGBM & 0.552 & 0.454 & 0.341 & 26.1 & 0.482 & 0.488 & 0.372 & 28.5 \\
13 +\bottomrule
14 +\end{tabular}
\ No newline at end of file
added results/tables/rev_ols_nested.tex +55 −0
@@ -0,0 +1,55 @@
1 +\begin{tabular}{lrrrrrr}
2 +\toprule
3 + & (1) & (2) & (3) & (4) & (5) & (5$'$) \\
4 +Dependent variable: ln(price) & M1 & M2 & M3 & M4 & M5 & M5 \\
5 +\midrule
6 +ln(bedrooms) & 0.168*** & 0.154*** & 0.158*** & 0.164*** & 0.160*** & 0.160** \\
7 + & (0.043) & (0.042) & (0.042) & (0.042) & (0.042) & [0.068] \\
8 +ln(1 + bathrooms) & 0.560*** & 0.514*** & 0.507*** & 0.464*** & 0.437*** & 0.437*** \\
9 + & (0.063) & (0.064) & (0.065) & (0.067) & (0.070) & [0.089] \\
10 +ln(guests) & 0.351*** & 0.324*** & 0.327*** & 0.321*** & 0.331*** & 0.331*** \\
11 + & (0.038) & (0.037) & (0.038) & (0.037) & (0.037) & [0.035] \\
12 +Shared bathroom & -0.441*** & -0.429*** & -0.423*** & -0.403*** & -0.385*** & -0.385*** \\
13 + & (0.053) & (0.052) & (0.053) & (0.052) & (0.053) & [0.061] \\
14 +Studio & 0.189*** & 0.210*** & 0.213*** & 0.179*** & 0.147** & 0.147* \\
15 + & (0.061) & (0.063) & (0.063) & (0.062) & (0.062) & [0.089] \\
16 +Chalet/cottage/cabin & 0.045 & 0.010 & 0.003 & 0.154*** & 0.099*** & 0.099** \\
17 + & (0.028) & (0.029) & (0.029) & (0.033) & (0.037) & [0.039] \\
18 +House & -0.028 & -0.035 & -0.037 & 0.095*** & 0.079** & 0.079 \\
19 + & (0.031) & (0.031) & (0.032) & (0.033) & (0.034) & [0.049] \\
20 +Condo/loft/apartment & -0.052 & -0.063* & -0.071* & -0.043 & -0.032 & -0.032 \\
21 + & (0.037) & (0.036) & (0.036) & (0.035) & (0.037) & [0.038] \\
22 +Hotel/B\&B/hostel & 0.008 & 0.024 & 0.044 & 0.122** & 0.079 & 0.079* \\
23 + & (0.046) & (0.047) & (0.047) & (0.049) & (0.051) & [0.045] \\
24 +Other/unconventional & 0.042 & 0.063 & 0.047 & 0.188** & 0.135 & 0.135 \\
25 + & (0.080) & (0.080) & (0.081) & (0.092) & (0.094) & [0.102] \\
26 +ln(1 + amenities) & & 0.071** & 0.048 & 0.067* & 0.094** & 0.094** \\
27 + & & (0.035) & (0.037) & (0.037) & (0.038) & [0.038] \\
28 +Pets allowed & & -0.048** & -0.044* & -0.032 & -0.044* & -0.044 \\
29 + & & (0.023) & (0.023) & (0.023) & (0.023) & [0.029] \\
30 +ln(1 + photos) & & 0.115*** & 0.104*** & 0.092*** & 0.087*** & 0.087*** \\
31 + & & (0.022) & (0.022) & (0.022) & (0.022) & [0.024] \\
32 +Superhost & & & 0.005 & 0.008 & 0.023 & 0.023 \\
33 + & & & (0.024) & (0.024) & (0.025) & [0.032] \\
34 +Guest Favourite & & & -0.055** & -0.034 & -0.035 & -0.035 \\
35 + & & & (0.027) & (0.027) & (0.027) & [0.032] \\
36 +ln(1 + reviews) & & & 0.020** & 0.015 & 0.015 & 0.015 \\
37 + & & & (0.010) & (0.010) & (0.010) & [0.026] \\
38 +Rated (star shown) & & & -0.056 & -0.033 & -0.041 & -0.041 \\
39 + & & & (0.049) & (0.050) & (0.050) & [0.044] \\
40 +Rating $-$ 4.8 (rated only) & & & 0.310*** & 0.328*** & 0.337*** & 0.337*** \\
41 + & & & (0.069) & (0.068) & (0.068) & [0.065] \\
42 +ln(1 + km to centre) & & & & -0.002 & -0.035* & -0.035 \\
43 + & & & & (0.010) & (0.019) & [0.024] \\
44 +ln(1 + listings within 1 km) & & & & 0.067*** & 0.064*** & 0.064*** \\
45 + & & & & (0.009) & (0.013) & [0.023] \\
46 +\midrule
47 +City / cell fixed effects & No & No & No & No & Yes & Yes \\
48 +Standard errors & HC3 & HC3 & HC3 & HC3 & HC3 & Cluster \\
49 +Observations & 2,480 & 2,480 & 2,480 & 2,480 & 2,480 & 2,480 \\
50 +$R^2$ & 0.443 & 0.454 & 0.461 & 0.479 & 0.509 & 0.509 \\
51 +Adjusted $R^2$ & 0.440 & 0.451 & 0.457 & 0.475 & 0.495 & 0.495 \\
52 +RMSE & 0.506 & 0.501 & 0.498 & 0.490 & 0.475 & 0.475 \\
53 +AIC & 3,686 & 3,639 & 3,619 & 3,539 & 3,490 & 3,490 \\
54 +\bottomrule
55 +\end{tabular}
\ No newline at end of file
added results/tables/rev_price_by_category.tex +14 −0
@@ -0,0 +1,14 @@
1 +\begin{tabular}{lrrrrrr}
2 +\toprule
3 +Title category & $N$ & Share & Mean (\$) & Median (\$) & P10 & P90 \\
4 +\midrule
5 +Rental unit & 697 & 0.281 & 167 & 132 & 67 & 290 \\
6 +Chalet/cottage/cabin & 748 & 0.302 & 259 & 201 & 110 & 466 \\
7 +House & 501 & 0.202 & 241 & 183 & 67 & 469 \\
8 +Condo/loft/apartment & 306 & 0.123 & 166 & 139 & 65 & 277 \\
9 +Hotel/B\&B/hostel & 145 & 0.058 & 118 & 99 & 53 & 191 \\
10 +Other/unconventional & 83 & 0.033 & 148 & 128 & 32 & 238 \\
11 +\midrule
12 +All & 2,480 & 1.000 & 206 & 162 & 70 & 376 \\
13 +\bottomrule
14 +\end{tabular}
\ No newline at end of file
added results/tables/rev_price_regimes.tex +13 −0
@@ -0,0 +1,13 @@
1 +\begin{tabular}{lrrrrr}
2 +\toprule
3 +Bedrooms & $N$ & Median (\$) & $N$ & Median (\$) & Ratio \\
4 + & \multicolumn{2}{c}{$\leq$ \$1{,}000} & \multicolumn{2}{c}{$>$ \$1{,}000} & \\
5 +\midrule
6 +0 & 15 & 105 & 2 & 4,679 & 44.6 \\
7 +1 & 953 & 112 & 439 & 2,072 & 18.5 \\
8 +2 & 648 & 162 & 226 & 2,735 & 16.9 \\
9 +3 & 508 & 209 & 129 & 3,884 & 18.6 \\
10 +4 & 277 & 270 & 72 & 4,624 & 17.1 \\
11 +5+ & 140 & 366 & 47 & 3,665 & 10.0 \\
12 +\bottomrule
13 +\end{tabular}
\ No newline at end of file
added results/tables/rev_quantile.tex +44 −0
@@ -0,0 +1,44 @@
1 +\begin{tabular}{lrrrrrr}
2 +\toprule
3 +Variable & OLS & $\tau=0.10$ & $\tau=0.25$ & $\tau=0.50$ & $\tau=0.75$ & $\tau=0.90$ \\
4 +\midrule
5 +ln(bedrooms) & 0.160*** & 0.014 & 0.099** & 0.169*** & 0.214*** & 0.187*** \\
6 + & (0.042) & (0.053) & (0.039) & (0.033) & (0.032) & (0.037) \\
7 +ln(1 + bathrooms) & 0.437*** & 0.241*** & 0.298*** & 0.401*** & 0.551*** & 0.551*** \\
8 + & (0.070) & (0.078) & (0.053) & (0.044) & (0.047) & (0.058) \\
9 +ln(guests) & 0.331*** & 0.374*** & 0.399*** & 0.346*** & 0.305*** & 0.307*** \\
10 + & (0.037) & (0.048) & (0.036) & (0.031) & (0.031) & (0.037) \\
11 +Shared bathroom & -0.385*** & -0.267*** & -0.332*** & -0.414*** & -0.388*** & -0.309*** \\
12 + & (0.053) & (0.067) & (0.051) & (0.045) & (0.047) & (0.056) \\
13 +Chalet/cottage/cabin & 0.099*** & 0.024 & 0.068* & 0.117*** & 0.166*** & 0.214*** \\
14 + & (0.037) & (0.053) & (0.040) & (0.036) & (0.036) & (0.043) \\
15 +House & 0.079** & 0.017 & 0.040 & 0.099*** & 0.087*** & 0.121*** \\
16 + & (0.034) & (0.048) & (0.037) & (0.033) & (0.033) & (0.039) \\
17 +Condo/loft/apartment & -0.032 & -0.183*** & -0.032 & -0.017 & 0.014 & 0.077** \\
18 + & (0.037) & (0.049) & (0.037) & (0.034) & (0.034) & (0.039) \\
19 +Hotel/B\&B/hostel & 0.079 & -0.091 & 0.101* & 0.181*** & 0.107** & 0.063 \\
20 + & (0.051) & (0.069) & (0.053) & (0.047) & (0.047) & (0.058) \\
21 +ln(1 + amenities) & 0.094** & 0.053 & 0.110*** & 0.086*** & 0.032 & 0.017 \\
22 + & (0.038) & (0.048) & (0.036) & (0.033) & (0.034) & (0.042) \\
23 +ln(1 + photos) & 0.087*** & 0.085*** & 0.100*** & 0.104*** & 0.100*** & 0.133*** \\
24 + & (0.022) & (0.028) & (0.022) & (0.019) & (0.021) & (0.027) \\
25 +Superhost & 0.023 & 0.081** & 0.052** & 0.006 & 0.025 & -0.003 \\
26 + & (0.025) & (0.032) & (0.025) & (0.023) & (0.023) & (0.028) \\
27 +Guest Favourite & -0.035 & -0.050 & -0.034 & 0.000 & -0.024 & -0.080*** \\
28 + & (0.027) & (0.036) & (0.028) & (0.025) & (0.025) & (0.029) \\
29 +ln(1 + reviews) & 0.015 & 0.042*** & 0.037*** & 0.007 & -0.026*** & -0.042*** \\
30 + & (0.010) & (0.015) & (0.010) & (0.008) & (0.008) & (0.008) \\
31 +Rated (star shown) & -0.041 & -0.052 & -0.056 & 0.054 & 0.056 & 0.072 \\
32 + & (0.050) & (0.064) & (0.048) & (0.041) & (0.041) & (0.047) \\
33 +Rating $-$ 4.8 (rated only) & 0.337*** & 0.355*** & 0.340*** & 0.257*** & 0.342*** & 0.383*** \\
34 + & (0.068) & (0.084) & (0.065) & (0.061) & (0.064) & (0.076) \\
35 +ln(1 + km to centre) & -0.035* & 0.008 & -0.014 & -0.049** & -0.082*** & -0.072*** \\
36 + & (0.019) & (0.027) & (0.021) & (0.020) & (0.018) & (0.022) \\
37 +ln(1 + listings within 1 km) & 0.064*** & 0.100*** & 0.080*** & 0.046*** & 0.033*** & 0.037*** \\
38 + & (0.013) & (0.017) & (0.013) & (0.012) & (0.012) & (0.014) \\
39 +\midrule
40 +Pseudo-$R^2$ / $R^2$ & 0.509 & 0.278 & 0.294 & 0.328 & 0.359 & 0.405 \\
41 +Observations & \multicolumn{6}{c}{2,480} \\
42 +City / cell fixed effects & \multicolumn{6}{c}{Yes} \\
43 +\bottomrule
44 +\end{tabular}
\ No newline at end of file
added results/tables/rev_robustness.tex +32 −0
@@ -0,0 +1,32 @@
1 +\begin{tabular}{lrrrrrrrrrr}
2 +\toprule
3 +Sample / specification & Bedr. & Bathr. & Guests & Superhost & Guest Fav. & ln reviews & Rating & ln dist. & $N$ & $R^2$ \\
4 +\midrule
5 +Baseline: nightly regime ($\hat{p}_i < 0.5$) & 0.160*** & 0.437*** & 0.331*** & 0.023 & -0.035 & 0.015 & 0.337*** & -0.035* & 2,480 & 0.509 \\
6 + & (0.042) & (0.070) & (0.037) & (0.025) & (0.027) & (0.010) & (0.068) & (0.019) & & \\
7 +Nightly regime, strict ($\hat{p}_i < 0.25$) & 0.161*** & 0.444*** & 0.329*** & 0.022 & -0.036 & 0.017* & 0.343*** & -0.034* & 2,475 & 0.516 \\
8 + & (0.042) & (0.068) & (0.037) & (0.025) & (0.027) & (0.010) & (0.067) & (0.019) & & \\
9 +Nightly regime, lenient ($\hat{p}_i < 0.75$) & 0.160*** & 0.438*** & 0.329*** & 0.020 & -0.039 & 0.014 & 0.354*** & -0.031* & 2,482 & 0.507 \\
10 + & (0.042) & (0.070) & (0.037) & (0.025) & (0.027) & (0.010) & (0.069) & (0.019) & & \\
11 +Price $\leq$ \$1{,}000 rule & 0.303*** & 0.409*** & 0.015 & 0.016 & -0.023 & -0.005 & 0.095 & -0.021 & 2,541 & 0.282 \\
12 + & (0.057) & (0.083) & (0.055) & (0.030) & (0.033) & (0.012) & (0.101) & (0.025) & & \\
13 +Price $\leq$ \$600 rule & 0.138*** & 0.247*** & 0.273*** & 0.020 & -0.001 & 0.015 & 0.254*** & -0.034* & 2,402 & 0.417 \\
14 + & (0.042) & (0.072) & (0.040) & (0.024) & (0.027) & (0.010) & (0.077) & (0.020) & & \\
15 +All priced listings (bimodal) & 0.604*** & 0.281** & -0.279*** & -0.240*** & -0.351*** & -0.131*** & 0.794*** & -0.084* & 3,456 & 0.158 \\
16 + & (0.095) & (0.125) & (0.080) & (0.057) & (0.063) & (0.023) & (0.176) & (0.048) & & \\
17 +Excluding hotels, B\&Bs, hostels & 0.122*** & 0.544*** & 0.327*** & 0.028 & -0.040 & 0.015 & 0.378*** & -0.040** & 2,335 & 0.513 \\
18 + & (0.040) & (0.063) & (0.036) & (0.026) & (0.028) & (0.010) & (0.074) & (0.020) & & \\
19 +Rated listings only & 0.175*** & 0.427*** & 0.314*** & 0.004 & -0.023 & 0.010 & 0.367*** & -0.032 & 2,246 & 0.509 \\
20 + & (0.045) & (0.075) & (0.037) & (0.026) & (0.027) & (0.011) & (0.069) & (0.021) & & \\
21 +Montreal only & 0.096 & 0.485*** & 0.313*** & -0.053 & 0.077 & 0.112*** & 0.336** & -0.173* & 506 & 0.543 \\
22 + & (0.086) & (0.167) & (0.079) & (0.059) & (0.064) & (0.021) & (0.147) & (0.091) & & \\
23 +Outside Montreal & 0.221*** & 0.369*** & 0.322*** & 0.030 & -0.041 & -0.017 & 0.309*** & -0.031 & 1,974 & 0.540 \\
24 + & (0.048) & (0.075) & (0.043) & (0.027) & (0.030) & (0.011) & (0.079) & (0.019) & & \\
25 +Trimmed 1\%/99\% within sample & 0.181*** & 0.301*** & 0.326*** & 0.019 & -0.012 & 0.009 & 0.342*** & -0.031* & 2,420 & 0.512 \\
26 + & (0.037) & (0.066) & (0.032) & (0.023) & (0.025) & (0.010) & (0.066) & (0.017) & & \\
27 +Weighted by $1 - \hat{p}_i$ & 0.160*** & 0.442*** & 0.329*** & 0.023 & -0.035 & 0.016 & 0.340*** & -0.034* & 2,480 & 0.512 \\
28 + & (0.042) & (0.068) & (0.037) & (0.025) & (0.027) & (0.010) & (0.067) & (0.019) & & \\
29 +60 spatial-cell fixed effects & 0.173*** & 0.459*** & 0.307*** & 0.008 & -0.040 & 0.018* & 0.330*** & -0.021 & 2,480 & 0.505 \\
30 + & (0.044) & (0.071) & (0.038) & (0.025) & (0.028) & (0.010) & (0.068) & (0.022) & & \\
31 +\bottomrule
32 +\end{tabular}
\ No newline at end of file
added results/tables/rev_shap_importance.tex +22 −0
@@ -0,0 +1,22 @@
1 +\begin{tabular}{lrr}
2 +\toprule
3 +Feature & Mean $|\phi_k|$ & Share of total (\%) \\
4 +\midrule
5 +ln(guests) & 0.1865 & 20.9 \\
6 +ln(bedrooms) & 0.0873 & 9.8 \\
7 +ln(1 + listings within 1 km) & 0.0796 & 8.9 \\
8 +City / cell fixed effects (all) & 0.0789 & 8.8 \\
9 +ln(1 + bathrooms) & 0.0788 & 8.8 \\
10 +ln(1 + reviews) & 0.0771 & 8.6 \\
11 +Rating $-$ 4.8 (rated only) & 0.0591 & 6.6 \\
12 +ln(1 + photos) & 0.0455 & 5.1 \\
13 +ln(1 + km to centre) & 0.0431 & 4.8 \\
14 +ln(1 + amenities) & 0.0369 & 4.1 \\
15 +Shared bathroom & 0.0270 & 3.0 \\
16 +Chalet/cottage/cabin & 0.0256 & 2.9 \\
17 +Guest Favourite & 0.0141 & 1.6 \\
18 +Condo/loft/apartment & 0.0114 & 1.3 \\
19 +Pets allowed & 0.0089 & 1.0 \\
20 +Rated (star shown) & 0.0083 & 0.9 \\
21 +\bottomrule
22 +\end{tabular}
\ No newline at end of file
added results/tables/rev_spatial.tex +49 −0
@@ -0,0 +1,49 @@
1 +\begin{tabular}{lrrrrr}
2 +\toprule
3 +Variable & OLS (M4) & SAR & SEM & SDM & SDM, $\mathbf{W}x$ \\
4 +\midrule
5 +ln(bedrooms) & 0.164*** & 0.165*** & 0.155*** & 0.151*** & 0.035 \\
6 + & (0.042) & (0.034) & (0.034) & (0.034) & (0.068) \\
7 +ln(1 + bathrooms) & 0.464*** & 0.444*** & 0.437*** & 0.436*** & 0.080 \\
8 + & (0.067) & (0.045) & (0.045) & (0.045) & (0.090) \\
9 +ln(guests) & 0.321*** & 0.301*** & 0.334*** & 0.333*** & -0.153** \\
10 + & (0.037) & (0.031) & (0.031) & (0.031) & (0.060) \\
11 +Shared bathroom & -0.403*** & -0.383*** & -0.391*** & -0.386*** & -0.010 \\
12 + & (0.052) & (0.047) & (0.048) & (0.048) & (0.087) \\
13 +Chalet/cottage/cabin & 0.154*** & 0.097*** & 0.136*** & 0.114*** & -0.012 \\
14 + & (0.033) & (0.034) & (0.036) & (0.038) & (0.058) \\
15 +House & 0.095*** & 0.073** & 0.096*** & 0.091*** & -0.064 \\
16 + & (0.033) & (0.034) & (0.035) & (0.035) & (0.065) \\
17 +Condo/loft/apartment & -0.043 & -0.041 & -0.026 & -0.016 & -0.054 \\
18 + & (0.035) & (0.034) & (0.034) & (0.035) & (0.059) \\
19 +Hotel/B\&B/hostel & 0.122** & 0.108** & 0.102** & 0.096** & 0.078 \\
20 + & (0.049) & (0.047) & (0.048) & (0.049) & (0.089) \\
21 +ln(1 + amenities) & 0.067* & 0.063* & 0.056* & 0.055 & 0.049 \\
22 + & (0.037) & (0.033) & (0.034) & (0.034) & (0.062) \\
23 +ln(1 + photos) & 0.092*** & 0.080*** & 0.093*** & 0.093*** & -0.030 \\
24 + & (0.022) & (0.020) & (0.020) & (0.020) & (0.037) \\
25 +Superhost & 0.008 & 0.002 & 0.006 & 0.004 & 0.034 \\
26 + & (0.024) & (0.023) & (0.023) & (0.023) & (0.045) \\
27 +Guest Favourite & -0.034 & -0.033 & -0.034 & -0.031 & 0.020 \\
28 + & (0.027) & (0.026) & (0.025) & (0.025) & (0.052) \\
29 +ln(1 + reviews) & 0.015 & 0.017** & 0.015* & 0.015* & 0.005 \\
30 + & (0.010) & (0.008) & (0.008) & (0.008) & (0.017) \\
31 +Rated (star shown) & -0.033 & -0.036 & -0.037 & -0.036 & -0.012 \\
32 + & (0.050) & (0.043) & (0.042) & (0.042) & (0.093) \\
33 +Rating $-$ 4.8 (rated only) & 0.328*** & 0.315*** & 0.345*** & 0.331*** & -0.294** \\
34 + & (0.068) & (0.063) & (0.063) & (0.063) & (0.128) \\
35 +ln(1 + km to centre) & -0.002 & -0.006 & -0.005 & -0.024 & 0.021 \\
36 + & (0.010) & (0.010) & (0.013) & (0.062) & (0.061) \\
37 +ln(1 + listings within 1 km) & 0.067*** & 0.053*** & 0.062*** & 0.044** & 0.008 \\
38 + & (0.009) & (0.009) & (0.011) & (0.020) & (0.023) \\
39 +\midrule
40 +$\rho$ (spatial lag) & & 0.200*** & & 0.261*** & \\
41 + & & (0.022) & & (0.028) & \\
42 +$\lambda$ (spatial error) & & & 0.284*** & & \\
43 + & & & (0.028) & & \\
44 +Log-likelihood & -1,748.7 & -1,710.6 & -1,702.1 & -1,684.3 & \\
45 +AIC & 3,539 & 3,465 & 3,446 & 3,453 & \\
46 +Pseudo-$R^2$ & 0.479 & 0.498 & 0.478 & 0.511 & \\
47 +Observations & \multicolumn{5}{c}{2,480} \\
48 +\bottomrule
49 +\end{tabular}
\ No newline at end of file
added results/tables/rev_stay_logit.tex +25 −0
@@ -0,0 +1,25 @@
1 +\begin{tabular}{lrrrr}
2 +\toprule
3 +Variable & Coefficient & (SE) & Avg.\ marginal effect & (SE) \\
4 +\midrule
5 +ln(bedrooms) & 0.914*** & (0.169) & 0.147 & (0.027) \\
6 +ln(1 + bathrooms) & -0.270 & (0.204) & -0.043 & (0.033) \\
7 +ln(guests) & -1.451*** & (0.138) & -0.233 & (0.020) \\
8 +ln(1 + amenities) & 0.016 & (0.129) & 0.003 & (0.021) \\
9 +Superhost & -0.417*** & (0.093) & -0.067 & (0.015) \\
10 +Guest Favourite & -0.609*** & (0.113) & -0.098 & (0.018) \\
11 +Rated (star shown) & 0.113 & (0.153) & 0.018 & (0.025) \\
12 +ln(1 + reviews) & -0.314*** & (0.037) & -0.050 & (0.006) \\
13 +Montreal & 0.365*** & (0.114) & 0.059 & (0.018) \\
14 +ln(1 + km to centre) & -0.059 & (0.040) & -0.009 & (0.006) \\
15 +Chalet/cottage/cabin & -0.419*** & (0.152) & -0.067 & (0.024) \\
16 +House & -0.306** & (0.137) & -0.049 & (0.022) \\
17 +Condo/loft/apartment & -0.022 & (0.135) & -0.003 & (0.022) \\
18 +Hotel/B\&B/hostel & -0.977*** & (0.209) & -0.157 & (0.033) \\
19 +Other/unconventional & -0.346 & (0.274) & -0.056 & (0.044) \\
20 +\midrule
21 +Observations & \multicolumn{4}{c}{3,456} \\
22 +Pseudo-$R^2$ & \multicolumn{4}{c}{0.177} \\
23 +Share in regime & \multicolumn{4}{c}{0.282} \\
24 +\bottomrule
25 +\end{tabular}
\ No newline at end of file
added results/tables/rev_summary.tex +26 −0
@@ -0,0 +1,26 @@
1 +\begin{tabular}{lrrrrrrr}
2 +\toprule
3 +Variable & Mean & Std.\ dev. & P10 & Median & P90 & $N$ & Mean, full \\
4 +\midrule
5 +Displayed price (CAD) & 206 & 176 & 70 & 162 & 376 & 2,480 & 1,233 \\
6 +ln(price) & 5.08 & 0.68 & 4.25 & 5.08 & 5.93 & 2,480 & 5.89 \\
7 +Bedrooms & 2 & 1 & 1 & 2 & 4 & 2,480 & 2 \\
8 +Bathrooms & 1.52 & 0.98 & 1.00 & 1.00 & 2.50 & 2,480 & 1.46 \\
9 +Guest capacity & 6 & 3 & 2 & 6 & 10 & 2,480 & 5 \\
10 +Beds (from title) & 4 & 3 & 1 & 3 & 6 & 2,443 & 3 \\
11 +Amenities count & 48 & 15 & 26 & 48 & 67 & 2,480 & 46 \\
12 +Photos & 31 & 20 & 11 & 26 & 56 & 2,480 & 28 \\
13 +Reviews & 64 & 79 & 0 & 37 & 162 & 2,480 & 53 \\
14 +Rating (rated listings) & 4.81 & 0.20 & 4.57 & 4.87 & 5.00 & 2,246 & 4.81 \\
15 +Rated (star shown) & 0.91 & 0.29 & 1.00 & 1.00 & 1.00 & 2,480 & 0.87 \\
16 +Superhost & 0.59 & 0.49 & 0.00 & 1.00 & 1.00 & 2,480 & 0.53 \\
17 +Guest Favourite & 0.41 & 0.49 & 0.00 & 0.00 & 1.00 & 2,480 & 0.34 \\
18 +Pets allowed & 0.30 & 0.46 & 0.00 & 0.00 & 1.00 & 2,480 & 0.29 \\
19 +Shared bathroom & 0.06 & 0.23 & 0.00 & 0.00 & 0.00 & 2,480 & 0.07 \\
20 +Studio & 0.03 & 0.18 & 0.00 & 0.00 & 0.00 & 2,480 & 0.05 \\
21 +Distance to nearest centre (km) & 48.24 & 259.14 & 1.22 & 17.42 & 70.19 & 2,480 & 41.46 \\
22 +Listings within 1 km & 24 & 45 & 0 & 3 & 94 & 2,480 & 25 \\
23 +Montreal & 0.20 & 0.40 & 0.00 & 0.00 & 1.00 & 2,480 & 0.27 \\
24 +Posterior prob.\ of stay regime & 0.00 & 0.02 & 0.00 & 0.00 & 0.00 & 2,480 & 0.28 \\
25 +\bottomrule
26 +\end{tabular}
\ No newline at end of file
added results/tables/rev_vif.tex +26 −0
@@ -0,0 +1,26 @@
1 +\begin{tabular}{lr}
2 +\toprule
3 +Regressor & VIF \\
4 +\midrule
5 +ln(bedrooms) & 4.16 \\
6 +ln(1 + bathrooms) & 1.80 \\
7 +ln(guests) & 3.78 \\
8 +Shared bathroom & 1.27 \\
9 +Studio & 1.08 \\
10 +Chalet/cottage/cabin & 2.54 \\
11 +House & 1.98 \\
12 +Condo/loft/apartment & 1.30 \\
13 +Hotel/B\&B/hostel & 1.33 \\
14 +Other/unconventional & 1.24 \\
15 +ln(1 + amenities) & 1.55 \\
16 +Pets allowed & 1.11 \\
17 +ln(1 + photos) & 1.62 \\
18 +Superhost & 1.36 \\
19 +Guest Favourite & 1.69 \\
20 +ln(1 + reviews) & 1.87 \\
21 +Rated (star shown) & 1.67 \\
22 +Rating $-$ 4.8 (rated only) & 1.53 \\
23 +ln(1 + km to centre) & 2.16 \\
24 +ln(1 + listings within 1 km) & 2.25 \\
25 +\bottomrule
26 +\end{tabular}
\ No newline at end of file
added scripts/10_revision_reanalysis.py +787 −0
@@ -0,0 +1,787 @@
1 +#!/usr/bin/env python3
2 +"""
3 +10_revision_reanalysis.py -- Editorial-board revision of UQO WP 4 (October 2026).
4 +
5 +Re-estimates every result reported in the revised paper from the only locally
6 +available copy of the Quebec Airbnb scrape, ``data/processed/airbnb_clean_wp5.parquet``
7 +(3,456 priced listings out of 5,000 scraped; prices winsorised at p1/p99 and
8 +ratings median-imputed by the companion paper's cleaning step -- the imputation is
9 +reversed here by parsing the star rating from the structured title).
10 +
11 +Outputs (all regenerated, never typed):
12 + results/tables/rev_*.tex / .csv / .json
13 + paper/figures/rev_*.pdf (and results/figures/)
14 +
15 +Run time: about 3-4 minutes on an Apple-silicon laptop.
16 +"""
17 +from __future__ import annotations
18 +
19 +import json
20 +import re
21 +import sys
22 +import time
23 +import warnings
24 +from pathlib import Path
25 +
26 +import numpy as np
27 +import pandas as pd
28 +import statsmodels.api as sm
29 +from scipy import stats
30 +
31 +warnings.filterwarnings("ignore")
32 +ROOT = Path(__file__).resolve().parent.parent
33 +DATA = ROOT / "data" / "processed" / "airbnb_clean_wp5.parquet"
34 +TAB = ROOT / "results" / "tables"
35 +FIG_R = ROOT / "results" / "figures"
36 +FIG_P = ROOT / "paper" / "figures"
37 +for d in (TAB, FIG_R, FIG_P):
38 + d.mkdir(parents=True, exist_ok=True)
39 +
40 +import matplotlib
41 +matplotlib.use("Agg")
42 +import matplotlib.pyplot as plt
43 +plt.rcParams.update({"font.family": "serif", "font.size": 10, "axes.spines.top": False,
44 + "axes.spines.right": False, "figure.dpi": 150})
45 +
46 +SEED = 42
47 +NIGHTLY_CAP = 1000.0 # main analysis sample: price <= $1,000
48 +KEY = {} # numbers quoted in the text
49 +T0 = time.perf_counter()
50 +
51 +
52 +def log(msg):
53 + print(f"[{time.perf_counter() - T0:6.1f}s] {msg}", flush=True)
54 +
55 +
56 +def savefig(fig, stem):
57 + for d in (FIG_R, FIG_P):
58 + fig.savefig(d / f"{stem}.pdf", bbox_inches="tight")
59 + plt.close(fig)
60 +
61 +
62 +def stars(p):
63 + return "***" if p < 0.01 else "**" if p < 0.05 else "*" if p < 0.10 else ""
64 +
65 +
66 +def fmt(x, d=3):
67 + return f"{x:.{d}f}"
68 +
69 +
70 +def tex_escape(s):
71 + return s.replace("&", r"\&").replace("%", r"\%").replace("_", r"\_").replace("$", r"\$")
72 +
73 +
74 +def write_tex(name, body):
75 + (TAB / f"{name}.tex").write_text(body, encoding="utf-8")
76 + log(f"wrote {name}.tex")
77 +
78 +
79 +# --------------------------------------------------------------------------
80 +# 1. Load and parse the structured title
81 +# --------------------------------------------------------------------------
82 +df = pd.read_parquet(DATA)
83 +df["name"] = df["name"].fillna("").astype(str)
84 +N_PRICED = len(df)
85 +nm = df["name"]
86 +
87 +# star rating from title (reverses the median imputation of the parquet)
88 +star = nm.str.extract(r"★\s*(\d+(?:[.,]\d+)?)", expand=False).str.replace(",", ".", regex=False).astype(float)
89 +df["rating_raw"] = star
90 +df["rated"] = star.notna().astype(int)
91 +df["is_new"] = nm.str.contains(r"★\s*New\b|·\s*New\s*·", regex=True).astype(int)
92 +# 37 German-locale titles ("★4,97") were truncated to 4.0 in the scraped rating field; the title value is retained
93 +KEY["n_rating_truncated_fixed"] = int(((star.notna()) & ((star - df["rating"]).abs() > 0.011)).sum())
94 +KEY["n_unrated"] = int((df["rated"] == 0).sum())
95 +KEY["n_new"] = int(df["is_new"].sum())
96 +
97 +# title category (English template "Category in City · ..."; 50 German-locale titles fall back to property_type)
98 +cat = nm.str.extract(r"^(.+?)\s+in\s+", expand=False)
99 +CAT_MAP = {
100 + "Rental unit": "Rental unit",
101 + "Chalet": "Chalet/cottage/cabin", "Cottage": "Chalet/cottage/cabin", "Cabin": "Chalet/cottage/cabin",
102 + "Vacation home": "Chalet/cottage/cabin", "Holiday home": "Chalet/cottage/cabin", "Nature lodge": "Chalet/cottage/cabin",
103 + "Home": "House", "Townhouse": "House", "Bungalow": "House", "Villa": "House", "Farm stay": "House",
104 + "Earthen home": "House", "Earth homes": "House", "Castle": "House",
105 + "Condo": "Condo/loft/apartment", "Loft": "Condo/loft/apartment", "Serviced apartment": "Condo/loft/apartment",
106 + "Apartment": "Condo/loft/apartment", "Guest suite": "Condo/loft/apartment",
107 + "Hotel": "Hotel/B&B/hostel", "Bed and breakfast": "Hotel/B&B/hostel", "Aparthotel": "Hotel/B&B/hostel",
108 + "Boutique hotel": "Hotel/B&B/hostel", "Hostel": "Hotel/B&B/hostel", "Guesthouse": "Hotel/B&B/hostel",
109 + "Guest house": "Hotel/B&B/hostel", "Resort": "Hotel/B&B/hostel", "casa particular": "Hotel/B&B/hostel",
110 +}
111 +PT_FALLBACK = {"Rental unit": "Rental unit", "Cabin/Chalet": "Chalet/cottage/cabin", "House": "House",
112 + "Condo": "Condo/loft/apartment", "Apartment": "Condo/loft/apartment", "Other": "Other/unconventional"}
113 +df["category"] = cat.map(CAT_MAP)
114 +df.loc[df["category"].isna() & cat.notna(), "category"] = "Other/unconventional"
115 +df.loc[cat.isna(), "category"] = df.loc[cat.isna(), "property_type"].map(PT_FALLBACK).fillna("Other/unconventional")
116 +CATS = ["Rental unit", "Chalet/cottage/cabin", "House", "Condo/loft/apartment", "Hotel/B&B/hostel", "Other/unconventional"]
117 +df["category"] = pd.Categorical(df["category"], categories=CATS)
118 +
119 +df["shared_bath"] = nm.str.contains(r"shared\s+(?:half-?)?bath|Gemeinschaftsbad", case=False, regex=True).astype(int)
120 +df["studio"] = nm.str.contains(r"\bStudio\b", case=False, regex=True).astype(int)
121 +df["beds"] = nm.str.extract(r"(\d+)\s*(?:beds?|Bett(?:en)?)\b", expand=False).astype(float)
122 +# the scraper stored bathrooms = 0 whenever the title qualified the bathroom ("1 shared bath", "1 private bath",
123 +# "Half-bath"); recover the count from the title; studios have bedrooms = 0 and are recoded to one sleeping room
124 +baths_title = nm.str.extract(r"(\d+(?:[.,]\d+)?)\s*(?:shared |private )?(?:bath|Badezimmer)", expand=False).str.replace(",", ".", regex=False).astype(float)
125 +half_bath = nm.str.contains(r"half-?bath", case=False, regex=True)
126 +df["bathrooms_raw"] = df["bathrooms"]
127 +fix = (df["bathrooms"] == 0) & baths_title.notna()
128 +df.loc[fix, "bathrooms"] = baths_title[fix]
129 +df.loc[(df["bathrooms"] == 0) & half_bath, "bathrooms"] = 0.5
130 +KEY["n_bathrooms_recovered"] = int(fix.sum() + ((df["bathrooms_raw"] == 0) & half_bath & ~fix).sum())
131 +bedr_title = nm.str.extract(r"(\d+)\s*(?:bedrooms?|Schlafzimmer)", expand=False).astype(float)
132 +fixb = (df["bedrooms"] == 0) & bedr_title.notna() & (df["studio"] == 0)
133 +df.loc[fixb, "bedrooms"] = bedr_title[fixb]
134 +df["bedrooms_raw"] = df["bedrooms"]
135 +df.loc[df["studio"] == 1, "bedrooms"] = 1
136 +KEY["n_bedrooms_recovered"] = int(fixb.sum()); KEY["n_studio_recoded"] = int(df["studio"].sum())
137 +
138 +# numeric prep
139 +for c in ("is_superhost", "is_guest_favorite", "pets_allowed"):
140 + df[c] = df[c].astype(int)
141 +df["price"] = df["price_numeric"].astype(float)
142 +df["lnp"] = np.log(df["price"])
143 +df["ln_bedrooms"] = np.log(df["bedrooms"].clip(lower=1))
144 +df["ln_bathrooms"] = np.log1p(df["bathrooms"])
145 +df["ln_guests"] = np.log(df["guests_count"].clip(lower=1))
146 +df["ln_amenities"] = np.log1p(df["amenities_count"])
147 +df["ln_images"] = np.log1p(df["num_images"])
148 +df["ln_reviews"] = np.log1p(df["num_reviews"])
149 +df["rating_c"] = np.where(df["rated"] == 1, df["rating_raw"] - 4.8, 0.0) # centred at 4.8, zero when unrated
150 +df["is_montreal"] = (df["city"] == "Montreal").astype(int)
151 +
152 +# geography: projected km, distance to nearest centre, local density
153 +R = 6371.0
154 +lat0, lon0 = df["lat"].mean(), df["long"].mean()
155 +df["x_km"] = R * np.radians(df["long"] - lon0) * np.cos(np.radians(lat0))
156 +df["y_km"] = R * np.radians(df["lat"] - lat0)
157 +sys.path.insert(0, str(ROOT))
158 +from src.config import CITY_CENTERS # noqa: E402
159 +centres = {v.name: (v.lat, v.lon) for v in CITY_CENTERS.values()}
160 +cx = np.array([R * np.radians(lo - lon0) * np.cos(np.radians(lat0)) for la, lo in centres.values()])
161 +cy = np.array([R * np.radians(la - lat0) for la, lo in centres.values()])
162 +dd = np.sqrt((df["x_km"].values[:, None] - cx[None, :]) ** 2 + (df["y_km"].values[:, None] - cy[None, :]) ** 2)
163 +df["dist_centre_km"] = dd.min(axis=1)
164 +df["ln_dist"] = np.log1p(df["dist_centre_km"])
165 +from sklearn.neighbors import KDTree # noqa: E402
166 +tree = KDTree(df[["x_km", "y_km"]].values)
167 +df["density_1km"] = tree.query_radius(df[["x_km", "y_km"]].values, r=1.0, count_only=True) - 1
168 +df["density_500m"] = tree.query_radius(df[["x_km", "y_km"]].values, r=0.5, count_only=True) - 1
169 +df["ln_density_1km"] = np.log1p(df["density_1km"])
170 +KEY["n_centres"] = len(centres)
171 +
172 +# --------------------------------------------------------------------------
173 +# 2. The price field: bimodality, mixture, regime model
174 +# --------------------------------------------------------------------------
175 +from sklearn.mixture import GaussianMixture # noqa: E402
176 +gm = GaussianMixture(2, random_state=SEED, n_init=5).fit(df[["lnp"]].values)
177 +order = np.argsort(gm.means_.ravel())
178 +mu = gm.means_.ravel()[order]; sd = np.sqrt(gm.covariances_.ravel()[order]); wt = gm.weights_[order]
179 +grid = np.linspace(df["lnp"].min(), df["lnp"].max(), 4000)
180 +post_hi = gm.predict_proba(grid[:, None])[:, order[1]]
181 +thr_ln = grid[np.argmax(post_hi >= 0.5)]
182 +KEY["mix"] = {"mu_lo": float(np.exp(mu[0])), "mu_hi": float(np.exp(mu[1])), "sd_lo": float(sd[0]), "sd_hi": float(sd[1]),
183 + "w_lo": float(wt[0]), "w_hi": float(wt[1]), "threshold": float(np.exp(thr_ln))}
184 +KEY["share_gt1000"] = float((df["price"] > 1000).mean())
185 +KEY["n_gt1000"] = int((df["price"] > 1000).sum())
186 +KEY["share_gt_mix"] = float((df["price"] > np.exp(thr_ln)).mean())
187 +KEY["share_le600"] = float((df["price"] <= 600).mean())
188 +KEY["price_median_all"] = float(df["price"].median()); KEY["price_mean_all"] = float(df["price"].mean())
189 +KEY["bimodality_coefficient"] = float((stats.skew(df["lnp"]) ** 2 + 1) / (stats.kurtosis(df["lnp"]) + 3 * (N_PRICED - 1) ** 2 / ((N_PRICED - 2) * (N_PRICED - 3))))
190 +KEY["hartigan_note"] = "dip test not run (package not installed)"
191 +
192 +# ratio of medians by bedrooms
193 +lo, hi = df[df.price <= 1000], df[df.price > 1000]
194 +ratio = (hi.groupby(hi.bedrooms.clip(upper=5))["price"].median() / lo.groupby(lo.bedrooms.clip(upper=5))["price"].median())
195 +KEY["median_ratio_by_bedrooms"] = {str(k): float(v) for k, v in ratio.items()}
196 +rows = []
197 +for b in range(6):
198 + l = lo[lo.bedrooms.clip(upper=5) == b]; h = hi[hi.bedrooms.clip(upper=5) == b]
199 + rows.append((f"{b}" if b < 5 else "5+", len(l), l.price.median(), len(h), h.price.median(), h.price.median() / l.price.median()))
200 +body = ["\\begin{tabular}{lrrrrr}", "\\toprule",
201 + "Bedrooms & $N$ & Median (\\$) & $N$ & Median (\\$) & Ratio \\\\",
202 + " & \\multicolumn{2}{c}{$\\leq$ \\$1{,}000} & \\multicolumn{2}{c}{$>$ \\$1{,}000} & \\\\", "\\midrule"]
203 +for r in rows:
204 + body.append(f"{r[0]} & {r[1]:,} & {r[2]:,.0f} & {r[3]:,} & {r[4]:,.0f} & {r[5]:.1f} \\\\")
205 +body += ["\\bottomrule", "\\end{tabular}"]
206 +write_tex("rev_price_regimes", "\n".join(body))
207 +
208 +# ---- two-regime mixture of hedonic regressions (EM) ---------------------------------
209 +# ln p_i = x_i'beta + delta * z_i + e_i, z_i in {0 (nightly), 1 (stay)}, e_i | z_i ~ N(0, sigma_z^2),
210 +# P(z_i = 1 | w_i) = Lambda(w_i'gamma). Common slopes; the stay regime shifts the intercept by delta
211 +# (a log stay length) and has its own variance (stay lengths vary).
212 +_CATD = [c for c in CATS if c != "Rental unit"]
213 +def _X_mix(d):
214 + X = pd.DataFrame({"ln_bedrooms": d["ln_bedrooms"], "ln_bathrooms": d["ln_bathrooms"], "ln_guests": d["ln_guests"],
215 + "shared_bath": d["shared_bath"], "studio": d["studio"], "ln_amenities": d["ln_amenities"],
216 + "ln_images": d["ln_images"], "is_superhost": d["is_superhost"], "is_guest_favorite": d["is_guest_favorite"],
217 + "ln_reviews": d["ln_reviews"], "rated": d["rated"], "rating_c": d["rating_c"], "ln_dist": d["ln_dist"],
218 + "ln_density_1km": d["ln_density_1km"], "is_montreal": d["is_montreal"]}, index=d.index)
219 + for c in _CATD:
220 + X[c] = (d["category"] == c).astype(float)
221 + return sm.add_constant(X.astype(float))
222 +Xm = _X_mix(df); ym = df["lnp"].values
223 +Wm = sm.add_constant(pd.DataFrame({"is_montreal": df["is_montreal"], "ln_reviews": df["ln_reviews"], "ln_guests": df["ln_guests"],
224 + "is_superhost": df["is_superhost"], "hotel": (df["category"] == "Hotel/B&B/hostel").astype(float),
225 + "chalet": (df["category"] == "Chalet/cottage/cabin").astype(float)}, index=df.index).astype(float))
226 +r = (df["price"] > 1000).astype(float).values # initialisation: the $1,000 rule
227 +delta, s0, s1 = 3.0, 0.5, 0.8; gamma = None
228 +for it in range(300):
229 + # M-step: WLS on stacked data for (beta, delta)
230 + Xs = np.vstack([np.column_stack([Xm.values, np.zeros(len(ym))]), np.column_stack([Xm.values, np.ones(len(ym))])])
231 + ys = np.concatenate([ym, ym]); ws = np.concatenate([(1 - r) / s0 ** 2, r / s1 ** 2])
232 + coef = np.linalg.lstsq(Xs * np.sqrt(ws)[:, None], ys * np.sqrt(ws), rcond=None)[0]
233 + beta, delta = coef[:-1], coef[-1]
234 + f0 = Xm.values @ beta; f1 = f0 + delta
235 + s0 = np.sqrt(np.sum((1 - r) * (ym - f0) ** 2) / np.sum(1 - r)); s1 = np.sqrt(np.sum(r * (ym - f1) ** 2) / np.sum(r))
236 + glm = sm.GLM(r, Wm, family=sm.families.Binomial()).fit(); gamma = glm.params.values; pi = glm.fittedvalues.values
237 + # E-step
238 + l0 = (1 - pi) * stats.norm.pdf(ym, f0, s0); l1 = pi * stats.norm.pdf(ym, f1, s1)
239 + r_new = l1 / (l0 + l1)
240 + ll = np.sum(np.log(l0 + l1))
241 + if np.max(np.abs(r_new - r)) < 1e-7:
242 + r = r_new; break
243 + r = r_new
244 +df["p_stay"] = r
245 +df["stay_regime"] = (r >= 0.5).astype(int)
246 +KEY["mixreg"] = {"iterations": it + 1, "loglik": float(ll), "delta": float(delta), "implied_nights": float(np.exp(delta)),
247 + "sigma_nightly": float(s0), "sigma_stay": float(s1), "share_stay": float(r.mean()), "n_stay": int(df["stay_regime"].sum()),
248 + "n_nightly": int((df["stay_regime"] == 0).sum()),
249 + "gamma": {k: [float(v), float(glm.bse[k]), float(glm.pvalues[k])] for k, v in glm.params.items()},
250 + "beta_common": {k: float(v) for k, v in zip(Xm.columns, beta)},
251 + "n_stay_le1000": int(((df["stay_regime"] == 1) & (df["price"] <= 1000)).sum()),
252 + "n_nightly_gt1000": int(((df["stay_regime"] == 0) & (df["price"] > 1000)).sum()),
253 + "n_ambiguous_25_75": int(((r > 0.25) & (r < 0.75)).sum()),
254 + "entropy_R2": float(1 + np.sum(r * np.log(np.clip(r, 1e-12, 1)) + (1 - r) * np.log(np.clip(1 - r, 1e-12, 1))) / (len(r) * np.log(2)))}
255 +# table: mixture parameters
256 +body = ["\\begin{tabular}{lr}", "\\toprule", "Parameter & Estimate \\\\", "\\midrule",
257 + f"Intercept shift of the stay regime, $\\delta$ (log points) & {delta:.3f} \\\\",
258 + f"Implied stay length, $\\exp(\\delta)$ (nights) & {np.exp(delta):.1f} \\\\",
259 + f"Residual s.d., nightly regime, $\\sigma_0$ & {s0:.3f} \\\\",
260 + f"Residual s.d., stay regime, $\\sigma_1$ & {s1:.3f} \\\\",
261 + f"Mean posterior probability of the stay regime & {r.mean():.3f} \\\\",
262 + f"Listings classified in the stay regime ($\\hat{{p}}_i \\geq 0.5$) & {int(df['stay_regime'].sum()):,} \\\\",
263 + f"\\quad of which displayed price $\\leq$ \\$1{{,}}000 & {KEY['mixreg']['n_stay_le1000']:,} \\\\",
264 + f"Listings classified nightly with displayed price $>$ \\$1{{,}}000 & {KEY['mixreg']['n_nightly_gt1000']:,} \\\\",
265 + f"Listings with $0.25 < \\hat{{p}}_i < 0.75$ & {KEY['mixreg']['n_ambiguous_25_75']:,} \\\\",
266 + f"Log-likelihood & {ll:,.1f} \\\\", f"EM iterations & {it + 1} \\\\", "\\midrule",
267 + "\\multicolumn{2}{l}{\\textit{Regime equation (logit coefficients, SE)}} \\\\"]
268 +GL = {"const": "Constant", "is_montreal": "Montreal", "ln_reviews": "ln(1 + reviews)", "ln_guests": "ln(guests)", "is_superhost": "Superhost",
269 + "hotel": "Hotel/B\\&B/hostel", "chalet": "Chalet/cottage/cabin"}
270 +for k, v in glm.params.items():
271 + body.append(f"{GL[k]} & {v:.3f}{stars(glm.pvalues[k])} ({glm.bse[k]:.3f}) \\\\")
272 +body += ["\\bottomrule", "\\end{tabular}"]
273 +write_tex("rev_mixture", "\n".join(body))
274 +
275 +# regime logit: which listings are classified in the stay regime?
276 +Xl = pd.get_dummies(df[["ln_bedrooms", "ln_bathrooms", "ln_guests", "ln_amenities", "is_superhost", "is_guest_favorite",
277 + "rated", "ln_reviews", "is_montreal", "ln_dist", "category"]], columns=["category"], drop_first=True, dtype=float)
278 +Xl.columns = [c.replace("category_", "") for c in Xl.columns]
279 +logit = sm.Logit(df["stay_regime"], sm.add_constant(Xl)).fit(disp=0, cov_type="HC1")
280 +me = logit.get_margeff(at="overall")
281 +LAB = {"ln_bedrooms": "ln(bedrooms)", "ln_bathrooms": "ln(1 + bathrooms)", "ln_guests": "ln(guests)",
282 + "ln_amenities": "ln(1 + amenities)", "is_superhost": "Superhost", "is_guest_favorite": "Guest Favourite",
283 + "rated": "Rated (star shown)", "ln_reviews": "ln(1 + reviews)", "is_montreal": "Montreal", "ln_dist": "ln(1 + km to centre)",
284 + "rating_c": "Rating $-$ 4.8 (rated only)", "ln_images": "ln(1 + photos)", "pets_allowed": "Pets allowed",
285 + "shared_bath": "Shared bathroom", "studio": "Studio", "ln_density_1km": "ln(1 + listings within 1 km)",
286 + "Chalet/cottage/cabin": "Chalet/cottage/cabin", "House": "House", "Condo/loft/apartment": "Condo/loft/apartment",
287 + "Hotel/B&B/hostel": "Hotel/B\\&B/hostel", "Other/unconventional": "Other/unconventional", "const": "Constant"}
288 +body = ["\\begin{tabular}{lrrrr}", "\\toprule", "Variable & Coefficient & (SE) & Avg.\\ marginal effect & (SE) \\\\", "\\midrule"]
289 +me_tab = me.summary_frame()
290 +for v in Xl.columns:
291 + body.append(f"{LAB.get(v, v)} & {logit.params[v]:.3f}{stars(logit.pvalues[v])} & ({logit.bse[v]:.3f}) & "
292 + f"{me_tab.loc[v, 'dy/dx']:.3f} & ({me_tab.loc[v, 'Std. Err.']:.3f}) \\\\")
293 +body += ["\\midrule", f"Observations & \\multicolumn{{4}}{{c}}{{{int(logit.nobs):,}}} \\\\",
294 + f"Pseudo-$R^2$ & \\multicolumn{{4}}{{c}}{{{logit.prsquared:.3f}}} \\\\",
295 + f"Share in regime & \\multicolumn{{4}}{{c}}{{{df['stay_regime'].mean():.3f}}} \\\\", "\\bottomrule", "\\end{tabular}"]
296 +write_tex("rev_stay_logit", "\n".join(body))
297 +KEY["logit"] = {v: [float(logit.params[v]), float(logit.bse[v]), float(logit.pvalues[v]), float(me_tab.loc[v, "dy/dx"])] for v in Xl.columns}
298 +
299 +# figure: log-price histogram with mixture
300 +fig, ax = plt.subplots(figsize=(6.5, 3.8))
301 +ax.hist(df["lnp"], bins=60, density=True, color="#9ecae1", edgecolor="white")
302 +xs = grid
303 +for k, c in zip(range(2), ("#3182bd", "#de2d26")):
304 + ax.plot(xs, wt[k] * stats.norm.pdf(xs, mu[k], sd[k]), color=c, lw=1.5,
305 + label=f"component {k + 1}: mode \\${np.exp(mu[k]):,.0f}, weight {wt[k]:.2f}")
306 +ax.plot(xs, gm.score_samples(xs[:, None]).pipe(np.exp) if False else np.exp(gm.score_samples(xs[:, None])), "k--", lw=1, label="mixture")
307 +ax.axvline(np.log(1000), color="grey", ls=":", lw=1); ax.text(np.log(1000) + 0.05, ax.get_ylim()[1] * 0.9, "\\$1,000", color="grey")
308 +ax.axvline(thr_ln, color="#de2d26", ls=":", lw=1)
309 +ticks = [25, 50, 100, 200, 500, 1000, 2000, 5000, 10000]
310 +ax.set_xticks(np.log(ticks)); ax.set_xticklabels([f"{t:,}" for t in ticks])
311 +ax.set_xlabel("Displayed price (CAD, log scale)"); ax.set_ylabel("Density"); ax.legend(frameon=False, fontsize=8)
312 +savefig(fig, "rev_fig_logprice_mixture")
313 +
314 +# --------------------------------------------------------------------------
315 +# 3. Analysis sample and descriptives
316 +# --------------------------------------------------------------------------
317 +A = df[df["stay_regime"] == 0].copy().reset_index(drop=True) # nightly regime (posterior < 0.5)
318 +KEY["N_A"] = len(A); KEY["N_priced"] = N_PRICED; KEY["N_scraped"] = 5000
319 +KEY["A_price_median"] = float(A.price.median()); KEY["A_price_mean"] = float(A.price.mean())
320 +KEY["A_share_montreal"] = float(A.is_montreal.mean()); KEY["A_n_cities"] = int(A.city.nunique())
321 +KEY["A_unrated_share"] = float((A.rated == 0).mean()); KEY["A_superhost"] = float(A.is_superhost.mean())
322 +KEY["A_guestfav"] = float(A.is_guest_favorite.mean()); KEY["A_cat_shares"] = A.category.value_counts(normalize=True).round(3).to_dict()
323 +KEY["A_cat_shares"] = {str(k): float(v) for k, v in KEY["A_cat_shares"].items()}
324 +KEY["A_p1_clip_n"] = int((A.price <= df.price.min() + 1e-6).sum()); KEY["A_price_max"] = float(A.price.max()); KEY["A_share_gt1000"] = float((A.price > 1000).mean())
325 +
326 +DESC = [("price", "Displayed price (CAD)"), ("lnp", "ln(price)"), ("bedrooms", "Bedrooms"), ("bathrooms", "Bathrooms"),
327 + ("guests_count", "Guest capacity"), ("beds", "Beds (from title)"), ("amenities_count", "Amenities count"),
328 + ("num_images", "Photos"), ("num_reviews", "Reviews"), ("rating_raw", "Rating (rated listings)"),
329 + ("rated", "Rated (star shown)"), ("is_superhost", "Superhost"), ("is_guest_favorite", "Guest Favourite"),
330 + ("pets_allowed", "Pets allowed"), ("shared_bath", "Shared bathroom"), ("studio", "Studio"),
331 + ("dist_centre_km", "Distance to nearest centre (km)"), ("density_1km", "Listings within 1 km"), ("is_montreal", "Montreal"), ("p_stay", "Posterior prob.\\ of stay regime")]
332 +body = ["\\begin{tabular}{lrrrrrrr}", "\\toprule",
333 + "Variable & Mean & Std.\\ dev. & P10 & Median & P90 & $N$ & Mean, full \\\\", "\\midrule"]
334 +for c, lab in DESC:
335 + s = A[c].dropna().astype(float); f = df[c].dropna().astype(float)
336 + d = 0 if c in ("price", "bedrooms", "guests_count", "beds", "amenities_count", "num_images", "num_reviews", "density_1km") else 2
337 + body.append(f"{lab} & {s.mean():,.{d}f} & {s.std():,.{d}f} & {s.quantile(.1):,.{d}f} & {s.median():,.{d}f} & {s.quantile(.9):,.{d}f} & {len(s):,} & {f.mean():,.{d}f} \\\\")
338 +body += ["\\bottomrule", "\\end{tabular}"]
339 +write_tex("rev_summary", "\n".join(body))
340 +
341 +body = ["\\begin{tabular}{lrrrrrr}", "\\toprule", "Title category & $N$ & Share & Mean (\\$) & Median (\\$) & P10 & P90 \\\\", "\\midrule"]
342 +for c in CATS:
343 + s = A.loc[A.category == c, "price"]
344 + body.append(f"{tex_escape(c)} & {len(s):,} & {len(s) / len(A):.3f} & {s.mean():,.0f} & {s.median():,.0f} & {s.quantile(.1):,.0f} & {s.quantile(.9):,.0f} \\\\")
345 +s = A.price
346 +body += ["\\midrule", f"All & {len(s):,} & 1.000 & {s.mean():,.0f} & {s.median():,.0f} & {s.quantile(.1):,.0f} & {s.quantile(.9):,.0f} \\\\",
347 + "\\bottomrule", "\\end{tabular}"]
348 +write_tex("rev_price_by_category", "\n".join(body))
349 +
350 +# --------------------------------------------------------------------------
351 +# 4. Nested OLS hedonic models
352 +# --------------------------------------------------------------------------
353 +STRUCT = ["ln_bedrooms", "ln_bathrooms", "ln_guests", "shared_bath", "studio"]
354 +CATD = [c for c in CATS if c != "Rental unit"]
355 +AMEN = ["ln_amenities", "pets_allowed", "ln_images"]
356 +HOST = ["is_superhost", "is_guest_favorite", "ln_reviews", "rated", "rating_c"]
357 +LOC = ["ln_dist", "ln_density_1km"]
358 +# city fixed effects: cities with >= 15 listings in the analysis sample; the rest pooled by K-means cell
359 +MIN_CITY = 15
360 +from sklearn.cluster import KMeans # noqa: E402
361 +vc = A.city.value_counts()
362 +big = set(vc[vc >= MIN_CITY].index)
363 +small = A[~A.city.isin(big)]
364 +km_small = KMeans(n_clusters=25, random_state=SEED, n_init=10).fit(small[["x_km", "y_km"]].values)
365 +A["fe_city"] = np.where(A.city.isin(big), A.city, "cell_" + pd.Series(km_small.predict(A[["x_km", "y_km"]].values), index=A.index).astype(str))
366 +KEY["n_city_fe"] = int(len(big)); KEY["n_cell_fe"] = 25; KEY["share_in_city_fe"] = float(A.city.isin(big).mean())
367 +KEY["n_fe_groups"] = int(A.fe_city.nunique())
368 +# finer grid-cell FE for robustness
369 +A["fe_cell60"] = KMeans(n_clusters=60, random_state=SEED, n_init=10).fit_predict(A[["x_km", "y_km"]].values)
370 +
371 +
372 +def design(d, cols, fe=None, drop_first_fe="Montreal"):
373 + X = pd.DataFrame(index=d.index)
374 + for c in cols:
375 + X[c] = (d.category == c).astype(float) if c in CATD else d[c].astype(float)
376 + if fe is not None:
377 + D = pd.get_dummies(d[fe].astype(str), prefix="fe", dtype=float)
378 + ref = f"fe_{drop_first_fe}" if f"fe_{drop_first_fe}" in D.columns else D.columns[0]
379 + D = D.drop(columns=[ref])
380 + X = pd.concat([X, D], axis=1)
381 + return sm.add_constant(X)
382 +
383 +
384 +SPECS = {
385 + "M1": STRUCT + CATD,
386 + "M2": STRUCT + CATD + AMEN,
387 + "M3": STRUCT + CATD + AMEN + HOST,
388 + "M4": STRUCT + CATD + AMEN + HOST + LOC,
389 + "M5": STRUCT + CATD + AMEN + HOST + LOC, # + city FE
390 +}
391 +fits = {}
392 +for k, cols in SPECS.items():
393 + X = design(A, cols, fe="fe_city" if k == "M5" else None)
394 + fits[k] = sm.OLS(A["lnp"], X).fit(cov_type="HC3")
395 +fit5_cl = sm.OLS(A["lnp"], design(A, SPECS["M5"], fe="fe_city")).fit(cov_type="cluster", cov_kwds={"groups": A["fe_city"].astype("category").cat.codes})
396 +fit5_cell = sm.OLS(A["lnp"], design(A, SPECS["M5"], fe="fe_city")).fit(cov_type="cluster", cov_kwds={"groups": A["fe_cell60"]})
397 +# VIF (M4, no FE)
398 +from statsmodels.stats.outliers_influence import variance_inflation_factor # noqa: E402
399 +X4 = design(A, SPECS["M4"])
400 +vif = pd.Series({c: variance_inflation_factor(X4.values, i) for i, c in enumerate(X4.columns) if c != "const"})
401 +KEY["vif_max"] = float(vif.max()); KEY["vif_argmax"] = str(vif.idxmax()); KEY["vif"] = {k: float(v) for k, v in vif.items()}
402 +
403 +ROWS = STRUCT + CATD + AMEN + HOST + LOC
404 +body = ["\\begin{tabular}{l" + "r" * 6 + "}", "\\toprule",
405 + " & (1) & (2) & (3) & (4) & (5) & (5$'$) \\\\",
406 + "Dependent variable: ln(price) & M1 & M2 & M3 & M4 & M5 & M5 \\\\", "\\midrule"]
407 +for v in ROWS:
408 + line = [LAB.get(v, tex_escape(v))]; se_line = [""]
409 + for k in ("M1", "M2", "M3", "M4", "M5"):
410 + f = fits[k]
411 + if v in f.params.index:
412 + line.append(f"{f.params[v]:.3f}{stars(f.pvalues[v])}"); se_line.append(f"({f.bse[v]:.3f})")
413 + else:
414 + line.append(""); se_line.append("")
415 + if v in fit5_cl.params.index:
416 + line.append(f"{fit5_cl.params[v]:.3f}{stars(fit5_cl.pvalues[v])}"); se_line.append(f"[{fit5_cl.bse[v]:.3f}]")
417 + else:
418 + line.append(""); se_line.append("")
419 + body.append(" & ".join(line) + " \\\\"); body.append(" & ".join(se_line) + " \\\\")
420 +body += ["\\midrule", "City / cell fixed effects & No & No & No & No & Yes & Yes \\\\",
421 + "Standard errors & HC3 & HC3 & HC3 & HC3 & HC3 & Cluster \\\\"]
422 +for lab, fn in (("Observations", lambda f: f"{int(f.nobs):,}"), ("$R^2$", lambda f: f"{f.rsquared:.3f}"),
423 + ("Adjusted $R^2$", lambda f: f"{f.rsquared_adj:.3f}"), ("RMSE", lambda f: f"{np.sqrt(f.mse_resid * f.df_resid / f.nobs):.3f}"),
424 + ("AIC", lambda f: f"{f.aic:,.0f}")):
425 + body.append(lab + " & " + " & ".join(fn(fits[k]) for k in ("M1", "M2", "M3", "M4", "M5")) + f" & {fn(fit5_cl)} \\\\")
426 +body += ["\\bottomrule", "\\end{tabular}"]
427 +write_tex("rev_ols_nested", "\n".join(body))
428 +KEY["ols"] = {k: {"n": int(f.nobs), "r2": float(f.rsquared), "adj": float(f.rsquared_adj), "rmse": float(np.sqrt(f.mse_resid * f.df_resid / f.nobs)),
429 + "aic": float(f.aic), "params": {v: [float(f.params[v]), float(f.bse[v]), float(f.pvalues[v])] for v in ROWS if v in f.params.index}}
430 + for k, f in fits.items()}
431 +KEY["ols"]["M5_cluster_city"] = {v: [float(fit5_cl.params[v]), float(fit5_cl.bse[v]), float(fit5_cl.pvalues[v])] for v in ROWS}
432 +KEY["ols"]["M5_cluster_cell60"] = {v: [float(fit5_cell.params[v]), float(fit5_cell.bse[v]), float(fit5_cell.pvalues[v])] for v in ROWS}
433 +# Kennedy (1981) corrected premia for dummies in M5
434 +f = fits["M5"]
435 +KEY["premia_M5"] = {v: float(100 * (np.exp(f.params[v] - 0.5 * f.bse[v] ** 2) - 1)) for v in CATD + ["shared_bath", "studio", "pets_allowed", "is_superhost", "is_guest_favorite", "rated"]}
436 +# F-tests of blocks (M5)
437 +def ftest(fit, vars_):
438 + R = np.zeros((len(vars_), len(fit.params)));
439 + for i, v in enumerate(vars_): R[i, list(fit.params.index).index(v)] = 1
440 + t = fit.f_test(R); return float(np.squeeze(t.fvalue)), float(t.pvalue)
441 +KEY["ftests_M5"] = {"category": ftest(f, CATD), "host": ftest(f, HOST), "amenities": ftest(f, AMEN), "location": ftest(f, LOC)}
442 +fe_cols = [c for c in f.params.index if c.startswith("fe_")]
443 +KEY["ftests_M5"]["city_fe"] = ftest(f, fe_cols)
444 +KEY["r2_within_fe_only"] = float(sm.OLS(A["lnp"], design(A, [], fe="fe_city")).fit().rsquared)
445 +log(f"OLS done: R2 M1..M5 = {[round(fits[k].rsquared, 3) for k in fits]}")
446 +
447 +# --------------------------------------------------------------------------
448 +# 5. Quantile regression (M5 specification)
449 +# --------------------------------------------------------------------------
450 +TAUS = [0.10, 0.25, 0.50, 0.75, 0.90]
451 +X5 = design(A, SPECS["M5"], fe="fe_city")
452 +qfits = {t: sm.QuantReg(A["lnp"], X5).fit(q=t, max_iter=5000) for t in TAUS}
453 +QROWS = ["ln_bedrooms", "ln_bathrooms", "ln_guests", "shared_bath", "Chalet/cottage/cabin", "House", "Condo/loft/apartment",
454 + "Hotel/B&B/hostel", "ln_amenities", "ln_images", "is_superhost", "is_guest_favorite", "ln_reviews", "rated", "rating_c", "ln_dist", "ln_density_1km"]
455 +body = ["\\begin{tabular}{l" + "r" * 6 + "}", "\\toprule",
456 + "Variable & OLS & $\\tau=0.10$ & $\\tau=0.25$ & $\\tau=0.50$ & $\\tau=0.75$ & $\\tau=0.90$ \\\\", "\\midrule"]
457 +for v in QROWS:
458 + line = [LAB.get(v, tex_escape(v)), f"{fits['M5'].params[v]:.3f}{stars(fits['M5'].pvalues[v])}"]; se = ["", f"({fits['M5'].bse[v]:.3f})"]
459 + for t in TAUS:
460 + q = qfits[t]; line.append(f"{q.params[v]:.3f}{stars(q.pvalues[v])}"); se.append(f"({q.bse[v]:.3f})")
461 + body.append(" & ".join(line) + " \\\\"); body.append(" & ".join(se) + " \\\\")
462 +
463 +
464 +def pseudo_r2(q, t):
465 + u = A["lnp"] - q.fittedvalues; rho = lambda u: np.sum(u * (t - (u < 0)))
466 + u0 = A["lnp"] - A["lnp"].quantile(t); return 1 - rho(u) / rho(u0)
467 +
468 +
469 +body += ["\\midrule", "Pseudo-$R^2$ / $R^2$ & " + f"{fits['M5'].rsquared:.3f} & " + " & ".join(f"{pseudo_r2(qfits[t], t):.3f}" for t in TAUS) + " \\\\",
470 + f"Observations & \\multicolumn{{6}}{{c}}{{{len(A):,}}} \\\\", "City / cell fixed effects & \\multicolumn{6}{c}{Yes} \\\\",
471 + "\\bottomrule", "\\end{tabular}"]
472 +write_tex("rev_quantile", "\n".join(body))
473 +KEY["quantile"] = {str(t): {v: [float(qfits[t].params[v]), float(qfits[t].bse[v]), float(qfits[t].pvalues[v])] for v in QROWS} for t in TAUS}
474 +KEY["quantile_pseudoR2"] = {str(t): float(pseudo_r2(qfits[t], t)) for t in TAUS}
475 +# interquantile difference tests (0.90 - 0.10) by pairwise bootstrap (B = 200)
476 +rng = np.random.default_rng(SEED)
477 +B = 100; diffs = {v: [] for v in ("ln_bedrooms", "ln_guests", "is_superhost", "rating_c", "ln_reviews", "ln_dist")}
478 +cache = TAB / "rev_iq_bootstrap.json"
479 +if cache.exists():
480 + diffs = json.loads(cache.read_text()); log("inter-quantile bootstrap loaded from cache")
481 +else:
482 + for b in range(B):
483 + idx = rng.integers(0, len(A), len(A))
484 + q1 = sm.QuantReg(A["lnp"].values[idx], X5.values[idx]).fit(q=0.10, max_iter=3000)
485 + q9 = sm.QuantReg(A["lnp"].values[idx], X5.values[idx]).fit(q=0.90, max_iter=3000)
486 + for v in diffs:
487 + j = list(X5.columns).index(v); diffs[v].append(float(q9.params[j] - q1.params[j]))
488 + cache.write_text(json.dumps(diffs))
489 +KEY["iq_bootstrap_B"] = B
490 +KEY["iq_diff_90_10"] = {}
491 +for v, arr in diffs.items():
492 + arr = np.array(arr); est = qfits[0.90].params[v] - qfits[0.10].params[v]
493 + KEY["iq_diff_90_10"][v] = [float(est), float(arr.std(ddof=1)), float(2 * (1 - stats.norm.cdf(abs(est / arr.std(ddof=1)))))]
494 +log("quantile done")
495 +
496 +fig, axes = plt.subplots(2, 3, figsize=(9.5, 5.2)); axes = axes.ravel()
497 +for ax, v in zip(axes, ["ln_bedrooms", "ln_guests", "ln_bathrooms", "is_superhost", "rating_c", "ln_dist"]):
498 + est = [qfits[t].params[v] for t in TAUS]; se = [qfits[t].bse[v] for t in TAUS]
499 + ax.fill_between(TAUS, np.array(est) - 1.96 * np.array(se), np.array(est) + 1.96 * np.array(se), color="#c6dbef")
500 + ax.plot(TAUS, est, "o-", color="#08519c", ms=3)
501 + ax.axhline(fits["M5"].params[v], color="#de2d26", ls="--", lw=1); ax.axhline(0, color="grey", lw=0.5)
502 + ax.set_title(LAB[v], fontsize=9); ax.set_xticks(TAUS)
503 +fig.supxlabel("Quantile $\\tau$ of ln(price)"); fig.supylabel("Coefficient")
504 +fig.tight_layout(); savefig(fig, "rev_fig_quantile")
505 +
506 +# --------------------------------------------------------------------------
507 +# 6. Spatial econometrics (M4 specification; W = k-nearest neighbours on projected km)
508 +# --------------------------------------------------------------------------
509 +import libpysal, spreg # noqa: E402
510 +from esda.moran import Moran # noqa: E402
511 +coords = A[["x_km", "y_km"]].values
512 +
513 +
514 +def knn_w(k):
515 + w = libpysal.weights.KNN.from_array(coords, k=k); w.transform = "r"; return w
516 +
517 +
518 +W5, W10 = knn_w(5), knn_w(10)
519 +KEY["moran"] = {}
520 +for lab, f, w in (("M4_k5", fits["M4"], W5), ("M5_k5", fits["M5"], W5), ("lnp_k5", None, W5), ("M4_k10", fits["M4"], W10)):
521 + z = A["lnp"].values if f is None else f.resid.values
522 + mi = Moran(z, w, permutations=999)
523 + KEY["moran"][lab] = [float(mi.I), float(mi.z_norm), float(mi.p_norm)]
524 +Xs = design(A, SPECS["M4"]).drop(columns="const")
525 +y = A[["lnp"]].values; Xv = Xs.values; names = list(Xs.columns)
526 +sar = spreg.ML_Lag(y, Xv, W5, name_x=names, name_y="lnp", method="full")
527 +sem = spreg.ML_Error(y, Xv, W5, name_x=names, name_y="lnp", method="full")
528 +sdm = spreg.ML_Lag(y, Xv, W5, name_x=names, name_y="lnp", method="full", slx_lags=1)
529 +sar10 = spreg.ML_Lag(y, Xv, W10, name_x=names, name_y="lnp", method="full")
530 +ols4 = fits["M4"]
531 +
532 +
533 +def sp_row(mod, v, lagged=False):
534 + nm_ = [n for n in mod.name_x]
535 + try:
536 + j = nm_.index(("W_" + v) if lagged else v)
537 + except ValueError:
538 + return "", ""
539 + b = float(mod.betas[j, 0]); se_ = float(mod.std_err[j]); p = float(mod.z_stat[j][1])
540 + return f"{b:.3f}{stars(p)}", f"({se_:.3f})"
541 +
542 +
543 +SROWS = ["ln_bedrooms", "ln_bathrooms", "ln_guests", "shared_bath", "Chalet/cottage/cabin", "House", "Condo/loft/apartment", "Hotel/B&B/hostel",
544 + "ln_amenities", "ln_images", "is_superhost", "is_guest_favorite", "ln_reviews", "rated", "rating_c", "ln_dist", "ln_density_1km"]
545 +body = ["\\begin{tabular}{lrrrrr}", "\\toprule", "Variable & OLS (M4) & SAR & SEM & SDM & SDM, $\\mathbf{W}x$ \\\\", "\\midrule"]
546 +for v in SROWS:
547 + l = [LAB.get(v, tex_escape(v)), f"{ols4.params[v]:.3f}{stars(ols4.pvalues[v])}"]; s = ["", f"({ols4.bse[v]:.3f})"]
548 + for m in (sar, sem, sdm):
549 + a, b_ = sp_row(m, v); l.append(a); s.append(b_)
550 + a, b_ = sp_row(sdm, v, lagged=True); l.append(a); s.append(b_)
551 + body.append(" & ".join(l) + " \\\\"); body.append(" & ".join(s) + " \\\\")
552 +rho_p = lambda m: float(m.z_stat[-1][1])
553 +body += ["\\midrule",
554 + f"$\\rho$ (spatial lag) & & {float(np.squeeze(sar.rho)):.3f}{stars(rho_p(sar))} & & {float(np.squeeze(sdm.rho)):.3f}{stars(rho_p(sdm))} & \\\\",
555 + f" & & ({float(sar.std_err[-1]):.3f}) & & ({float(sdm.std_err[-1]):.3f}) & \\\\",
556 + f"$\\lambda$ (spatial error) & & & {float(np.squeeze(sem.lam)):.3f}{stars(rho_p(sem))} & & \\\\",
557 + f" & & & ({float(sem.std_err[-1]):.3f}) & & \\\\",
558 + f"Log-likelihood & {ols4.llf:,.1f} & {float(np.squeeze(sar.logll)):,.1f} & {float(np.squeeze(sem.logll)):,.1f} & {float(np.squeeze(sdm.logll)):,.1f} & \\\\",
559 + f"AIC & {ols4.aic:,.0f} & {float(np.squeeze(sar.aic)):,.0f} & {float(np.squeeze(sem.aic)):,.0f} & {float(np.squeeze(sdm.aic)):,.0f} & \\\\",
560 + f"Pseudo-$R^2$ & {ols4.rsquared:.3f} & {float(np.squeeze(sar.pr2)):.3f} & {float(np.squeeze(sem.pr2)):.3f} & {float(np.squeeze(sdm.pr2)):.3f} & \\\\",
561 + f"Observations & \\multicolumn{{5}}{{c}}{{{len(A):,}}} \\\\", "\\bottomrule", "\\end{tabular}"]
562 +write_tex("rev_spatial", "\n".join(body))
563 +KEY["spatial"] = {"rho_sar": [float(np.squeeze(sar.rho)), float(sar.std_err[-1]), rho_p(sar)], "lam_sem": [float(np.squeeze(sem.lam)), float(sem.std_err[-1]), rho_p(sem)],
564 + "rho_sdm": [float(np.squeeze(sdm.rho)), float(sdm.std_err[-1]), rho_p(sdm)], "rho_sar_k10": [float(np.squeeze(sar10.rho)), float(sar10.std_err[-1]), rho_p(sar10)],
565 + "ll": {"ols": float(ols4.llf), "sar": float(np.squeeze(sar.logll)), "sem": float(np.squeeze(sem.logll)), "sdm": float(np.squeeze(sdm.logll))},
566 + "aic": {"ols": float(ols4.aic), "sar": float(np.squeeze(sar.aic)), "sem": float(np.squeeze(sem.aic)), "sdm": float(np.squeeze(sdm.aic))}}
567 +# LR test SDM vs SAR (restriction theta = 0)
568 +lr = 2 * (float(np.squeeze(sdm.logll)) - float(np.squeeze(sar.logll))); KEY["spatial"]["lr_sdm_vs_sar"] = [lr, int(len(names)), float(1 - stats.chi2.cdf(lr, len(names)))]
569 +# LeSage-Pace impacts (SAR and SDM), dense inverse
570 +Wd = W5.full()[0]
571 +I_n = np.eye(len(A)); S_sar = np.linalg.inv(I_n - float(np.squeeze(sar.rho)) * Wd); S_sdm = np.linalg.inv(I_n - float(np.squeeze(sdm.rho)) * Wd)
572 +imp = {}
573 +for v in SROWS:
574 + j = names.index(v); b_sar = float(sar.betas[j + 1, 0])
575 + d = np.trace(S_sar) / len(A) * b_sar; t = S_sar.sum() / len(A) * b_sar
576 + b_sdm = float(sdm.betas[j + 1, 0]); th = float(sdm.betas[sdm.name_x.index("W_" + v), 0])
577 + M = S_sdm @ (I_n * b_sdm + Wd * th)
578 + d2 = np.trace(M) / len(A); t2 = M.sum() / len(A)
579 + imp[v] = {"sar": [d, t - d, t], "sdm": [d2, t2 - d2, t2]}
580 +# simulated SEs for SAR and SDM impacts (300 draws from the ML asymptotic distribution; exact traces via the
581 +# complex eigenvalues of the asymmetric KNN matrix: tr[(I - rW)^-1] = sum_i 1/(1 - r*lambda_i))
582 +rng = np.random.default_rng(SEED)
583 +evals = np.linalg.eigvals(Wd)
584 +def _sim(mod, has_theta):
585 + V = np.asarray(mod.vm); th_hat = mod.betas.ravel(); dr_all = rng.multivariate_normal(th_hat, V, size=300)
586 + out = {v: [] for v in SROWS}
587 + for dr in dr_all:
588 + r_ = dr[-1]
589 + if abs(r_) >= 1:
590 + continue
591 + tr = np.mean(1 / (1 - r_ * evals)).real; trw = np.mean(evals / (1 - r_ * evals)).real; tot = 1 / (1 - r_)
592 + for v in SROWS:
593 + b = dr[names.index(v) + 1]; th = dr[mod.name_x.index("W_" + v)] if has_theta else 0.0
594 + direct = tr * b + trw * th; total = (b + th) * tot
595 + out[v].append([direct, total - direct, total])
596 + return {v: np.array(a).std(axis=0, ddof=1) for v, a in out.items()}
597 +sd_sar = _sim(sar, False); sd_sdm = _sim(sdm, True)
598 +pz = lambda est, sd_: stars(2 * (1 - stats.norm.cdf(abs(est / sd_)))) if sd_ > 0 else ""
599 +body = ["\\begin{tabular}{lrrrrrr}", "\\toprule", " & \\multicolumn{3}{c}{SAR} & \\multicolumn{3}{c}{SDM} \\\\",
600 + "\\cmidrule(lr){2-4}\\cmidrule(lr){5-7}", "Variable & Direct & Indirect & Total & Direct & Indirect & Total \\\\", "\\midrule"]
601 +KEY["impacts"] = {}
602 +for v in SROWS:
603 + a = imp[v]; s1_ = sd_sar[v]; s2_ = sd_sdm[v]
604 + body.append(f"{LAB.get(v, tex_escape(v))} & " + " & ".join(f"{a['sar'][i]:.3f}{pz(a['sar'][i], s1_[i])}" for i in range(3)) + " & "
605 + + " & ".join(f"{a['sdm'][i]:.3f}{pz(a['sdm'][i], s2_[i])}" for i in range(3)) + " \\\\")
606 + body.append(" & " + " & ".join(f"({s1_[i]:.3f})" for i in range(3)) + " & " + " & ".join(f"({s2_[i]:.3f})" for i in range(3)) + " \\\\")
607 + KEY["impacts"][v] = {"sar": a["sar"], "sar_se": s1_.tolist(), "sdm": a["sdm"], "sdm_se": s2_.tolist()}
608 +body += ["\\bottomrule", "\\end{tabular}"]
609 +write_tex("rev_impacts", "\n".join(body))
610 +KEY["spatial"]["sar_multiplier"] = float(S_sar.sum() / len(A)); KEY["spatial"]["sar_direct_ratio"] = float(np.trace(S_sar) / len(A))
611 +log("spatial done")
612 +
613 +# --------------------------------------------------------------------------
614 +# 7. Machine learning: random vs spatially blocked cross-validation, SHAP
615 +# --------------------------------------------------------------------------
616 +from sklearn.model_selection import KFold, GroupKFold # noqa: E402
617 +from sklearn.linear_model import ElasticNetCV, LinearRegression # noqa: E402
618 +from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor # noqa: E402
619 +from sklearn.preprocessing import StandardScaler # noqa: E402
620 +from sklearn.pipeline import make_pipeline # noqa: E402
621 +import xgboost as xgb, lightgbm as lgb # noqa: E402
622 +
623 +XML = design(A, SPECS["M5"], fe="fe_city").drop(columns="const")
624 +XML.columns = [re.sub(r"[^0-9a-zA-Z_]", "_", c) for c in XML.columns]
625 +yv = A["lnp"].values; pv = A["price"].values
626 +blocks = KMeans(n_clusters=20, random_state=SEED, n_init=10).fit_predict(coords)
627 +KEY["ml_n_blocks"] = 20
628 +MODELS = {
629 + "OLS (M5)": lambda: LinearRegression(),
630 + "Elastic net": lambda: make_pipeline(StandardScaler(), ElasticNetCV(l1_ratio=[.1, .5, .9], cv=5, random_state=SEED, n_jobs=-1)),
631 + "Random forest": lambda: RandomForestRegressor(n_estimators=500, min_samples_leaf=3, max_features=0.5, random_state=SEED, n_jobs=-1),
632 + "Gradient boosting": lambda: GradientBoostingRegressor(n_estimators=500, learning_rate=0.05, max_depth=3, subsample=0.8, random_state=SEED),
633 + "XGBoost": lambda: xgb.XGBRegressor(n_estimators=600, learning_rate=0.03, max_depth=5, subsample=0.8, colsample_bytree=0.8, min_child_weight=3, random_state=SEED, n_jobs=-1, verbosity=0),
634 + "LightGBM": lambda: lgb.LGBMRegressor(n_estimators=600, learning_rate=0.03, num_leaves=15, min_child_samples=10, subsample=0.8, subsample_freq=1, colsample_bytree=0.8, random_state=SEED, n_jobs=-1, verbose=-1),
635 +}
636 +
637 +
638 +def cv_eval(splitter, groups=None):
639 + out = {}
640 + for name, mk in MODELS.items():
641 + yhat = np.zeros_like(yv)
642 + for tr, te in splitter.split(XML, yv, groups):
643 + m = mk(); m.fit(XML.iloc[tr], yv[tr]); yhat[te] = m.predict(XML.iloc[te])
644 + r2 = 1 - np.sum((yv - yhat) ** 2) / np.sum((yv - yv.mean()) ** 2)
645 + rmse = np.sqrt(np.mean((yv - yhat) ** 2)); mae = np.mean(np.abs(yv - yhat))
646 + mdape = np.median(np.abs(np.exp(yhat) - pv) / pv) * 100
647 + out[name] = [r2, rmse, mae, mdape]
648 + return out
649 +
650 +
651 +res_rand = cv_eval(KFold(5, shuffle=True, random_state=SEED))
652 +res_block = cv_eval(GroupKFold(5), groups=blocks)
653 +body = ["\\begin{tabular}{lrrrrrrrr}", "\\toprule", " & \\multicolumn{4}{c}{Random 5-fold CV} & \\multicolumn{4}{c}{Spatially blocked 5-fold CV} \\\\",
654 + "\\cmidrule(lr){2-5}\\cmidrule(lr){6-9}", "Model & $R^2$ & RMSE & MAE & MdAPE (\\%) & $R^2$ & RMSE & MAE & MdAPE (\\%) \\\\", "\\midrule"]
655 +for name in MODELS:
656 + a, b_ = res_rand[name], res_block[name]
657 + body.append(f"{name} & {a[0]:.3f} & {a[1]:.3f} & {a[2]:.3f} & {a[3]:.1f} & {b_[0]:.3f} & {b_[1]:.3f} & {b_[2]:.3f} & {b_[3]:.1f} \\\\")
658 +body += ["\\bottomrule", "\\end{tabular}"]
659 +write_tex("rev_ml_cv", "\n".join(body))
660 +KEY["ml"] = {"random": res_rand, "blocked": res_block}
661 +log("ML CV done")
662 +
663 +# SHAP on XGBoost fitted to the full analysis sample
664 +import shap # noqa: E402
665 +xg = MODELS["XGBoost"](); xg.fit(XML, yv)
666 +# exact TreeSHAP values computed natively by XGBoost (pred_contribs); last column is the bias term
667 +contrib = xg.get_booster().predict(xgb.DMatrix(XML), pred_contribs=True)
668 +sv = contrib[:, :-1]; KEY['shap_bias'] = float(contrib[0, -1])
669 +assert np.allclose(contrib.sum(axis=1), xg.predict(XML), atol=1e-3)
670 +imp_shap = pd.Series(np.abs(sv).mean(axis=0), index=XML.columns)
671 +fe_mask = imp_shap.index.str.startswith("fe_")
672 +imp_agg = imp_shap[~fe_mask].copy(); imp_agg["City / cell fixed effects (all)"] = imp_shap[fe_mask].sum()
673 +imp_agg = imp_agg.sort_values(ascending=False)
674 +LAB2 = {re.sub(r"[^0-9a-zA-Z_]", "_", k): v for k, v in LAB.items()}
675 +body = ["\\begin{tabular}{lrr}", "\\toprule", "Feature & Mean $|\\phi_k|$ & Share of total (\\%) \\\\", "\\midrule"]
676 +tot = imp_shap.sum()
677 +for k, v in imp_agg.head(16).items():
678 + body.append(f"{LAB2.get(k, tex_escape(k))} & {v:.4f} & {100 * v / tot:.1f} \\\\")
679 +body += ["\\bottomrule", "\\end{tabular}"]
680 +write_tex("rev_shap_importance", "\n".join(body))
681 +KEY["shap_top"] = {k: float(v) for k, v in imp_agg.head(10).items()}; KEY["shap_total"] = float(tot)
682 +KEY["shap_fe_share"] = float(imp_shap[fe_mask].sum() / tot)
683 +# beeswarm of the 12 most important non-FE features
684 +top = imp_shap[~fe_mask].sort_values(ascending=False).head(12).index
685 +Xd = XML[top].copy(); Xd.columns = [LAB2.get(c, c) for c in top]
686 +fig = plt.figure(figsize=(7, 4.6))
687 +shap.summary_plot(sv[:, [list(XML.columns).index(c) for c in top]], Xd, show=False, plot_size=None, max_display=12)
688 +plt.gcf().set_size_inches(7, 4.6); plt.xlabel("SHAP value (contribution to predicted ln price)")
689 +savefig(plt.gcf(), "rev_fig_shap")
690 +log("SHAP done")
691 +
692 +# --------------------------------------------------------------------------
693 +# 8. Robustness of the M5 specification
694 +# --------------------------------------------------------------------------
695 +RKEYS = ["ln_bedrooms", "ln_bathrooms", "ln_guests", "is_superhost", "is_guest_favorite", "ln_reviews", "rating_c", "ln_dist"]
696 +
697 +
698 +def refit(d, fe="fe_city", label=""):
699 + d = d.reset_index(drop=True)
700 + if fe == "fe_cell60":
701 + X = design(d, SPECS["M5"], fe="fe_cell60", drop_first_fe="0")
702 + else:
703 + X = design(d, SPECS["M5"], fe=fe)
704 + X = X.loc[:, (X != 0).any(axis=0)]
705 + if label.startswith("Weighted"):
706 + return sm.WLS(d["lnp"], X, weights=1 - d["p_stay"]).fit(cov_type="HC3")
707 + return sm.OLS(d["lnp"], X).fit(cov_type="HC3")
708 +
709 +
710 +def _fe(d):
711 + return d.assign(fe_city=lambda d: np.where(d.city.isin(big), d.city, "cell_" + pd.Series(km_small.predict(d[["x_km", "y_km"]].values), index=d.index).astype(str)))
712 +variants = [
713 + ("Baseline: nightly regime ($\\hat{p}_i < 0.5$)", A),
714 + ("Nightly regime, strict ($\\hat{p}_i < 0.25$)", _fe(df[df.p_stay < 0.25])),
715 + ("Nightly regime, lenient ($\\hat{p}_i < 0.75$)", _fe(df[df.p_stay < 0.75])),
716 + ("Price $\\leq$ \\$1{,}000 rule", _fe(df[df.price <= 1000])),
717 + ("Price $\\leq$ \\$600 rule", _fe(df[df.price <= 600])),
718 + ("All priced listings (bimodal)", _fe(df)),
719 + ("Excluding hotels, B\\&Bs, hostels", A[A.category != "Hotel/B&B/hostel"]),
720 + ("Rated listings only", A[A.rated == 1]),
721 + ("Montreal only", A[A.is_montreal == 1]),
722 + ("Outside Montreal", A[A.is_montreal == 0]),
723 + ("Trimmed 1\\%/99\\% within sample", A[(A.price > A.price.quantile(.01)) & (A.price < A.price.quantile(.99))]),
724 + ("Weighted by $1 - \\hat{p}_i$", A),
725 +]
726 +body = ["\\begin{tabular}{l" + "r" * (len(RKEYS) + 2) + "}", "\\toprule",
727 + "Sample / specification & " + " & ".join(["Bedr.", "Bathr.", "Guests", "Superhost", "Guest Fav.", "ln reviews", "Rating", "ln dist."]) + " & $N$ & $R^2$ \\\\", "\\midrule"]
728 +KEY["robust"] = {}
729 +for lab, d in variants:
730 + f = refit(d, label=lab)
731 + cells = [f"{f.params[v]:.3f}{stars(f.pvalues[v])}" if v in f.params.index else "" for v in RKEYS]
732 + ses = [f"({f.bse[v]:.3f})" if v in f.params.index else "" for v in RKEYS]
733 + body.append(f"{lab} & " + " & ".join(cells) + f" & {int(f.nobs):,} & {f.rsquared:.3f} \\\\")
734 + body.append(" & " + " & ".join(ses) + " & & \\\\")
735 + KEY["robust"][lab] = {"n": int(f.nobs), "r2": float(f.rsquared), **{v: [float(f.params[v]), float(f.bse[v]), float(f.pvalues[v])] for v in RKEYS if v in f.params.index}}
736 +# grid-cell FE (60 cells)
737 +f = refit(A, fe="fe_cell60")
738 +body.append("60 spatial-cell fixed effects & " + " & ".join(f"{f.params[v]:.3f}{stars(f.pvalues[v])}" for v in RKEYS) + f" & {int(f.nobs):,} & {f.rsquared:.3f} \\\\")
739 +body.append(" & " + " & ".join(f"({f.bse[v]:.3f})" for v in RKEYS) + " & & \\\\")
740 +KEY["robust"]["cell60"] = {"n": int(f.nobs), "r2": float(f.rsquared), **{v: [float(f.params[v]), float(f.bse[v]), float(f.pvalues[v])] for v in RKEYS}}
741 +# Montreal x bedrooms heterogeneity
742 +body += ["\\bottomrule", "\\end{tabular}"]
743 +write_tex("rev_robustness", "\n".join(body))
744 +log("robustness done")
745 +
746 +# --------------------------------------------------------------------------
747 +# 9. Figures: map, price by category, binned partial relationships
748 +# --------------------------------------------------------------------------
749 +fig, ax = plt.subplots(figsize=(7, 5.2))
750 +sc = ax.scatter(A["long"], A["lat"], c=A["lnp"], s=5, cmap="viridis", alpha=0.7, linewidths=0)
751 +cb = fig.colorbar(sc, ax=ax, shrink=0.8); cb.set_label("Displayed price (CAD)")
752 +tk = [50, 100, 200, 400, 800]; cb.set_ticks(np.log(tk)); cb.set_ticklabels([str(t) for t in tk])
753 +ax.set_xlabel("Longitude"); ax.set_ylabel("Latitude"); ax.set_xlim(-80, -61); ax.set_ylim(44.8, 50.5)
754 +for nmc, (la, lo) in centres.items():
755 + if nmc in ("Montréal", "Québec", "Gatineau", "Mont-Tremblant", "Sherbrooke", "Saguenay", "Rimouski"):
756 + ax.annotate(nmc, (lo, la), fontsize=7, xytext=(3, 3), textcoords="offset points")
757 +savefig(fig, "rev_fig_map")
758 +
759 +fig, ax = plt.subplots(figsize=(7, 3.8))
760 +data = [A.loc[A.category == c, "price"] for c in CATS]
761 +ax.boxplot(data, vert=False, showfliers=False, widths=0.6, medianprops={"color": "#de2d26"})
762 +ax.set_yticks(range(1, len(CATS) + 1)); ax.set_yticklabels([f"{c} (n={len(d)})" for c, d in zip(CATS, data)], fontsize=8)
763 +ax.set_xscale("log"); ax.set_xlabel("Displayed price (CAD, log scale)"); savefig(fig, "rev_fig_price_by_category")
764 +
765 +fig, axes = plt.subplots(1, 2, figsize=(9, 3.4))
766 +r4 = fits["M4"]
767 +# partial residual plots: residual + beta*x against x, binned
768 +for ax, v, xl in zip(axes, ("ln_dist", "rating_c"), ("Distance to nearest centre (km)", "Rating (rated listings)")):
769 + d = A.copy(); d["pr"] = r4.resid + r4.params[v] * d[v]
770 + if v == "rating_c":
771 + d = d[d.rated == 1]; xvar = d["rating_raw"]
772 + else:
773 + xvar = d["dist_centre_km"]
774 + bins = pd.qcut(xvar, 20, duplicates="drop"); g = d.groupby(bins, observed=True)
775 + xm = g.apply(lambda s: xvar.loc[s.index].mean()); ym = g["pr"].mean(); se = g["pr"].sem()
776 + ax.errorbar(xm, ym, yerr=1.96 * se, fmt="o", ms=3, color="#08519c", ecolor="#9ecae1")
777 + ax.set_xlabel(xl); ax.set_ylabel("Partial residual of ln(price)")
778 + if v == "ln_dist": ax.set_xscale("symlog", linthresh=1)
779 +fig.tight_layout(); savefig(fig, "rev_fig_partials")
780 +
781 +# --------------------------------------------------------------------------
782 +# 10. Save key numbers
783 +# --------------------------------------------------------------------------
784 +KEY["runtime_s"] = time.perf_counter() - T0
785 +(TAB / "rev_key_numbers.json").write_text(json.dumps(KEY, indent=1, default=float), encoding="utf-8")
786 +A.drop(columns=["name"]).to_csv(ROOT / "data" / "processed" / "analysis_sample.csv", index=False)
787 +log("done")
added scripts/11_vif_table.py +17 −0
@@ -0,0 +1,17 @@
1 +#!/usr/bin/env python3
2 +"""Write results/tables/rev_vif.tex from the VIFs stored in rev_key_numbers.json (companion of 10_revision_reanalysis.py)."""
3 +import json
4 +from pathlib import Path
5 +ROOT = Path(__file__).resolve().parent.parent
6 +k = json.loads((ROOT / "results/tables/rev_key_numbers.json").read_text())
7 +LAB = {"ln_bedrooms": "ln(bedrooms)", "ln_bathrooms": "ln(1 + bathrooms)", "ln_guests": "ln(guests)", "shared_bath": "Shared bathroom",
8 + "studio": "Studio", "ln_amenities": "ln(1 + amenities)", "pets_allowed": "Pets allowed", "ln_images": "ln(1 + photos)",
9 + "is_superhost": "Superhost", "is_guest_favorite": "Guest Favourite", "ln_reviews": "ln(1 + reviews)", "rated": "Rated (star shown)",
10 + "rating_c": "Rating $-$ 4.8 (rated only)", "ln_dist": "ln(1 + km to centre)", "ln_density_1km": "ln(1 + listings within 1 km)",
11 + "Hotel/B&B/hostel": "Hotel/B\\&B/hostel"}
12 +rows = ["\\begin{tabular}{lr}", "\\toprule", "Regressor & VIF \\\\", "\\midrule"]
13 +for v, x in k["vif"].items():
14 + rows.append(f"{LAB.get(v, v)} & {x:.2f} \\\\")
15 +rows += ["\\bottomrule", "\\end{tabular}"]
16 +(ROOT / "results/tables/rev_vif.tex").write_text("\n".join(rows))
17 +print("rev_vif.tex written; max VIF", round(k["vif_max"], 2), k["vif_argmax"])
18