# Converting lat/lon to Postal code using Python

I have this DataFrame:

``````      Lat       Lon
29.39291 -98.50925
29.39923 -98.51256
29.40147 -98.51123
29.38752 -98.52372
29.39291 -98.50925
29.39537 -98.50402
29.39343 -98.49707
29.39291 -98.50925
29.39556 -98.53148
``````

I want to convert these lat/lon rows to ZIP/Postal codes (for each row), using Python.

• Not sure what your exact error/problem is, but pygeocoder hasn't seen an update in a while, maybe checkout geocoder. Note, that you need to set env variables with an API key you've created from a Google Account. I haven't tried the Bing provider, but that is also an option with geocoder.
– Ryan
Commented Mar 4, 2020 at 19:35
• I am not a dev, but am wondering if anyone has tried to add the Plus-Codes to this calculation? Plus Codes/P Codes are used by starlink for Lat Long Coordinates of a subscriber terminal. Google earth will provide P-Codes when you search a Lat/Long but looking to do this in python. Some community reported benefits to P-Codes: Every location on earth can have a mailing address The encoding of 10 characters plus “+” character is much more efficient in terms of number of bytes than latitude and longitude, which to represent the same level of specificity would need to consist of two floating point Commented Dec 2, 2022 at 15:00

You can use `geopy` and its `Nominatim` geocoder.

Here is an example using the `DataFrame` you provided:

``````import geopy
import pandas as pd

def get_zipcode(df, geolocator, lat_field, lon_field):
location = geolocator.reverse((df[lat_field], df[lon_field]))

geolocator = geopy.Nominatim(user_agent='my-application')

df = pd.DataFrame({
'Lat': [29.39291, 29.39923, 29.40147, 29.38752, 29.39291, 29.39537, 29.39343, 29.39291, 29.39556],
'Lon': [-98.50925, -98.51256, -98.51123, -98.52372, -98.50925, -98.50402, -98.49707, -98.50925, -98.53148]
})
zipcodes = df.apply(get_zipcode, axis=1, geolocator=geolocator, lat_field='Lat', lon_field='Lon')
``````
``````>>> zipcodes
0    78204
1    78204
2    78204
3    78225
4    78204
5    78204
6    78204
7    78204
8    78225
dtype: object
``````
• Thank you for the answer. I got an error of `ConfigurationError: Using Nominatim with default or sample `user_agent` "my-application" is strongly discouraged, as it violates Nominatim's ToS https://operations.osmfoundation.org/policies/nominatim/ and may possibly cause 403 and 429 HTTP errors. Please specify a custom `user_agent` with `Nominatim(user_agent="my-application")` or by overriding the default `user_agent`: `geopy.geocoders.options.default_user_agent = "my-application"`.`. Is there any update you could add here? Commented Jul 15, 2022 at 19:46

For geocoding with ArcGIS, credentials have to be provided `gis = GIS("http://www.arcgis.com", "username", "password")`.

In terms of pandas, this code should do the work (adapted from @Marcelo Villa's answer)

``````from arcgis.geocoding import reverse_geocode
from arcgis.geometry import Geometry
from arcgis.gis import GIS
import pandas as pd

gis = GIS("http://www.arcgis.com", "***", "***")

def get_zip(df, lon_field, lat_field):
location = reverse_geocode((Geometry({"x":float(df[lon_field]), "y":float(df[lat_field]), "spatialReference":{"wkid": 4326}})))

df = pd.DataFrame({
'Lat': [29.39291, 29.39923, 29.40147, 29.38752, 29.39291, 29.39537, 29.39343, 29.39291, 29.39556],
'Lon': [-98.50925, -98.51256, -98.51123, -98.52372, -98.50925, -98.50402, -98.49707, -98.50925, -98.53148]
})

zipcodes = df.apply(get_zip, axis=1, lat_field='Lat', lon_field='Lon')
``````

Probably not as smart as pandas but using Python's internal module csv and ArcGIS's API for Python Reverse Geocoding.

``````from arcgis.geocoding import reverse_geocode
from arcgis.geometry import Geometry
from arcgis.gis import GIS
import csv

gis = GIS("http://www.arcgis.com", "***", "***")

coords = [
(29.39291, -98.50925),
(29.39923, -98.51256),
(29.40147, -98.51123),
(29.38752, -98.52372),
(29.39291, -98.50925),
(29.39537, -98.50402),
(29.39343, -98.49707),
(29.39291, -98.50925),
(29.39556, -98.53148)
]

result = []

for lat, lon in coords:
pt = Geometry({
"x": float(lon),
"y": float(lat),
"spatialReference": {
"wkid": 4326
}
})
try:
result.append({'lat': lat, 'lon': lon, 'geocoded': reverse_geocode(pt)})
except:
pass

result_zip = []

for item in result:
result_item = {
'lat': item['lat'],
'lon': item['lon'],
}
result_zip.append(result_item)

keys = result_zip[0].keys()

with open('output.csv', 'w', encoding='utf8', newline='') as output_file:
dict_writer = csv.DictWriter(output_file, keys, delimiter=';', quoting=csv.QUOTE_NONE, lineterminator='\r')
dict_writer.writerows(result_zip)
``````

Output csv-file looks as following

Simplifying Marcelo's answer, using only python and geopy (No Pandas):

``````import geopy
geo_locator = geopy.Nominatim(user_agent='1234')
# Latitude, Longitude
r = geo_locator.reverse((43.509004, -79.628853))
``````geolocator = geopy.Nominatim(user_agent='1234')