Une question, un partenariat, un accès aux données ?
Écrivez-nous directement à parcelledata@gmail.com
The product is one number: the empirical "brown discount" (décote) — what an F/G home actually sells for versus an equivalent D, computed on real transactions at local granularity, with a confidence band. This document is the provenance trail for that number: every published figure can be traced to (a) the controlled method that produced it, (b) the sample it rests on, and (c) a match set that survives the temporal/renovation checks below.
| Attribute | Value |
|---|---|
| Publisher | DGFiP via data.gouv.fr (geo-dvf) |
| Licence | Licence Ouverte 2.0 |
| URL | https://files.data.gouv.fr/geo-dvf/latest/csv/<year>/departements/<dept>.csv.gz |
| Years used | 2022–2025 |
Only residential rows (type_local ∈ {Appartement, Maison}) with surface and
price are downloaded (scripts/download_all.py).
dpe03existant)| Attribute | Value |
|---|---|
| Publisher | ADEME |
| Licence | Licence Ouverte 2.0 |
| API | https://data.ademe.fr/data-fair/api/v1/datasets/dpe03existant/lines |
| Size | ~15 M dwellings nationally |
Why v2 and not the legacy pre-2021 dpe-france dataset. An earlier
build matched 2022–2025 sales against pre-July-2021 certificates. Measured
consequences on that build: median certificate-to-sale gap of 4.2 years
(p75 = 6.1 y), 18 % of matches carrying the blank label "N", and a naive
label/price gradient that was essentially flat — maximal
renovation-in-between risk plus a label scale (pre-reform) that is not the
one the decote must measure. With v2 the median gap is 69 days (dept-69
benchmark) and 99.8 % of matches fall within 3 years.
v2 additionally provides: BAN-geocoded coordinates and address parts
(score_ban, identifiant_ban), and numero_dpe_remplace (explicit
certificate-replacement chains).
Register property (verified empirically): when a certificate is replaced, ADEME removes the replaced certificate from the open-data register (in dept 69, only 2 of 46 606 replacement targets still exist in the register). The candidate pool therefore cannot contain an officially superseded DPE. The residual renovation risk is renovations without a chained re-filing, which the S2 heuristic below addresses.
DVF publishes one row per (mutation, disposition, local) but
valeur_fonciere is the price of the whole mutation.
normalize.prepare_dvf_mutations:
nature_mutation == "Vente" only (excludes VEFA, exchanges,
adjudications);Dept-69 funnel (2022–2025): 119 056 raw rows → 111 934 Vente → 98 962 after dedup → 86 913 single-dwelling sales (3 850 multi-local mutations, 12 049 rows, excluded).
Known residual bias: a dwelling sold together with a non-residential lot (garage, cellar) filtered at download keeps the bundled price. This is trimmed by the €/m² [p01, p99] filter in §6.
Candidate pairs (blocking.py) must pass all of:
| Block | Rule |
|---|---|
| B1 | same INSEE commune |
| B2 | ≤ 50 m between DVF geocode and DPE BAN geocode (0.001° grid + 4-neighbour expansion, then exact distance) |
| B3 | DPE surface ∈ [0.70, 1.50] × DVF surface |
| B4 | DPE date ∈ [sale − 10 y, sale + 30 d] |
Blocking is deliberately permissive on time (B4); the publication window is enforced downstream (§6) so that the excluded volume is measurable.
Pair score (matching.py):
match_score = 0.30·dist + 0.35·surface + 0.15·time + 0.10·type + 0.10·address
Selection: for each sale, the most recent certificate not later than
30 days after the deed, among candidates above threshold ("take latest" —
the certificate the buyer saw); ties broken by score. A global one-to-one
assignment (Hungarian per postal block, greedy fallback) prevents one DPE
from serving several sales; contested certificates are flagged
(dpe_contested).
Per-record confidence:
match_confidence = 0.50·structural + 0.20·time_proximity + 0.30·ambiguity
ambiguity = 1 (unique candidate) else 0.5·min(1, margin/0.10) + 0.5·label_consensus
label_consensus is the share of the sale's plausible candidates that carry
the same label as the selected one — many same-building candidates that all
say "F" are harmless for the decote; a close runner-up with a different label
is the dangerous case. Tiers: HIGH ≥ 0.75, MEDIUM ≥ 0.60, LOW below.
Diagnostic columns on every record: n_candidates, score_margin,
label_consensus, dpe_contested, gap_days, dist_m, plus each score
component.
Dept-69 benchmark: 51 197 matches / 86 911 usable sales = 58.9 %; 21 % of sales have a unique candidate; median 5 candidates; 22 % contested certificates resolved by the assignment.
renovation.py)The killer confounder: DPE filed F, renovation, sale — recorded as "F sold at price X" when it was effectively a D.
| Signal | Rule | Action |
|---|---|---|
S1 flag_superseded |
matched certificate replaced (chain) on/before the sale | excluded if the label changed (in practice ~0: the register removes superseded certificates — S1 is a structural guard) |
S2 flag_later_dpe |
different certificate ≤ 20 m, same type, surface ± 10 %, dated between the matched DPE and the sale | excluded if the label changed |
S3 flag_price_outlier |
F/G sale above local p90 €/m² | reported only — overlaps with genuinely premium F/G stock; excluding it would mechanically inflate the decote |
renovation_suspect = S1 or S2 with a label change. Dept-69: 0.42 % of
matches; excluded from published aggregates. Renovations with no DPE
re-filing before the sale are undetectable case-by-case; their window is
bounded by the 3-year publication gap limit (median gap 69 days).
Applied by decote.prepare_analysis_frame, counts logged per run
(decote_funnel.json):
gap_days ∈ [−30 d, 3 years] — 3 years accepted because v2 keeps 99.8 %
of matches inside it anyway and a tighter cap mostly discards rural stock;renovation_suspect;Dept-69: 51 197 matched → 40 613 analysis rows (79 %).
Naive median(F) − median(D) measures composition (F homes are older and
more rural), not the label. Instead (decote.py):
log(€/m²) = Σ_c β_c·1[class ∈ c] + γ·controls + μ_location + ε
match_confidence;decote = exp(β) − 1. Pooled F+G is the count-weighted combination of β_F,
β_G with a delta-method CI.
Finer location FE mechanically shrink the decote (dept-69: FG −6.3 % with dept-level FE → −4.2 % with commune FE) — that shrinkage is the composition bias being removed, and is why level-mixing is never allowed in rankings.
Publication rules. A commune × type figure exists only if the cell has
≥ 80 usable sales, ≥ 10 sales in the class and in the reference D, and a
finite SE. Otherwise the lookup falls back commune → departement → national,
and says so (geo_level). Every figure carries n_sales_cell,
n_sales_classe, n_sales_ref_d and a 95 % CI. No number ships without
them.
validation.py: matches with identical house number and identical
normalised street (the "gold" set) are re-matched blind to all address
information (geometry + surface + type + date only), mirroring the
production selection rule. Disagreement estimates the wrong-certificate rate
of the geometry-driven matching regime.
Dept-69: 19 678 gold pairs (13 542 with ≥ 2 candidates):
| Metric | All gold | Ambiguous (≥2 candidates) |
|---|---|---|
| wrong certificate | 1.9 % | 2.7 % |
| wrong label | 0.20 % | 0.30 % |
Wrong-label is the harm metric for the decote (same-building errors that agree on the label do not move class coefficients). Caveats: the gold set skews toward well-addressed dwellings, and errors where the true certificate never entered the candidate set (bad geocode, surface outside the window) are not covered — that failure mode is bounded by blocking design, not measured.
| File | Content |
|---|---|
data/output/by_dept/<dept>.parquet |
matched records + all diagnostics/flags |
data/output/decote_figures.parquet |
every published figure (geo, level, type, class, effect, CI, samples, model version) |
data/output/decote_funnel.json |
filter-by-filter row counts |
data/output/decote_ranking_departements.csv / _communes.csv |
rankings, projections of the same figures |
GET /api/decote?q=<address> |
BAN-geocoded lookup → applicable decote + CI + geo_level |
GET /api/decote/ranking |
same figures, ranked |
surface_reelle_bati (gross) vs DPE habitable surface (net) differ
systematically; absorbed by the surface control, not fixed.