% Author: Simon-Pierre Boucher — contact@spboucher.ai
% ============================================================================
\section{The horse race}
\label{sec:results}

Table~\ref{tab:race_random} reports the full scoreboard under the random
holdout (411{,}283 training sales, 102{,}929 test sales);
Table~\ref{tab:race_temporal} repeats it under the forward-in-time split.
Figures~\ref{fig:forms}--\ref{fig:methods} visualize each axis.

\begin{table}[p]
\centering
\begin{threeparttable}
\caption{The scoreboard, random 80/20 holdout}
\label{tab:race_random}
\small
\input{../results/tables/horserace_random}
\begin{tablenotes}[flushleft]\footnotesize
\item \textit{Notes:} All metrics on the held-out 20\% (102{,}929 sales).
MdAPE/MAPE: median/mean absolute percentage error on price levels (log
models retransformed with Duan smearing; Box--Cox inverted).
RMSE$_{\ln}$ and $R^2_{\ln}$: computed on log predicted vs.\ log actual
prices. Backbone rows repeat across axes by construction (A5 $=$ B3 $=$
C2; B4 $=$ D1). Bold: best in axis.
\end{tablenotes}
\end{threeparttable}
\end{table}

\begin{table}[p]
\centering
\begin{threeparttable}
\caption{The scoreboard, forward-in-time holdout}
\label{tab:race_temporal}
\small
\input{../results/tables/horserace_temporal}
\begin{tablenotes}[flushleft]\footnotesize
\item \textit{Notes:} Training on sales before January 2025 (355{,}824);
testing on 2025--2026 (158{,}388). Unseen time categories are priced at
the last training period (carry-forward); the machine-learning models
receive the same information through the clamped month counter.
\end{tablenotes}
\end{threeparttable}
\end{table}

\subsection{Axis A: functional form is second-order}

Under the random split (Figure~\ref{fig:forms}), the six forms span
16.5--18.6\% MdAPE. The spline specification wins (16.5\%), the log-log
is second (17.0\%) --- floor area enters multiplicatively, as intuition
suggests --- and the linear, semi-log and quadratic forms cluster within
half a point of each other. The Box--Cox transformation selects
$\hat\lambda = 0.25$ by profile likelihood (Table~\ref{tab:boxcox}), i.e.\
the data reject both the linear ($\lambda=1$) and the log ($\lambda=0$)
--- and then \emph{underperforms} the simple semi-log out of sample
(18.6\%), because optimizing curvature in-sample does not survive
prediction, precisely the warning of \citet{cassel1985cost} and
\citet{cropper1988choice}. The ordering is preserved under the temporal
split. Two free lessons: curvature in \emph{attributes} (splines) is
worth more than curvature in the \emph{price} (Box--Cox); and no form
choice moves the needle by more than two points.

\begin{figure}[t]
\centering
\includegraphics[width=0.85\textwidth]{fig_forms.png}
\caption{Axis A --- functional form. MdAPE on the random holdout;
municipality and quarter fixed effects and the base attribute set held
fixed throughout.}
\label{fig:forms}
\end{figure}

\begin{table}[t]
\centering
\begin{threeparttable}
\caption{Box--Cox profile likelihood}
\label{tab:boxcox}
\small
\input{../results/tables/boxcox}
\begin{tablenotes}[flushleft]\footnotesize
\item \textit{Notes:} $^{\dagger}$Thousands, relative to the maximum
(zero = chosen $\lambda$). Estimated on the random-split training sample
with the A-axis design.
\end{tablenotes}
\end{threeparttable}
\end{table}

\subsection{Axis B: time controls --- anything beats nothing}

Omitting time controls entirely costs three points (21.1\% versus 18.1\%)
in a window containing a boom, a correction and a recovery
(Figure~\ref{fig:time}). But the granularity ladder flattens immediately:
year, quarter and month effects are indistinguishable to within a quarter
point under the random split. Under the temporal split the ordering
inverts at the bottom --- \emph{no} time effects (25.4\%) is the worst
choice again, but month effects with carry-forward (20.3\%) beat quarter
effects (20.5\%) only marginally: once the level must be extrapolated,
fine within-sample time resolution has little to offer.

\begin{figure}[t]
\centering
\includegraphics[width=0.85\textwidth]{fig_time.png}
\caption{Axis B --- time effects (quadratic semi-log backbone,
municipality FE). MdAPE on the random holdout.}
\label{fig:time}
\end{figure}

\subsection{Axis C: spatial controls are first-order --- up to a point}

Location dominates every other design margin
(Figure~\ref{fig:space}). Stripping all spatial controls costs
\emph{ten} points (27.9\% versus 17.5\%) --- five times the entire
functional-form range. The granularity ladder, however, is
non-monotonic: the $\sim$5.5~km grid (5{,}255 cells, 17.5\%) beats
municipality effects (18.1\%), but the $\sim$1.1~km grid (30{,}548
cells, 19.4\%) \emph{overfits} --- its cells average seventeen K sales
each, unseen cells in the holdout revert to the baseline, and estimated
effects are noisy. The optimal spatial resolution is an interior
solution, echoing \citet{goodman1998housing} on submarket definition:
finer is better only while cells remain thick enough to estimate.

\begin{figure}[t]
\centering
\includegraphics[width=0.85\textwidth]{fig_space.png}
\caption{Axis C --- spatial controls (quadratic semi-log backbone,
quarter FE). MdAPE on the random holdout.}
\label{fig:space}
\end{figure}

\subsection{Axis D: the machines --- and what they actually buy}

Under the random split (Figure~\ref{fig:methods}), gradient boosting
posts 14.4\% and the random forest 14.6\%, against 16.5\% for the best
linear model and 18.3\% for the textbook OLS: a 13--21\% error
reduction, squarely in the range reported by the AVM literature
\citep{mayer2019estimation, hong2020machine}. The decomposition rows
identify the source. Boosting \emph{without coordinates} collapses to
23.2\% --- worse than plain OLS with municipality dummies --- so the
machine's edge is overwhelmingly a flexible surface over space, not
exotic structure--attribute interactions. Pure proximity without
structure (the $k$-NN comparables rule, 21.2\%) fails too: it is the
\emph{combination} of spatial flexibility with attribute adjustment that
wins. The cross-validated ridge (16.7\%) confirms that regularizing the
high-dimensional dummy design buys a little; it cannot manufacture the
missing interactions.

\begin{figure}[t]
\centering
\includegraphics[width=0.85\textwidth]{fig_methods.png}
\caption{Axis D --- estimation methods on the identical attribute set.
MdAPE on the random holdout.}
\label{fig:methods}
\end{figure}

\subsection{The generalization gap: when the test set is the future}

Table~\ref{tab:generalization} and Figure~\ref{fig:generalization}
contain the paper's central result. Moving from the random to the
forward-in-time split degrades every model --- the price level of
2025--26 must be carried forward, not interpolated --- but the
degradation is systematically larger for the flexible methods.
Gradient boosting loses 6.8 points of MdAPE (14.4 $\to$ 21.2) and the
random forest 6.7, while the spline hedonic loses 2.6 (16.5 $\to$ 19.1)
and the log-log 2.2. The ranking \emph{reverses}: the best linear models
beat the machines on the median error in the deployment scenario, and
tie them exactly on $R^2_{\ln}$ ($\approx 0.52$). The machines remain
better on MAPE (29.7 versus 30.5), i.e.\ in the tails, but the headline
random-validation gap --- the number the ML-valuation literature
reports --- overstates their deployable advantage entirely. The lesson
is methodological and general: for models whose job is to price the
future, random cross-validation is the wrong experiment
\citep{mullainathan2017machine, clapp2002predicting}.

\begin{table}[t]
\centering
\begin{threeparttable}
\caption{Random versus forward-in-time evaluation}
\label{tab:generalization}
\small
\input{../results/tables/generalization}
\begin{tablenotes}[flushleft]\footnotesize
\item \textit{Notes:} Selected models (the backbone and the full D axis)
under both splits.
\end{tablenotes}
\end{threeparttable}
\end{table}

\begin{figure}[t]
\centering
\includegraphics[width=0.85\textwidth]{fig_generalization.png}
\caption{The generalization gap. MdAPE under the random holdout (filled
circles) and the forward-in-time holdout (open squares); the grey
segment joins the two evaluations of the same model.}
\label{fig:generalization}
\end{figure}
