In de Basisregistratie Adressen en Gebouwen (BAG) beheert het Kadaster alle adressen die in Nederland voorkomen. In de BAG wordt bij een adres ook de postcode van PostNL vastgelegd, en dus moet het mogelijk zijn om o.b.v. de BAG een postcodetabel van Nederland samen te stellen.
Een ontwikkelaar kan deze postcodetabel vervolgens in zijn eigen software gebruiken, of als product of service aanbieden tegen een veel lagere prijs dan PostNL er voor vraagt.
Wat moeten we doen om op deze manier een postcodetabel samen te stellen? En hoe betrouwbaar is deze postcodetabel dan? Dit artikel geeft het antwoord en beschrijft een techniek waarmee we een postcodetabel kunnen samenstellen die maximaal overeenkomt met de postcodetabel van PostNL. We doorlopen daarbij de volgende stappen:
- Definitie van de postcodetabel
- Documentatie van de BAG
- De bronbestanden
- Inlezen en analyseren van de gegevens
- Eerste poging: de BAG-postcodetabel
- De 4-cijferige postcodetabel
- De PostNL-postcodetabel
Noot: in de BAG worden geen postbussen bijgehouden, deze blijven hier dus buiten beschouwing.
Bij dit artikel hoort een openbare Power BI app waar de (tussen)resultaten te vinden zijn. In het vervolg zal ik regelmatig verwijzen naar één van de acht rapportpagina’s van deze app.
Test
Als je een site wilt testen die adres- en postcodediensten aanbiedt probeer dan eens de volgende postcode/huisnummer combinaties:
Postcode | Plaatsnaam volgens de BAG | Plaatsnaam volgens PostNL |
1521NE 61 | Westknollendam | Wormerveer |
1541LZ 15 | Zaandijk | Koog aan de Zaan |
1541NZ 84 | Zaandam | Koog aan de Zaan |
3471BS 5 | Woerden | Kamerik |
3471HC 100 | Zegveld | Kamerik |
9207HC 1 | Drachten-Azeven | Drachten |
Een service die de plaatsnaam volgens de BAG retourneert is dus geen 100% betrouwbaar alternatief voor de officiële postcodetabel van PostNL. Dat betekent overigens niet dat deze service in het geheel niet meer betrouwbaar is. In het volgende licht ik toe hoe het zit, en laat ik zien hoe het beter kan.
Stap 1: Definitie Postcodetabel
We definiëren de volledige postcodetabel als elke mogelijke combinatie van postcode, huisnummer, huisletter, huisnummertoevoeging, straatnaam en plaatsnaam. De eerste van meer dan 9 miljoen regels zien er als volgt uit:
De verdichte postcodetabel definiëren we als elke mogelijke combinatie van postcode, straatnaam en plaatsnaam, uitgebreid met de waarden kleinste huisnummer, grootste huisnummer, en aantal objecten. Dit zijn de eerste van meer dan 468.000 regels:
Beide tabellen kunnen we gebruiken om een volledig adres te bepalen wanneer postcode, huisnummer, huisletter en toevoeging gegeven zijn. M.b.v. de volledige postcodetabel kunnen we bovendien controleren of het gegeven huisnummer en de combinatie met huisletter en toevoeging juist is. Met de verdichte postcodetabel kunnen we alleen controleren of het huisnummer in het juiste bereik ligt.
Overigens, bij één postcode kunnen tot maximaal zes verschillende straatnamen voorkomen. Postcode 1060NN is hierbij topscorer.
Merk op dat de combinatie postcode en huisnummer voldoende is om de juiste straat en plaats te identificeren. Dit is altijd het geval, en een uniek kenmerk van het Nederlandse postcode systeem.
Stap 2: De BAG leren kennen
De officiële systeembeschrijving van de BAG is de Catalogus BAG 2018, zoals vastgesteld door de minister van Binnenlandse Zaken en Koninkrijksrelaties op 29 maart 2018. Bij deze systeembeschrijving is door het Kadaster een ondersteunende Praktijkhandleiding BAG gepubliceerd. Beide documenten zijn toegankelijk via GitHub en gepubliceerd onder de licentie Creative Commons Naamsvermelding-GeenAfgeleideWerken 3.0 Nederland.
Conceptueel model
Hoofdstuk 5 van de Catalogus beschrijft het conceptueel model van de BAG m.b.v. het volgende schema:
Onze postcodetabel is feitelijk een verzameling van alle adressen in de BAG met een postcode. Volgens de Praktijkhandleiding wordt een adres “bepaald door de naam van de openbare ruimte, het huisnummer, een eventuele huisletter en huisnummertoevoeging en de woonplaats”. Voor de postcodetabel kunnen we ons dus beperken tot de objecttypen Woonplaats (WPL), Openbare ruimte (OPR) en Nummeraanduiding (NUM). De overige objecttypen in het conceptueel model kunnen we negeren.
De gangbare route om een adres met postcode te bepalen is: bepaal bij het NUM-object (met postcode) de straatnaam van het gerelateerde OPR-object, en bepaal de plaatsnaam van het aan dat OPR-object gerelateerde WPL-object. Op deze gangbare route is echter een uitzondering mogelijk.
De optionele relatie “ligt in” tussen NUM en WPL
In de Praktijkhandleiding BAG is een artikel gewijd aan de vraag: “Hoe wordt het in de BAG geregistreerd als een verblijfsobject in een andere woonplaats of gemeente ligt dan de bijbehorende openbare ruimte?”
Zie onderstaande afbeelding. De Voorbeeldstraat ligt in Westdorp, maar de bijbehorende objecten 1, 3 en 5 liggen in Oostdorp (met opritten die uitkomen op de Voorbeeldstraat). In deze situatie moet de optionele relatie tussen woonplaats en nummeraanduiding toegepast worden.
Zo komen we volgens de gangbare route tot de adressen Voorbeeldstraat 2/4/6 in Westdorp, en via de optionele route tot Voorbeeldstraat 1/3/5 in Oostdorp. De BAG kent in deze context maar één Voorbeeldstraat, en die ligt in Westdorp. Zie het artikel in de Praktijkhandleiding voor meer informatie over deze optionele relatie.
Als een NUM object een relatie heeft met een WPL-object dan bepaalt deze relatie de woonplaats; als een NUM object geen optionele relatie heeft met een WPL-object dan wordt de woonplaats bepaald via het OPR-object. De straatnaam van een NUM-object wordt altijd via het OPR-object bepaald.
In de BAG bevinden zich circa 1.700 relevante NUM-objecten met de optionele relatie naar WPL.
De geldigheid van objecten
In de BAG wordt de historie van alle objecten bijgehouden. Telkens als (een attribuut van) een object wijzigt, wordt bij de laatste gegevens van dat object een datum einde geldigheid opgenomen. Gelijktijdig wordt een nieuw voorkomen van hetzelfde object in de BAG opgenomen (met een datum begin geldigheid die gelijk is aan de datum einde geldigheid van het vorige voorkomen). Zo ontstaat historie die precies op elkaar aansluit.
Bij het inlezen van de BAG-bestanden beperken we ons tot de geldige objecten.
De status van objecten
Elk object heeft een status. De objecttypen NUM en OPR kunnen uitgegeven of ingetrokken zijn, en een WPL-object is aangewezen of ingetrokken. Zie ook dit artikel in de Praktijkhandleiding, waarin de vraag wordt beantwoord: “Als ik alle actuele gegevens opvraag in de BAG, krijg ik ook alle ingetrokken verblijfsobjecten, straten en adressen te zien. Hoe kan dit?”. Verderop kom ik hier op terug.
Stap 3: De bronbestanden voorbereiden
De gebruikte bronbestanden zijn van het BAG Extract 2.0 van 1 april 2020 die het Kadaster via Github en Dropbox beschikbaar stelde. Dit is een levering per gemeente bestaande uit 355 zip-archieven. Uitgepakt gaat het om een kleine 100 GB aan Xml gegevens in 10.427 bestanden.
Voor ons doeleinde kunnen we volstaan met het verwerken van de objecttypen WPL, OPR en NUM. Enkele kengetallen per objecttype staan in de volgende tabel:
WPL | OPR | NUM | Totaal | |
Aantal bestanden | 355 | 358 | 1.820 | 2.533 |
Aantal objecten | 3.525 | 335.347 | 11.439.839 | 11.778.711 |
Aantal geldige objecten | 2.623 | 285.683 | 9.838.667 | 10.126.973 |
Aantal duplicaten | 3 | 74 | 1.706 | 1.783 |
Enkele opmerkingen:
- Elk Xml-bestand bevat uitsluitend gegevens van één objecttype en van één gemeente.
- NUM-bestanden bevatten maximaal 7.000 objecten, OPR-bestanden maximaal 6.500. Bij grotere gemeenten worden de objecten zo nodig over meerdere bestanden verdeeld die dan een volgnummer krijgen. Om deze reden tellen de typen OPR en NUM meer dan 355 bestanden.
- De betekenis van het aantal duplicaten wordt verderop toegelicht.
Voor dit artikel zijn uitsluitend de 10.126.973 geldige objecten verwerkt.
Voor de verwerking van de gegevens is gebruik gemaakt van Power BI Desktop. Echter, met de gangbare technieken is Power Query niet goed in staat om zoveel en zulke omvangrijke Xml-bestanden te verwerken. Om deze reden zijn met een VB/Sax reader alle Xml-bestanden één-op-één geconverteerd naar een csv formaat, waarbij alleen de geldige objecten en relevante kenmerken zijn overgenomen. Power BI Desktop is dan goed in staat om de 10,1 miljoen geldige objecten m.b.v. Power Query in het datamodel te laden.
Het resultaat is hier te vinden in de vorm van de openbare Power Bi app BAG Postcodes.
Rapportpagina Bestanden geeft een gedetailleerd overzicht van alle verwerkte Xml bestanden.
Stap 4: de ingelezen gegevens analyseren
Duplicaten
Door alleen geldige objecten te verwerken was de verwachting dat elk object nog maar één keer zou voorkomen. Dat bleek niet het geval. De volgende tabel geeft een overzicht van de Woonplaatsen die twee of meer keren voorkomen:
De verklaring voor Smilde en Nes is dat als een woonplaats de status ingetrokken krijgt deze geldig blijft. Smilde behoorde ooit tot de gemeente Assen en kwam bij een herindeling onder de gemeente Midden-Drenthe; dat verklaart de Smilde regel ”ingetrokken Assen”. Vervolgens is de plaatscode van Smilde gewijzigd van 2457 in 3021, waardoor 2457 Smilde opnieuw werd ingetrokken, en 3021 Smilde (niet in de tabel) werd opgevoerd met status aangewezen. Er zijn in de WPL-tabel dus drie geldige rijen met woonplaats Smilde, waarvan twee met status ingetrokken.
De verklaring voor Nes is vergelijkbaar, hier is de code gewijzigd van 2531 Nes Heerenveen naar 3603 Nes Heerenveen.
Dat woonplaats 1519 Muiderberg zowel in de gemeenten 1942 Gooise Meren als in 1945 Berg en Dal de status aangewezen heeft is een fout in deze levering van het BAG Extract 2.0. Dit is door het Kadaster bevestigd en ongetwijfeld in een latere levering gecorrigeerd. De levering van 1 april 2020 is inmiddels verwijderd.
Ook de OPR-tabel bevat een aantal (72) duplicaten. Deze worden allemaal veroorzaakt door de dubbele woonplaats Muiderberg. Hetzelfde geldt voor de 1637 dubbele NUM-objecten.
Conclusies: (1) een levering van het BAG extract kan fouten bevatten, al zal dat zeer uitzonderlijk zijn; (2) we moeten de ingelezen geldige objecten ook controleren op status, die mag niet de waarde ingetrokken hebben.
Statusconflicten
Om het adres bij een postcode te bepalen moet elk geldig en actueel NUM object verwijzen naar:
- een geldig en actueel OPR object; en
- een geldig en actueel WPL object (ongeacht de route waarlangs deze bereikt wordt).
In deze levering blijken er NUM-objecten te zijn die niet voldoen aan deze voorwaarden. Een overzicht kan verkregen worden door op rapportpagina Nummers te filteren op Status = Uitgegeven en vervolgens wplNaam oplopend te sorteren:
De meeste NUM-objecten die niet aan de voorwaarden voldoen maken gebruik van de optionele relatie tussen NUM en WPL, wat te zien is aan de gevulde kolom numWplId. De woonplaats id’s 1041 (Hellendoorn), 1042 (Nijverdal) en 2869 (Nijkerk) zijn alle drie ingetrokken. Blijkbaar is het mogelijk om een woonplaats in te trekken terwijl er door NUM-objecten nog naar verwezen wordt. Er is dan sprake van een Statusconflict nummeraanduiding – woonplaats (CNW).
Tot slot zijn er in Tabel 7 twee NUM-objecten met postcode 8152AV. Toen ik op 15 juni 2020 in de BAG Viewer zocht op 8152AV 5 kreeg ik dit als resultaat:
Blijkbaar is het in het BAG systeem mogelijk om een OPR object (580 Industriestraat) de status ingetrokken te geven en de gerelateerde NUM objecten actueel te laten. Er is dan sprake van een Statusconflict nummeraanduiding – openbare ruimte (CNO).
We merken nog op dat op 15 juni 2020 Google Maps nog niet bekend was met alle wijzigingen in deze omgeving. En ook PostNL liep op 15 juni nog achter op de BAG: |
Conclusie: het kan in de BAG voorkomen dat een NUM object met postcode verwijst naar een ingetrokken OPR-object, of naar een ingetrokken WPL-object via de optionele relatie. Dat maakt het NUM-object voor onze postcode tabel onbruikbaar. Dit geldt ook als een OPR-object bij een NUM-object verwijst naar een ingetrokken woonplaats.
Stap 5: De BAG-postcodetabel
We kunnen nu een eerste versie van de volledige postcodetabel maken. De 9.838.667 ingelezen geldige NUM-objecten vormen hiervoor de basis, zie rapportpagina Nummers. Onbruikbaar zijn:
- 493.246 ingetrokken objecten,
- 207.606 objecten zonder postcode, straatnaam of woonplaats,
- 1.706 duplicaten,
Als we de NUM tabel filteren op deze condities dan blijven er 9.165.078 bruikbare NUM-objecten over. Dit noemen we de volledige postcodetabel.
Op basis van deze volledige postcodetabel kunnen we nu ook de verdichte postcodetabel samenstellen, zie rapportpagina BAG-postcodes. Deze tabel is gebaseerd op een groepering van de volledige postcodetabel op postcode, woonplaats en straatnaam, met aggregaties Min en Max op huisnummer, en Sum op Count. Enkele kengetallen:
- Aantal regels: 468.301
- Aantal unieke postcodes: 460.902
- Aantal unieke woonplaats Id’s: 2.500
- Aantal unieke woonplaats namen: 2.424.
Onder de streep is het aantal objecten nog steeds 9.165.078.
Stap 6: De postcode4-tabel
Volgens het Convenant inzake postcodes is “de Postcode gebaseerd op de indeling van het land naar woonplaatsen, waarbij een woonplaats een uniek gegeven is waaraan een unieke 4-cijferige postcode kan worden toegekend.” (artikel 2.4). Dit wordt ook wel het Woonplaatsbeginsel genoemd.
Een 4-cijferige postcode (hier verder afgekort tot pc4) kan dus niet naar twee of meer woonplaatsen verwijzen. Andersom kan wel: een woonplaats kan naar meerdere pc4’s verwijzen. Dit beginsel biedt een mogelijkheid om onze postcodetabel op kwaliteit te controleren.
Rapportpagina Postcode4 toont de pc4-tabel op basis van de BAG, met een groepering op de eerste vier posities van de postcode in combinatie met de woonplaats Id, en met de aggregatie Sum op ObjectCount.
Deze pc4-tabel telt 4.185 regels en 4.070 unieke 4-cijferige postcodes. Dat deze waarden verschillen betekent dat er regels voorkomen met dezelfde 4-cijferige postcode maar met een andere woonplaats. De BAG-gegevens voldoen dus blijkbaar niet aan het woonplaatsbeginsel. Dit vraagt om een nadere analyse.
Onderstaande tabel toont alle regels in de pc4-tabel waarvan de 4-cijferige postcode drie keer voorkomt (Pc4Freq = 3).
Wat opvalt is dat bijvoorbeeld in de groep 1541 de plaats Koog aan de Zaan veel meer NUM-objecten telt (5.463) dan de plaatsen Zaandam (1) en Zaandijk (4). Wellicht zijn de vijf objecten van Zaandam en Zaandijk een vergissing, misschien is er een goede reden voor dat deze afwijken. Hoe dan ook, als bij pc4 1541 maar één plaatsnaam hoort dan mogen we wel veronderstellen dat dat Koog aan de Zaan is. We kunnen dat bij PostNL.nl controleren, bijvoorbeeld aan de hand van de postcodes 1541LZ nummer 15 en 1541NZ nummer 84. En inderdaad, beide retourneren Koog aan de Zaan als woonplaats.
Zo bepalen we van elke pc4 groep de regel met het grootste aantal objecten, en markeren die in de kolom IsMaxRow. Door vervolgens de pc4-tabel hierop te filteren verkrijgen we een nieuwe pc4-tabel waarin elke 4-cijferige postcode precies één keer voorkomt, en dus maar naar één woonplaats wijst. Er blijven dan 4.070 regels over, met 4.070 unieke pc4’s.
Als extra controle heb ik dit resultaat vergeleken met de pc4-tabel van het CBS uit 2018, die 4.066 regels telt. Bij het CBS ontbreken de pc4 1364, 5722, 6391 en 6625. Pc4 5722 is een nieuwe wijk in Asten en was destijds bij het CBS onbekend. De andere drie pc4’s zijn waarschijnlijk te gering in omvang voor CBS doeleinden. Sorteer de pc4-tabel maar oplopend op ObjectCount, en het resultaat zal niet verrassen. Hoe dan ook, we mogen concluderen dat onze pc4-tabel betrouwbaar is. |
Met de vernieuwde pc4-tabel kunnen we nu de BAG-postcodetabel verbeteren. Maar eerst is er nog een mysterie op te lossen.
De 13 verdwenen woonplaatsen
Het aantal unieke wplid’s in de vernieuwde pc4-tabel blijkt nu 2.487, dat zijn er 13 minder dan de verwachte 2.500 op basis van de BAG-postcodetabel. Het aantal unieke woonplaatsnamen is met 1 verminderd, van 2.424 naar 2.423. Hoe is dat te verklaren?
De volgende tabel toont de 26 pc4 regels waar de 13 vervallen wplid’s in voorkomen. Het zijn 13 paren van dezelfde pc4 met verschillende wplId’s.
De 13 regels met IsMaxRow = False komen in de nieuwe Pc4-tabel te vervallen. En omdat de bijbehorende wplId niet meer voorkomt bij een andere pc4 verdwijnen deze 13 wplId’s helemaal uit de pc4-tabel. De bijbehorende naam blijft echter wel bestaan, op Drachten-Azeven na.
Drachten-Azeven
Drachten is de hoofdplaats van de gemeente Smallingerland. Het dorp Drachten-Azeven grenst aan Drachten maar behoort tot de gemeente Opsterland. Het is een bedrijventerrein met 43 verblijfsobjecten zonder inwoners in een hoek van het kruispunt A7 en N381. Ondanks de geringe omvang is Drachten-Azeven voor de BAG een aparte woonplaats, met Id 3344.
Volgens de BAG horen de postcodes 9207HA t/m 9207HG bij Drachten-Azeven. In de vernieuwde pc4-tabel komt de plaatsnaam Drachten-Azeven te vervallen en krijgt iedere postcode beginnend met 9207 de plaats Drachten toegewezen. Dat blijkt volledig in overeenstemming met de postcodetabel van PostNL, die bij geen enkele postcode de plaats Drachten-Azeven toewijst.
Drachten-Azeven is de enige plaatsnaam die in de nieuwe pc4-tabel vervalt. Het klopt dus dat het aantal unieke woonplaatsnamen in de nieuwe pc4 tabel met 1 is verminderd, van 2.424 naar 2.423.
In de overige 12 vervallen woonplaats id’s is de situatie vergelijkbaar met Drachten-Azeven, met dien verstande dat alleen bij Drachten-Azeven de plaatsnamen bij de pc4 verschillend zijn. In alle situaties is het zo dat door een gemeentelijke herindeling een klein deel van een plaats onder een andere gemeente komt te vallen. Voor de BAG wordt de “afsplitsing” een zelfstandige woonplaats, met een eigen plaatscode, maar (meestal) met dezelfde naam. Zie scenario 3a op de pagina Gemeentelijke herindeling en gemeentegrenswijzigingen van de Praktijkhandleiding BAG.
Stap 7: De PostNL-postcodetabel
Om de BAG-postcodetabel zoveel mogelijk te laten lijken op de postcodetabel van PostNL moeten we de woonplaats bij elke postcode vervangen door de overeenkomende woonplaats uit de vernieuwde pc4 tabel. Bijvoorbeeld: bij alle postcodes die beginnen met 9207 wordt de plaatsnaam vervangen door Drachten. Of: bij alle postcodes die beginnen met 1541 wordt de plaatsnaam vervangen door Koog aan de Zaan. Rapportpagina PostNL-postcodes laat het resultaat zien. Volgens verwachting zijn er in deze tabel nog 2.487 unieke woonplaats Id’s en 2.423 unieke woonplaatsnamen. De overige kengetallen zijn ongewijzigd: in deze postcodetabel o.b.v. de BAG-levering van 1 april 2020 zijn er 468.201 postcode/straat/plaats combinaties, met 460.902 unieke postcodes.
Conclusie
Met voldoende kennis van de BAG is het goed mogelijk om uit de BAG een postcodetabel af te leiden: de BAG-postcodetabel. Hierbij moet rekening gehouden worden met enkele bijzondere situaties die in dit artikel zijn beschreven.
We hebben gezien dat de BAG-postcodetabel op een aantal punten afwijkt van de officiële postcodetabel van PostNL. De BAG en PostNL hebben allebei hun eigen waarheid. Door de juiste manipulatie – waarbij het woonplaatsbeginsel een belangrijke rol speelt – kunnen we de BAG-postcodetabel transformeren naar de PostNL-postcodetabel. De verwachting is dat deze PostNL-postcodetabel goeddeels overeenkomt met de officiële postcodetabel van PostNL. Maar 100% zeker zullen we nooit zijn.
Naschrift
Het Kadaster liet weten dat in samenwerking met PostNL de kwaliteit van de postcodes op maandelijkse basis wordt geanalyseerd en teruggekoppeld aan gemeenten via het kwaliteitsdashboard. De afbeelding hieronder geeft een impressie van een dashboard.