Can You Geocode a Census?
A table lands in your pipeline. One column of addresses typed by humans over the years, free text: "Flat 2, 14 Station Rd." "Rte 3 Box 12-B." "Old fire hall, Main Street." Somebody important wants a map by Monday, and your map will be exactly as good as whatever the geocoder does with those strings.
At census scale, or permit-file scale, or customer-list scale, geocoding is an ingestion problem, and ingestion problems get solved with validation loops rather than with a better vendor. The loop has four stages. Each one exists because the stage before it exposed a failure, and the last one is staffed by humans because it should be.
Geocoding fails in four checkable ways
Every one of these has a signature you can detect in code, which is the good news hiding inside the bad news.
Rural addresses often don't exist as numbers anywhere. A rural route box is a real address for the mail carrier and a dead end for any gazetteer built from dwelling points: "Rte 3, Box 12" resolves to nothing, correctly. Open registries inherit the same shape; OpenStreetMap's address coverage is dense in cities and thin in open country, a pattern that follows population density rather than any cartographic policy. The result is a coverage gap that looks, from inside a city office, like random noise in the data.
Ambiguity is the failure that feels most unfair, because the geocoder did its job. Two streets called Station Road in one town are not a hypothetical, it is the most common way a confident match goes quietly wrong. The input mentions "Station Road", some gazetteer contains two of them kilometers apart, and the match lands on the one the sender didn't mean. There is a correct-looking coordinate for a wrong place sitting at the top of the candidate list.
Formatting noise is the boring one, and it is also where whole rows vanish. Units and floor designations ride along in the string. Accents and street-type synonyms vary (Street against St., avenue against Av.). Postal codes disagree with municipal names, and PO boxes are deliverable by definition and located by nothing.
Confidence values lie less than you'd hope, and more than you can afford. Every source returns a score, and people read the score as a verdict when it is only a ranking hint. We have seen a 0.9 hit the wrong Station Road while a 0.6 turned out to be a correct street with one transposed digit, fixable by a fifteen-second glance. Scores also mean different things across sources, so a threshold that worked on one dataset is uncalibrated on the next.
| Failure | What it looks like | Detection |
|---|---|---|
| Rural gap | No candidate within any plausible distance | Reverse check returns a sparse neighborhood |
| Ambiguity | Two close-named candidates far apart | Candidate spread, measured in meters |
| Formatting noise | String edits away from every candidate | Match distance above threshold after normalization |
| Overstated confidence | High score, wrong place | Second independent source disagrees |
The loop: geocode, then disagree with yourself on purpose
Geocode first, and store all candidates rather than the top hit. Where the jurisdiction allows, run a second source and keep both answers; the US Census Bureau's geocoder, for example, takes address batches of up to 10,000 rows per call for US addresses. Candidates are cheap and the reverse-check needs them.
Reverse-check next. Reverse geocode the chosen point and compare what comes back against what went in. This single step catches the confident wrong match better than any string metric, because the wrong Station Road reverse-resolves to a neighborhood the input string never mentioned.
Here we owe you a dead end. Our first attempt ranked candidates with string similarity, the tool that was already on the shelf. It failed in a specific way: the review queue filled with tight string matches pointed at the wrong street, while genuinely correct matches with sloppy input typing got flagged. String closeness predicted how close the strings were, which is precisely what it measures. Disagreement between independent sources predicted actual error much better, so the queue got re-sorted by disagreement, large discrepancies first, and the human hours finally landed on the rows that mattered.
Boundary and fallback come third. Check each matched point against the polygon you already trust: a parcel or block boundary, a municipality limit. When a registry holds a polygon for the property but no point, snap to the polygon centroid and label the row as polygon-level truth rather than pretending otherwise. Keep the three truth levels visibly separate in your output: point-level, interpolated, and polygon-level. A map that renders them identically is lying by omission, and the lie surfaces the first time somebody queries a single pixel and builds a decision on it.
Everything still ambiguous goes to the human queue, sorted by disagreement. Both leading candidates appear on a small map with the input string beside them. With a decent interface a reviewer closes rows in well under a minute, and the queue stays bounded because it holds only the residual.
One definitional mercy, if your table really is a census of people: most statistical agencies publish nothing at that granularity, for good reason. Individual US census returns stay sealed for 72 years by law. What you are almost always holding is a census of premises: dwellings, businesses, parcels. Premises have addresses that their owners publish. Confirm which census you have before explaining the map to anybody.
Open data before licenses
Open sources win this problem class for reasons that have nothing to do with price. Re-running next quarter costs nothing, the same source returns the same answer, and every row has an audit trail back to a query you can reproduce. OpenStreetMap, national gazetteers such as the USGS's GNIS, and open address registries carry most of the weight. France's Base Adresse Nationale publishes geolocated addresses for the whole country under an open license. OpenAddresses aggregates hundreds of millions of address points from public sources worldwide. The tradeoff is honest: openness costs you coverage at the sparse rural edge, which is exactly the gap you were trying to fill. The compensation is that disagreement between two open sources is itself signal. Where OSM and a national registry agree, the row is probably right; where only one does, the row has a name on it in the queue.
Attribution obligations come along with the data, and they are real: ODbL terms attach to derived databases built on OpenStreetMap, and each registry carries its own license with its own wording about what you must display. Budget an hour to read them. It is the cheapest hour in the project.
What no dataset can fix
Some rows cannot be matched because the address does not exist as a point anywhere. Rural route boxes, informal descriptions, buildings that went up after every registry last refreshed: the queue does not go to zero, and it never will, no matter which sources you stack. The failure mode to avoid is pretending it does, which is what a matched-rate percentage without its residual printed beside it actually is.
So print the residual. Next to the legend, same font size, an honest count of what the loop matched, what it verified, what it could only place at polygon level, and what it left for humans. Before you ship, you should be able to produce all four numbers from the pipeline itself. If you can't, what you have built is a picture, not a map.
A geocode is a claim. Validation is what turns it into evidence.
AngoraTek builds data pipelines for geospatial work, including the boring ingestion parts. If addresses and polygons are your week, this is our kind of problem.Thanks for reading this far. If this sounds like the problem you're wrestling with, tell us about it. A principal reads every message.
Start a conversation