# How to speed up geographic entity lookup (reverse geocoding?)?

I have a very large set of coordinates (40,000+) that I need to categorise in a hierarchy of geographic entities; region, country, administrative divisions, city. I only have the coordinates and no other information about them. My current approach - included below - is far to slow. It also suffers from not being able to select the city of the coordinate.

With

locs =
GeoPosition /@ Reverse /@ RandomPoint[#, 1] & /@
DiscretizeGraphics /@
EntityValue[Keys@Select[Normal@EntityValue[RandomEntity["City", 700], "HasPolygon",
"EntityAssociation"], Values[#] == True &],
"Polygon"] // Flatten


as the points. I have constructed the following.

ClearAll[geoEntityCode];
With[{
geoCode = {
With[{rgn = DeleteCases[Entity["GeographicRegion", "World"]]@
EntityValue["GeographicRegion", "Entities"]},
Pick[rgn, GeoWithinQ[rgn, #1]]] &
,
With[{cntry =
Flatten@EntityValue[#2, {EntityProperty["GeographicRegion",
"Countries"]}]},
Pick[cntry, GeoWithinQ[cntry, #1]]] &
,
EntityList@
,
,
With[{city =
EntityList@
Entity["City", {EntityProperty["City",
Pick[city, GeoWithinQ[city, #1]]] &
}
},
geoEntityCode[pos_GeoPosition] :=
Module[{res = ConstantArray[Missing[], 5]},
res[[1]] = First@geoCode[[1]][pos];
(res[[#]] =
Check[
First@geoCode[[#]][pos, res[[# - 1]]],
Missing[\$MessageList[[-1]]]
]
) & /@ Range[2, 5];
res
]
]


Then

geoEntityCode@First@locs


completes but takes far too long and gives a few errors on finding the city.

The odd thing is that Wolfram|Alpha finds this information exceptionally fast.

How do I improve this Entity performance and have it return the city (or nearest city)? Or should I just try and grab the information from WolframAlpha?

I think you can use GeoIdentify for this.

The following took 40 seconds on 250 random locations (the timing is internet dependent of course).

(* locs defined from code OP provided *)
Length[locs]

250

spec = "GeographicRegion" | "AdministrativeDivision1" | "AdministrativeDivision2" | "Country" | "City";
AbsoluteTiming[
ids = DeleteCases[GeoIdentify[spec, locs], Entity["GeographicRegion", "World"], {2}];
]

{39.465, Null}

Column[{First[locs], First[ids]}]


• Big fat +1! I don't know how I missed this function. It just below GeoWithinQ so I should have seen it. This most likely is the answer. Will wait a bit for the accept just in case. – Edmund Sep 24 '16 at 22:23
• Ok, glad it gave you what you wanted! – Chip Hurst Sep 25 '16 at 1:54