Naprawdę?NAI
PLEN

Methodology · version 2.0.0 · effective July 26, 2026

How we calculate the Naprawdę Affordability Index

NAI is one number — a weighted geometric mean of four sub-indices, each rebased to 100 at 2015 Q1. Higher means more affordable. Below is the full formula, the reconciled assumptions behind it, its known limitations, and a changelog — enough for anyone to reconstruct the number by hand.

Basis

Which wage: the median, not the mean

Every wage-derived number on this site stands on the MEDIAN gross wage — half of all jobs pay less. Until version 2.0.0 it stood on the mean, while the page called it a median in several places. That was a substantive error, not a typo.

SeriesStatisticPopulationRole
P4610medianwhole national economy (ZUS)the basis of every published figure
P4609meanwhole national economy (ZUS)the comparison, published alongside
P2687meanenterprise sector (10+ employees)headline national wage (a different population)

Verified live (January 2026, by the seat of entity, total): a national median of 7,447 zł against a mean of 9,353 zł — 79.6%. Across cities it runs from 76.8% (Warsaw) to 86.2% (Katowice). That spread matters: were the ratio constant, changing basis would merely rescale every city by the same factor. It isn't — so it reorders them too.

The 2015 Q1 base has no measured median — the P4610 survey only starts in 2024. The base median is reconstructed exactly as the base mean already is (Tier B): by freezing each city's current median-to-mean ratio and carrying it back. The effect is deliberately conservative — the same factor appears in a sub-index's numerator and denominator, so the NAI level itself is close to insensitive to the basis switch, and the entire visible change lands where it should: in the numbers a human reads.

Formula

Four sub-indices

NAI(city) = Π Sᵢ ^ wᵢ — a geometric, not arithmetic, mean, so weakness in one component can't be masked by strength in another. When a component's data is missing (today: rent), its weight is dropped and the rest renormalize to sum to 1.

Sub-indexWeightFunction
Years of work for a flat0.45affordability_years()
Mortgage payment as % of pay0.35rate_adjusted_burden_pct()
Rent as % of income — outside the index's scope0.00rent_to_income_pct()
Real wage growth (cumulative)0.20nai_realwage_level()

The national figure is the population-weighted mean of every city's NAI (nai_national() in lambda_function.py). When population data isn't available yet, weights are equal instead.

Sensitivity

Does the choice of weights matter?

Each row shifts one weight by ±0.05, proportionally renormalizing the other three so they still sum to 1 — using the same illustrative Wrocław worked example (§3.5, NAI = 80.73). No single weight shift moves the result by more than 1.98 points.

Sub-index (base weight)−0.05+0.05
Years of work for a flat0.450.40 81.23up by 0.50 pts0.50 80.24down by 0.49 pts
Mortgage payment as % of pay0.350.30 81.58up by 0.85 pts0.40 79.90down by 0.83 pts
Real wage growth (cumulative)0.200.15 78.80down by 1.93 pts0.25 82.71up by 1.98 pts

This is a partial substitute for an independent economist review, not a replacement for it: it shows the result isn't fragile to reasonable, one-at-a-time weight changes, but it doesn't substitute for a public, named review of the whole methodology by an outside economist — that review hasn't happened yet.

Assumptions

Reconciled mortgage assumptions

These numbers used to disagree with the page's own copy — the code and the text now say the same thing.

Flat size
60 m²
Down payment (LTV)
10% (loan: 90%)
Loan term
25 years
Bank margin
+2.0 p.p.
Net wage
71% brutto
Wage basis
median (P4610)
Base period
2015 Q1 = 100

Limitations

What's still missing

  • No working rent data source exists yet — NBP's rent-report pages are blocked by bot protection. The index publishes without that component (flagged partial) until a source is found.
  • Real city-level wages only exist from roughly 2024 onward. Base-year (2015) wages for earlier years are reconstructed by holding each city's wage-to-national ratio constant — flagged as reconstructed, never shown as a certainty.
  • The frozen median-to-mean ratio cannot capture how the SHAPE of the wage distribution changed since 2015. If wage inequality genuinely moved, the historical span won't show it. Current readings use both real figures, so this affects only the comparison against the base.
  • The median and mean from the wage-distribution survey publish on a ~5–6 month lag — longer than the headline enterprise-sector wage. The period is printed next to each of those figures and can differ from CPI's.
  • The GUS survey's unit of observation is an EMPLOYMENT RELATIONSHIP, not a person: someone holding two contracts is counted twice. A median across employments is not the same thing as a median across people's incomes.
  • Beyond the median and the mean we have no monthly city-level deciles, so the calculator's distribution position is a lognormal fit to those two numbers — an estimate, least accurate in the tails.
  • CPI is a single basket weighted by economy-wide spending. Lower-income households have a different spending mix and typically a different lived inflation rate; GUS publishes no monthly CPI by income group, so real wage growth — on either basis — inherits that limitation.
  • The national historical series back to 2015 is annual, not quarterly, and omits the real-wage-growth and rent components — a simplification of the historical reconstruction, not of how the current value is computed.

Changelog

Version history

Newest first. Every published NAI value is stamped with the methodology version it was computed under.

v3.0.0 · 2026-07-27

  • The index's scope is now explicitly limited to BUYING, and it is named that way on the page. It was previously defined over four components, published on three, and captioned "partial index — rent data isn't available yet". That was not a data fault but a mismatch between definition and product: the page promised three things, delivered three things, then apologised for a fourth the reader had never been told about.
  • Weights: years of work 0.45, mortgage payment 0.35, real wages 0.20. Rent is weighted 0 — out of scope rather than "missing". This makes the published index complete as defined, and the partial caption is gone from the page because it stopped being true, not because it was hidden.
  • The section now leads with years of work for a 60 m² flat — a figure that needs no explanation — with the index as its summary. Added a component breakdown and a plain-language scale sentence wherever the number appears.
  • New "Renting" section: a national rent price index (Eurostat HICP, CP0411, 2015 = 100) set beside wage growth over the same period. Deliberately NOT an input to the index — it measures rent actually paid under existing tenancies, so it moves more slowly than newly advertised lets, and folding it in would overstate affordability. Published separately and labelled, it is honest and useful.
  • No city-level market-rent source was found: NBP's BaRN reports remain behind bot protection, ceny_mieszkan.xlsx carries price sheets only, and GUS/BDL publishes no market-rent series. Re-verified 2026-07-27.

v2.0.0 · 2026-07-26

  • Switched the statistical basis from the MEAN to the MEDIAN. Every wage-derived number — years of work, payment as % of pay, prices in hours of work, the "you vs. your city" comparison — is now computed on the median wage (GUS/BDL P4610) rather than the mean (P4609). The page previously said "median" while showing a mean; that was false, and this version is about that.
  • The mean doesn't disappear: it's published beside the median everywhere the median is the headline figure, plus a new "A mean is not a median" section breaking the gap down city by city.
  • The NAI value itself barely moves, and that is a result rather than a coincidence: a sub-index is a ratio against the base, and the base is reconstructed with the same frozen median-to-mean ratio, so the basis factor cancels between numerator and denominator. What changes is the numbers a human reads — not the index level.
  • Added a national median-wage series and a median-based real wage figure (median y/y minus CPI) — a different number from the mean-based one.
  • Noted that the headline "Mean gross wage" (P2687, enterprise sector) covers a different population from the city figures (P4609/P4610, the whole national economy); national comparisons now use the mean from the same survey as the median.
  • Added a distribution-position estimate to the "work it out for yourself" panel — a lognormal fit to the published median/mean pair, clearly labelled as an estimate.

v1.0.0 · 2026-07-24

  • Initial release: a weighted-geometric-mean composite (years-of-work 0.40, mortgage burden 0.30, rent-to-income 0.15, real-wage growth 0.15), base period 2015 Q1 = 100.
  • Ships without the rent sub-index — no working rent data source exists yet (see "Limitations" below); the remaining weights renormalize and the value is flagged partial.
  • National historical series back to 2015 (annual granularity, national-wage proxy for years before real city-level wages existed).
  • Reconciled the down-payment assumption (90% LTV) with the actual mortgage-payment formula — it previously financed 100% of the price despite the page's own copy already claiming 90%.

Reproducibility

Reproduce this number

Every input comes from a public, free API — nothing sits behind paid access.

Dane: GUS (BDL), NBP · Opracowanie: vedantsen.com