% ============================================================================ \section{Methodology} \label{sec:methodology} % ============================================================================ Our empirical strategy has two parts: a feature-engineering pipeline that turns raw listings into an analysis-ready design matrix (Sections~\ref{subsec:structural}--% \ref{subsec:vision}), and a hedonic regression that maps those features to price (Section~\ref{subsec:econometrics}). \subsection{Theoretical Framework} \label{subsec:theory} Following \citet{rosen1974hedonic}, a house is a bundle of $K$ characteristics $\mathbf{z}=(z_1,\dots,z_K)$, and the market clears through a hedonic price function $P(\mathbf{z})$ that equates the marginal bid of buyers to the marginal offer of sellers. A buyer with income $y$ and preferences $U(x,\mathbf{z})$ over a numéraire good $x$ and housing attributes chooses $\mathbf{z}$ to solve % \begin{equation} \max_{x,\,\mathbf{z}}\; U(x,\mathbf{z}) \quad\text{s.t.}\quad y = x + P(\mathbf{z}), \label{eq:consumer} \end{equation} % which yields the first-order condition that, at the optimum, the implicit (\emph{marginal}) price of each attribute equals the buyer's marginal willingness to pay: % \begin{equation} p_k(\mathbf{z}) \;\equiv\; \frac{\partial P(\mathbf{z})}{\partial z_k} \;=\; \frac{\partial U/\partial z_k}{\partial U/\partial x}, \qquad k = 1,\dots,K. \label{eq:implicit} \end{equation} % Equation~\eqref{eq:implicit} is the object of interest: the slope of the hedonic surface in the direction of attribute~$z_k$. The empirical task is to recover $P(\mathbf{z})$---and hence its gradient---from observed prices and characteristics. The linear model of Section~\ref{subsec:econometrics} imposes a parametric form on $P(\cdot)$ and reads the implicit prices off its coefficients; the machine-learning estimators of Section~\ref{sec:benchmark} approximate $P(\cdot)$ nonparametrically, trading the closed-form gradient for predictive flexibility. Two caveats apply throughout. The observed price is an asking price, so $P(\cdot)$ is the hedonic function of sellers' offers rather than of transactions; and the machine-generated attributes are measured with error and chosen by the seller, so their coefficients are predictive associations rather than structural marginal prices (Section~\ref{subsec:limits}). \subsection{Structural and Locational Attributes} \label{subsec:structural} Structural attributes are extracted by deterministic rules. Living area and lot area are reported in heterogeneous units (\texttt{"1535 sqft"}, \texttt{"1,333.2 ft²"}, \texttt{"11 561.52 ft²"}, \texttt{"961.6 m2"}); we parse each string and convert all areas to square feet. For Realtor.ca listings that report room-by-room dimensions (e.g.\ \texttt{"23 ft ,4 in x 13 ft ,8 in"}) but no aggregate living area, we sum the parsed room areas and calibrate the total against listings where both are observed; the median ratio of reported area to summed-room area is~0.98, so the reconstructed value is used directly to fill missing living area. Age is computed as $2026-\text{year built}$, entered together with its square to allow a non-monotone depreciation profile. Bedrooms, bathrooms, parking spaces, and storeys are taken from the attribute block. Missing values are imputed by the within-property-type median, and each imputed field is accompanied by a ``\texttt{has\_}'' indicator so that the regression can distinguish observed from imputed values. Location is captured by \textbf{municipality fixed effects}. City names are normalized (Realtor.ca appends neighbourhood qualifiers in parentheses, which we strip), and municipalities with fewer than 20 listings are pooled into a residual category, leaving 195 city effects; the pooled group of small municipalities is the omitted (reference) category, so every reported municipality effect is a premium or discount relative to a listing in a small municipality. In robustness checks we replace the municipality effects by \textbf{forward sortation area (RTA) effects}, the first three characters of the postal code, which are available for all but one listing: 419 RTAs appear in the sample, of which 250 have at least 20 listings and receive their own effect. Property-type fixed effects and a source indicator complete the locational and platform controls. \subsection{Rule-Based Amenities and Room Detail} \label{subsec:amenities} Fifteen amenity indicators are detected by bilingual (French/English) keyword matching over the concatenated feature list, description, and title: swimming pool, waterfront, garage, fireplace, central air conditioning or heat pump, finished basement, proximity to water, cul-de-sac, proximity to a golf course, ski hill, park, school, highway, and public transit, and the absence of rear neighbours. From the Realtor.ca room block we additionally construct room-detail indicators---presence of a primary bedroom, a basement, an office, a family room, a workshop, a wine cellar, a sunroom, a mezzanine, a library, and a laundry room---together with the room and storey counts. Two listing-quality signals, the number of photographs (capped at~60) and the presence of a virtual tour, proxy for the marketing tier of the listing. Finally, following the evidence of Section~\ref{subsec:text_content}, two language indicators (English, mixed; French omitted) and the description length are available as controls. \subsection{Language-Model Specifications from Text} \label{subsec:llm} Free-text descriptions contain valuation-relevant information that resists keyword extraction: whether the home is turnkey or a fixer-upper, whether the kitchen or bathroom has been renovated, the flooring and countertop materials, the heating system, the presence of a water view, and income potential. We extract these as a fixed set of structured specifications using a large language model (\texttt{gpt-4o-mini}, OpenAI, called through the Chat Completions API in July 2026) with \emph{schema-constrained decoding}: the request specifies a strict JSON schema with closed enumerations and required fields, so the API validates the output at generation time and the model returns exactly the expected fields in the expected value domains (Table~\ref{tab:app_features}). Decoding temperature is set to zero, and the system instruction, written in French, constrains the model to rely only on the text and to code absent information as \texttt{false}, \texttt{unknown}, or an empty list. Each call consumes roughly 600 input and 110 output tokens; the extraction is run in parallel, is resumable through an on-disk cache keyed by the listing identifier, and retries transient errors with exponential backoff, for a total cost of about \$3 across the sample. Descriptions are truncated at 4{,}000 characters, which affects only the longest DuProprio property sheets. \subsection{Vision Attributes from the Façade Photograph} \label{subsec:vision} To capture the visual quality that neither structured fields nor text convey, we analyze one photograph per listing---the façade---with a vision--language model (\texttt{claude-haiku-4-5}, Anthropic, Messages API, July 2026). For Realtor.ca the first image is the exterior shot; for DuProprio, whose images are captioned, we select the first image whose caption is not a room name. The model returns twelve fields under a strict JSON schema: an exterior-shot flag, a visual building type, an overall condition score (1--10), a curb-appeal score (1--10), a renovation level, the list of exterior materials, landscaping quality, a visible-garage flag, the visual storey count, the setting (dense urban, suburban, rural, waterfront, wooded), a photo-quality score, and a luxury indicator. The system instruction directs the model to ground each score in concrete criteria (surface condition, materials, landscaping) rather than taste, and to flag non-exterior images. Images are passed by URL without local download; each call consumes roughly 2{,}470 input and 100 output tokens, for a total cost of about \$57 across the sample. As with the text layer, the pass is parallelized, resumable, and retried. Unlike the text layer, the vision calls did not set a sampling temperature and therefore ran at the API default, so repeated calls could return slightly different scores for borderline images; we did not re-run the extraction to measure this test--retest variability (see Section~\ref{subsec:limits}). \paragraph{From schema fields to regressors.} Imposing a typed schema with enumerations, required fields, and \texttt{additionalProperties:false} moves validation into the API layer, so the outputs are tabulated variables that require no free-text post-processing. They are then mapped to numeric regressors: booleans to $0/1$; the six-level text condition scale to an ordinal score $0$--$5$ (\textit{to renovate} $=0$, \ldots, \textit{new} $=5$, with \textit{unknown} placed at the ``good'' midpoint of~2); the five-level visual renovation scale to $0$--$4$ and landscaping to $0$--$3$; multi-valued fields (flooring, heating, exterior materials) and the setting to one indicator per category. The twelve vision fields thus generate 21 regressors (two scores, the photo-quality score, two ordinal scales, three indicators, five setting indicators, and eight material indicators), and the text schema 18 regressors. A listing whose photograph is not an exterior shot keeps the model's best-effort scores and is flagged by the exterior indicator. Model identifiers are API aliases that resolve to the provider's current snapshot; we record the alias and the extraction date, and the raw JSON outputs are archived so that every regressor can be regenerated from them without new API calls. \subsection{Econometric Specification} \label{subsec:econometrics} We adopt a semi-logarithmic functional form, the standard workhorse in the hedonic literature \citep{malpezzi2003hedonic}. Collect the attributes of listing~$i$ into disjoint blocks, % \begin{equation} \resizebox{.94\textwidth}{!}{$\displaystyle \mathbf{X}_i = \big(\underbrace{\ln\text{Area}_i,\ \ln\text{Lot}_i}_{\text{size (logged)}},\ \underbrace{\mathbf{s}_i}_{\text{structural}},\ \underbrace{\mathbf{a}_i}_{\text{amenities}},\ \underbrace{\mathbf{r}_i}_{\text{rooms}},\ \underbrace{\mathbf{m}_i}_{\text{listing}},\ \underbrace{\mathbf{g}_i}_{\text{LLM text}},\ \underbrace{\mathbf{v}_i}_{\text{vision}}\big) $} \label{eq:blocks} \end{equation} % and estimate, by ordinary least squares, % \begin{equation} \begin{aligned} \ln P_i \;=\;& \alpha \;+\; \beta\,\ln\text{Area}_i \;+\; \gamma\,\ln\text{Lot}_i \;+\; \mathbf{s}_i^{\!\top}\bm{\delta}_s + \mathbf{a}_i^{\!\top}\bm{\delta}_a + \mathbf{r}_i^{\!\top}\bm{\delta}_r + \mathbf{m}_i^{\!\top}\bm{\delta}_m \\ &+ \underbrace{\mathbf{g}_i^{\!\top}\bm{\delta}_g}_{\text{LLM text}} + \underbrace{\mathbf{v}_i^{\!\top}\bm{\delta}_v}_{\text{vision}} \;+\; \underbrace{\mu_{c(i)}}_{\text{city FE}} \;+\; \underbrace{\tau_{t(i)}}_{\text{type FE}} \;+\; \varepsilon_i , \end{aligned} \label{eq:hedonic} \end{equation} % where $c(i)$ and $t(i)$ index the municipality and property type of listing~$i$, and $\mu_c$, $\tau_t$ are the corresponding fixed effects that sweep out location- and type-specific price levels. The source indicator is part of $\mathbf{m}_i$. In matrix form $\mathbf{y}=\mathbf{Z}\bm{\theta}+\bm{\varepsilon}$ with $\widehat{\bm{\theta}}=(\mathbf{Z}^{\!\top}\mathbf{Z})^{-1}\mathbf{Z}^{\!\top}\mathbf{y}$. The contribution of a feature layer is measured by the change in $R^2$ when its block is added to the specification that contains all preceding blocks; the order is size and structural, amenities, rooms and listing signals, text, vision, so the text layer is credited only with what the keyword amenities do not already capture, and the vision layer only with what neither the text nor the structured fields capture. \paragraph{Interpretation of the coefficients.} Because the size variables enter in logs, $\beta$ and $\gamma$ are \emph{elasticities}: $\partial \ln P/\partial \ln\text{Area}=\beta$. For an indicator regressor $d$ with coefficient $b$, the percentage price effect is not $b$ but % \begin{equation} \%\Delta P \;=\; \big(e^{\,b}-1\big)\times 100, \label{eq:halvorsen} \end{equation} % the \citet{halvorsen1980interpretation} correction we apply throughout (for small $b$, $e^{b}-1\approx b$; the \citealp{kennedy1981estimation} adjustment $e^{\,b-\frac12\widehat{\mathrm{Var}}(b)}-1$ moves none of our reported effects by more than 0.1 percentage point). For an ordinal score such as curb appeal, $b$ is the log-price difference associated with one step of the scale, holding the other attributes fixed. Under Equation~\eqref{eq:hedonic} the implicit price of a continuous attribute $z_k$ from \eqref{eq:implicit} is $p_k=\delta_k\,P/z_k$, so the semi-log form lets the \emph{dollar} marginal price scale with the price level while keeping the \emph{percentage} effect constant. \paragraph{Two-part coverage design.} Because living area is reported for only about 38\% of Realtor.ca listings, we estimate two nested versions of \eqref{eq:hedonic} and combine their predictions: % \begin{equation} \widehat{\ln P}_i = \begin{cases} \widehat{\ln P}_i^{\,A} & \text{if area is measured (Model A, rich),}\\[2pt] \widehat{\ln P}_i^{\,B} & \text{otherwise (Model B, broad; }\beta\equiv 0). \end{cases} \label{eq:twopart} \end{equation} % Model~A includes $\ln\text{Area}$ and is fit on the 9{,}446 listings with a measured or reconstructed area; Model~B drops it and is fit on the full cleaned sample, so every listing can be priced. \paragraph{Inference.} House-price residuals are strongly heteroskedastic, and listings within a municipality share unobserved local shocks that induce within-cluster error correlation. Our preferred standard errors are therefore clustered at the municipality level (195 clusters), the same level as the fixed effects \citep{cameron2015cluster,abadie2023when}: % \begin{equation} \widehat{\mathrm{Var}}_{\text{CL}}(\widehat{\bm{\theta}}) = (\mathbf{Z}^{\!\top}\mathbf{Z})^{-1} \Bigg(\sum_{c=1}^{C} \mathbf{Z}_c^{\!\top}\hat{\bm{\varepsilon}}_c \hat{\bm{\varepsilon}}_c^{\!\top}\mathbf{Z}_c\Bigg) (\mathbf{Z}^{\!\top}\mathbf{Z})^{-1}, \label{eq:cluster} \end{equation} % where $\mathbf{Z}_c$ and $\hat{\bm{\varepsilon}}_c$ stack the regressors and residuals of cluster $c$. Cluster sizes are very unequal---Montreal alone contributes about one listing in twenty, and the pooled residual category of small municipalities, which is treated as a single cluster, holds about one listing in four (5{,}006 listings from 999 municipalities)---a configuration in which the asymptotic cluster-robust variance can be unreliable \citep{mackinnon2017wild}. We therefore also report a pairs cluster bootstrap that resamples municipalities with replacement ($B=299$) and takes the 2.5th and 97.5th percentiles of the resampled coefficients as a confidence interval. As a complement we compute heteroskedasticity-consistent (HC3) standard errors \citep{white1980heteroskedasticity,mackinnon1985some}; Section~\ref{subsec:robust} shows that the three approaches agree on the significance of the property-level AI attributes and differ mainly for keyword amenities with a strong spatial component. When RTA fixed effects replace municipality effects, standard errors are clustered by RTA. \paragraph{Retransformation.} Predicting the \emph{level} of price requires undoing the log. Because $\mathbb{E}[P\mid\mathbf{Z}]=\exp(\mathbf{Z}\bm{\theta})\,\mathbb{E}[e^{\varepsilon}] \neq \exp(\mathbf{Z}\bm{\theta})$, naive exponentiation is biased downward. Under $\varepsilon\sim\mathcal N(0,\sigma^2)$ we use the closed-form correction, and more generally Duan's nonparametric smearing estimate \citep{duan1983smearing}: % \begin{equation} \widehat{P}_i = \exp\!\big(\widehat{\ln P}_i\big)\cdot \underbrace{\exp\!\big(\tfrac12\hat\sigma^{2}\big)}_{\text{normal}} \qquad\text{or}\qquad \widehat{P}_i = \exp\!\big(\widehat{\ln P}_i\big)\cdot \underbrace{\frac1n\sum_{j=1}^{n} e^{\hat\varepsilon_j}}_{\text{smearing }\hat\phi}. \label{eq:smearing} \end{equation} % The out-of-sample accuracy metrics of Section~\ref{sec:benchmark} are computed on $\ln P$ (for $R^2$) and on the ratio of predicted to actual price (for the median absolute percentage error), neither of which depends on the retransformation constant. \paragraph{Out-of-sample validation.} All predictive comparisons use five-fold cross-validation with a common seed, so that every estimator and every feature set is evaluated on identical held-out folds. Under \emph{random} folds a held-out house typically has close neighbours in the training folds, which flatters any model that can exploit spatial proximity \citep{roberts2017cross}. We therefore repeat the exercise with \emph{spatially grouped} folds, assigning entire RTAs to folds so that no held-out listing shares its RTA with a training listing; because many small municipalities consist of a single RTA, their municipality indicator is then unobserved in training and the model prices them at the reference level. The spatial design is a deliberately harsh test of how the estimators and feature layers behave for a new area; the random design corresponds to the operational use of an AVM that prices a new listing in a market it already covers.