Is the Kempen region still undervalued?
Analysing 15 years of Belgian government real-estate data to compare apartment price growth in the Kempen region against major cities.
I grew up in the Kempen, the stretch of Antwerp province roughly bounded by Turnhout, Geel, and Herentals. When I started looking at apartments a few years ago, the received wisdom was clear: buy in the Kempen while it is still affordable, because prices will catch up to the cities eventually. That sounded reasonable, but I wanted to see whether the data actually supports it.
Belgium publishes quarterly median transaction prices per municipality through Statbel, going back to 2010. That gives us about 34,000 rows covering every municipality in the country — enough to fit trend lines and compare regions properly.
The data
Belgian government real-estate data: quarterly median transaction prices per municipality since 2010, sourced from Statbel. We load the Excel export, normalise column names, and parse quarters into proper dates.
Show code
import pandas as pd
import numpy as np
from scipy.optimize import curve_fit
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
df = pd.read_excel("../data/data.xlsx", sheet_name="Per gemeente", header=[2])
df.dropna(how="all", axis=1, inplace=True)
df = df.rename(columns=column_mapping) # houses, apartments, etc.
quarter_end = {"Q1": "-03-31", "Q2": "-06-30", "Q3": "-09-30", "Q4": "-12-31"}
df["date"] = pd.to_datetime(df["jaar"].astype(str) + df["periode"].map(quarter_end))
df.set_index("date", inplace=True)
print(f"{len(df):,} rows \u00d7 {len(df.columns)} columns ({df['lokaliteit'].nunique()} municipalities, {df.index.min():%Y-Q1} to {df.index.max():%Y-Q1})") 34,465 rows × 18 columns (581 municipalities, 2010-Q1 to 2025-Q1)
For each city we fit both an exponential curve and a linear regression to quarterly median apartment prices over the full 15-year window, then compare R² scores.
Show code
def exp_func(x, a, b):
return a * np.exp(b * x)
def fit_city(city, offset=None):
cdf = df[df["lokaliteit"] == city].dropna(subset=["median_euro_apartments"])
if offset:
cdf = cdf[cdf.index >= cdf.index.max() - pd.DateOffset(years=offset)]
x = np.arange(len(cdf))
y = cdf["median_euro_apartments"].values
popt, _ = curve_fit(exp_func, x, y, p0=(y[0], 0.01), maxfev=5000)
exp_pred = exp_func(x, *popt)
lr = LinearRegression().fit(x.reshape(-1, 1), y)
lin_pred = lr.predict(x.reshape(-1, 1))
return {
"quarters": len(cdf), "latest": y[-1],
"exp_growth": (np.exp(4 * popt[1]) - 1) * 100,
"exp_r2": r2_score(y, exp_pred),
"lin_growth": (lr.coef_[0] * 4 / y[0]) * 100,
"lin_r2": r2_score(y, lin_pred),
}
cities = ["TURNHOUT", "ANTWERPEN", "GENT", "GEEL", "HERENTALS", "LEUVEN", "MECHELEN", "BRUGGE"]
results = {c.title(): fit_city(c) for c in cities}
summary = pd.DataFrame(results).T
summary | Quarters | Latest (EUR) | Exp. growth | Exp. R² | Lin. growth | Lin. R² | Better fit | |
|---|---|---|---|---|---|---|---|
| Turnhout | 61 | 237,000 | 3.13% | 0.837 | 3.63% | 0.808 | Exponential |
| Antwerpen | 61 | 246,000 | 4.91% | 0.955 | 6.26% | 0.922 | Exponential |
| Gent | 61 | 310,000 | 4.68% | 0.949 | 5.43% | 0.938 | Exponential |
| Geel | 52 | 250,000 | 4.19% | 0.883 | 5.23% | 0.882 | Exponential |
| Herentals | 42 | 255,000 | 4.81% | 0.889 | 5.68% | 0.876 | Exponential |
| Leuven | 61 | 281,000 | 3.74% | 0.908 | 4.33% | 0.890 | Exponential |
| Mechelen | 61 | 269,500 | 5.23% | 0.952 | 6.71% | 0.930 | Exponential |
| Brugge | 61 | 255,000 | 2.66% | 0.877 | 2.95% | 0.871 | Exponential |
Over the full 15-year window the exponential model wins for every city, though the margin is slim for Geel and Brugge. The key takeaway: linear growth estimates overstate yearly appreciation because they ignore compounding. Turnhout's 3.63% linear estimate drops to 3.13% under an exponential fit — a meaningful difference over a 20-year mortgage.
The summary table already tells the core story. Over the full 15-year window, the exponential model fits better than linear for every city, though the margin varies. More importantly, the growth rates diverge meaningfully: Turnhout apartments have appreciated at roughly 3.1% per year, while Antwerpen sits at 4.9% and Mechelen at 5.2%.
Growth rates across cities
Turnhout sits near the bottom of the comparison — only Brugge grew more slowly. Herentals, a Kempen neighbour just 15 km away, grew at 4.8% and now trades at a higher median than Turnhout. That is not what you would expect if the Kempen were moving as a single undervalued block.
Where prices stand today
The growth rate chart tells you how fast prices moved, but not where they ended up. A city that grew quickly from a low base may still be affordable in absolute terms.
Turnhout is the cheapest city in this comparison at EUR 237,000 — about 76% of Gent’s median. But the gap is not as dramatic as people tend to assume. The Kempen towns of Geel and Herentals have already converged with Antwerpen in absolute price terms, sitting in the EUR 250-255K range.
How prices diverged over time
The bar charts show where things stand, but the line chart shows how they got there. Notice how Antwerpen started below Turnhout in 2010 and crossed over around 2015.
Exponential vs linear: why it matters
One of the more useful findings from this analysis: linear trend models consistently overstate growth rates compared to exponential fits. For Turnhout, the linear estimate is 3.6% per year versus 3.1% exponential. That half-percent difference compounds: over a 20-year mortgage it means predicting EUR 285K instead of EUR 265K at maturity.
The exponential model wins on R-squared for every city over the full data window. Over shorter windows (five years), the two fits are nearly indistinguishable — which makes sense, since any smooth curve looks linear if you zoom in far enough. The practical takeaway: if you are projecting property values over a decade or more, use an exponential fit.
What this means for the Kempen
The “buy in the Kempen because it is cheap” narrative is partly outdated. Geel and Herentals are no longer meaningfully cheaper than Antwerpen for apartments. Turnhout remains the most affordable option, but it also has the slowest growth — meaning the gap is widening, not closing.
None of this is investment advice. Municipal medians smooth over enormous variation within a city, the data says nothing about specific neighbourhoods or property quality, and 15 years of history does not predict the next 15. But if you hear someone say the Kempen is undervalued, it is worth checking which part of the Kempen they mean.
Source code: vastgoed-analysis on GitHub.