Skip to contents

This package geocodes from seven sources. One is the base; three more can be imported beside it or queried over the network; three are online services it falls through to. Each has a vignette of its own covering what it adds, the licence it comes with, and what goes wrong with it. This one is the map.

The seven

source vignette where it lives tier licence
National Address Repository vignette("source-nar") local, imported "nar", "nar_interpolate" StatCan Open Licence
Répertoire québécois des adresses vignette("source-rqa") local, rqa_import() "rqa" CC-BY 4.0
Road Network File vignette("source-rnf") local, rnf_import() "rnf" StatCan Open Licence
BC Address Geocoder vignette("source-bc") online "bc" OGL – British Columbia
NRCan national geolocator vignette("source-nrcan") online "nrcan" OGL – Canada
Quebec MRNF geocoder vignette("source-qc") online "qc" CC-BY 4.0
NRCan Nominatim (OpenStreetMap) vignette("source-osm") online none ODbL

Three things about that table are worth reading twice, and the rest of this vignette is those three: NAR is not one source among seven, the licence column is what decides the tier column, and the last row has no tier because of its licence rather than its quality.

NAR is the base, not a tier among others

Everything here is organized around the National Address Repository. It is what nar_connection() opens, what reverse_geocode() reads, what the gazetteer behind normalize_address() is built from, and what collect_nar() hands back. Without an imported NAR release the only working parts of this package are the four online geocoders and the rule-based half of the parser.

It is also the yardstick. Every other source here — the two local imports and the four services — has been measured against NAR, because there was nothing else national to measure against. That gives NAR’s limits a double weight: a wrong record is both a wrong answer and a wrong ruler. Read vignette("source-nar") before any of the others, and read the accuracy figures in the rest of them as disagreement with NAR rather than as error.

The tiers, in order

method names the tiers to try and the order to try them in. Each tier is offered only the rows the ones before it left without a position, so the order is the priority. geocode() defaults to c("nar", "nar_interpolate") — local, free, and conservative.

Here is a chain that names all seven, against seven addresses picked so that each finds a different way through:

addr <- c("7 Saint Andrews Gdns, Toronto, ON",
          "9999 Jasper Ave, Edmonton, AB",
          "1650 Chabanel, Montreal, QC",
          "185 Deerfield Rd, Newmarket, ON",
          "8850 University High St, Burnaby, BC",
          "1545 Maley Dr, Sudbury, ON",
          "3510 Rue Somerled, Montreal, QC")

offline <- geocode(addr, method = c("nar", "rqa", "nar_interpolate", "rnf"))
online  <- geocode(addr, method = c("nar", "rqa", "nar_interpolate", "rnf",
                                    "bc", "nrcan", "qc"))

data.frame(input = addr,
           offline = offline$match_method,
           everything = online$match_method)
#>                                  input          offline       everything
#> 1    7 Saint Andrews Gdns, Toronto, ON     nar_building     nar_building
#> 2        9999 Jasper Ave, Edmonton, AB nar_interpolated nar_interpolated
#> 3          1650 Chabanel, Montreal, QC     rqa_building     rqa_building
#> 4      185 Deerfield Rd, Newmarket, ON rnf_interpolated rnf_interpolated
#> 5 8850 University High St, Burnaby, BC             none         bc_civic
#> 6           1545 Maley Dr, Sudbury, ON    rnf_ambiguous            nrcan
#> 7      3510 Rue Somerled, Montreal, QC             none             none

Reading down the offline column: NAR has the first address; NAR does not have the second but has its neighbours, so it is interpolated; Quebec’s register has the third; the road network file has the street of the fourth and no address source does. The fifth and sixth need the network, and the last one nothing here can place — which is the honest answer and not a failure of the chain.

The sixth row is the interesting one. Three separate segments in Sudbury named Maley claim a range containing 1545, so the road network tier refuses rather than guessing — rnf_ambiguous is a decision, not a failure — and the row is passed on to the online tiers, where the geolocator places it.

What each layer is worth

Measured on the same 5,000 Corporations Canada registered-office addresses the package measures everything on:

chain coverage
"nar" alone 87.9%
+ "nar_interpolate" — the default 92.4%
+ "rnf" 94.3%

The road network file is the largest single addition, and the reason is structural: it is the only source here that reaches streets NAR does not carry at all, which is the biggest component of what NAR fails on.

The other three are measured on their own populations, because they are regional:

tier population what it adds
"rqa" 4,000 Quebec filings 88.5% → 90.1% placed; and 82.7% → 89.1% placed on a register point rather than an interpolated one
"bc" 600 BC filings roughly half the NAR failures in BC are addresses BC’s registry holds
"nrcan" the national residual 8.1% of what the offline tiers leave unplaced
"qc" 600 Quebec filings 81.0% → 83.3% — but see below

The "rqa" row is the one whose headline is in the second column. Most of what it does is not new coverage but replacing an interpolated guess with the register’s own coordinate, a median 26 m away.

And "qc" overlaps "rqa" almost entirely: they serve the same register, one online and one imported. If you have run rqa_import(), the online Quebec tier has very little left to do — which is why it never fires in the demo above. It is what you reach for when you have not.

Offline or online

This is the first practical division, and it is not the same as good or bad.

The three local sources are snapshots. They answer instantly, in bulk, with no rate limit and no network, and they are as current as the release you imported. An address newer than that release is in none of them.

The four services are live and are rate-limited. They answer one request at a time — five per second is what this package throttles to — so a chain that ends in an online tier takes as long as the number of rows that reach it. That is usually fine, because so few do: online tiers only ever see what every offline tier failed on.

Two consequences worth planning around. "nrcan" is the only tier that works before NAR has been downloaded, and the only one that covers a province a partial import does not hold. And your addresses leave the machine when an online tier runs, which is a decision to make deliberately if the address list is sensitive.

Licences decide which sources can be default tiers

Every source here is openly licensed, and that is not enough on its own — what matters is whether the licences compose, because geocode() returns one table with rows from several of them.

The Statistics Canada Open Licence, the Open Government Licence (Canada, and British Columbia) and CC-BY 4.0 are all attribution licences. They compose: mixing them obliges you to attribute each, and nothing more. Six of the seven sources here are in that group, which is why all six are tiers.

OpenStreetMap data is ODbL, which is attribution plus share-alike, and the share-alike obligation attaches to a derived database. Folding a handful of ODbL rows into a result table changes what the caller may do with the whole of it. So osm_geocode() is exported and is deliberately not a tier: reaching for it is an explicit call, and the service’s own licence string rides along on every row as osm_licence. That decision is about the licence and not about the accuracy, which has never been measured — see vignette("source-osm").

The two CC-BY sources need their attribution discharged, and there is a function for it:

rqa_attribution()
#> [1] "Contains information licensed under CC-BY 4.0 from the Repertoire quebecois des adresses, Ministere des Ressources naturelles et des Forets, Gouvernement du Quebec."

Only one source can check NAR, and only in one province

It is tempting to read agreement between two sources as confirmation. Mostly it is not, because these sources are not independent of each other.

Quebec’s register is where NAR’s Quebec rows come from: over 2.5 million paired addresses the two agree to a median of 21 cm. That is lineage, not accuracy, and it means neither "rqa" nor "qc" can tell you whether a NAR Quebec point is right. There is no second opinion available for Quebec inside this package.

The BC Address Geocoder is the closest thing to an exception. It is a parcel-level provincial authority rather than a compilation, and where it and NAR disagree BC’s answer is the more reliable of the two — which is what bc_validate() is for. Even there the independence is partial: on a quarter of addresses the two agree to within 1.6 m, which is not two readings converging.

g <- geocode(c("20460 Douglas Cres, Langley, BC", "1188 Bidwell St, Vancouver, BC"),
             method = c("nar", "nar_interpolate"))

bc_validate(g) |>
  select(input, match_method, bc_match_method, bc_precision, bc_dist_m)
#>                             input match_method bc_match_method bc_precision  bc_dist_m
#> 1 20460 Douglas Cres, Langley, BC nar_building        bc_civic CIVIC_NUMBER 16.4159747
#> 2  1188 Bidwell St, Vancouver, BC nar_building        bc_civic CIVIC_NUMBER  0.2946784

Validate rows an offline tier placed. Re-asking BC about a row the "bc" tier itself answered returns the same point by construction, and a bc_dist_m of zero that means nothing.

qc_validate() is the Quebec counterpart and works the same way — with the caveat above about what its small distances mean.

Reverse geocoding is local, with one exception

reverse_geocode() reads NAR and nothing else, which makes it fast and offline. Of the four services here only Quebec’s does reverse at all: qc_reverse_geocode() is the one online reverse geocoder in the package. BC’s, NRCan’s and Nominatim’s bindings are forward only — that was probed rather than assumed.

uncertainty_m is not one thing

Read the column with the source in mind. uncertainty_m is defined as the error this package adds relative to NAR’s own building point, so a 0 means “nothing was added”, not “this point is exact” — and it says nothing about NAR’s own error.

Beyond that, the numbers have three different provenances:

  • Measured. The NAR and road network tiers. 176 m for a blockface point is the p90 building-to-blockface separation over 1.85 million addresses that carry both; the interpolation figure comes from an error/span ratio that turns out to be scale-invariant; the road network tier’s max(95, 0.35 × len_m) covers the true distance 91.8% of the time.
  • Assigned. The bc_*, nrcan and qc_* figures. Those services publish a precision vocabulary and no distances, so the metres are deliberately pessimistic order-of-magnitude translations. They are a ranking safe to filter on, not an error bar comparable to the NAR tiers’.
  • Absent. NA for the weaker RQA classes and for every osm row, because nothing has measured what they are worth and a plausible invented constant would be indistinguishable in the output from the two kinds above.

Where to go next

Start with vignette("source-nar"), since everything else is measured against it. Then read the vignette for whichever source you are about to turn on.

Each of them ends with a pointer to the note it is drawn from. The notes ship with the package and carry the full measurements, the failure modes that have not been fixed, and what to do next:

list.files(system.file("notes", package = "cangeocode"))