Get address using Latitude and Longitude from two columns in DataFrame?

Question:

I have a dataframe with the longitude column and latitude column. When I try to get the address using geolocator.reverse() I get the error ValueError: Must be a coordinate pair or Point

I can’t for the life of me insert the lat and long into the reverse function without getting that error. I tried creating a tuple using list(zip(zips['Store_latitude'], zips['Store_longitude'])) but I get the same error.

Code:

import pandas as pd

from geopy.geocoders import Nominatim

from decimal import Decimal

from geopy.point import Point

zips = pd.read_excel("zips.xlsx")

geolocator = Nominatim(user_agent="geoapiExercises")


zips['Store_latitude']= zips['Store_latitude'].astype(str)

zips['Store_longitude'] = zips['Store_longitude'].astype(str)

zips['Location'] = list(zip(zips['Store_latitude'], zips['Store_longitude']))

zips['Address'] = geolocator.reverse(zips['Location'])

What my DataFrame looks like

Store_latitude Store_longitude
34.2262225 -118.4508349
34.017667 -118.149135
Asked By: Andres Green

||

Answers:

I think you might try with a tuple or a geopy.point.Point before going to a list to see whether the package works all right.

I tested just now as follows (Python 3.9.13, command line style)

import geopy
p  = geopy.point.Point(51.4,3.45)
gl = geopy.geocoders.Nominatim(user_agent="my_test") # Without the user_agent it raises a ConfigurationError.
gl.reverse(p)

output:
Location(Vlissingen, Zeeland, Nederland, (51.49433865, 3.415005767601362, 0.0))

This is as expected.

Maybe you should cast your dataframe[‘Store_latitude’] and dataframe[‘Store_longitude’] before/after you convert to list? They are not strings?

More information on your dataframe and content would be required to further assist, I think.
Good luck!

EDIT: added information after OP’s comments below.

  1. When you read your excel file as zips = pd.read("yourexcel.xlsx") you will get a pandas dataframe.

The content of the dataframe is two columns (which will be of type Series) and each element will be a numpy.float64 (if your excel has real values as input and not strings!). You can check this using the type() command:

>>> type(zips)
<class 'pandas.core.frame.DataFrame'>
>>> type(zips['Lat'])
<class 'pandas.core.series.Series'>
>>> type(zips['Lat'][0])
<class 'numpy.float64'>

What you then do is convert these floats (=decimal numbers) to a string (=text) by performing zips[...] = zips[...].astype(str). There is no reason to do that, because your geolocator requires numbers, not text.

  1. As shown in the comment by @Derek, you need to iterate over each row and while doing so, you can put the resulting Locations you receive from the geolocator in a new column.

So in the next block, I first create a new (empty) list. Then i iterate over couples of lat,lon by combining your zips[‘Lat’] and zips[‘lon’] using the zip command (so the naming of zips is a bit unlucky if you don’t know the zip command; it thus may be confusing you). But don’t worry, what it does is just combining the entries of each row in the varables lat and lon. Within the for-each loop, I append the result of the geolocator lookup. Note that the argument of the reverse command is a tuple (lat,lon), so the complete syntax is reverse( (lat,lon) ). Instead of (lat,lon), you could also have created a Point as in my original example. But that is not necessary imo. (note: for brevity I just write ‘Lat’ and ‘Lon’ instead of your Store…).
Finally, assign the result list as a new column in your zip pandas dataframe.

import geopy as gp
# instiate a geolocator
gl = gp.geocoders.Nominatim(user_agent="my_test")

locations = []    # Create empty list

# For loop over each couple of lat, lon
for lat,lon in zip(zips['Lat'], zips['Lon']):
    locations.append(gl.reverse((lat,lon))

# Add extra column to your pandas table (address will be the column name)
zips = zips.assign(address=locations) 

One thing you still may want, is just have the text string instead of the complete geopy.Location() string in your table.
To get that you write the for loop with this small modification ([0] as the first element of the Location object). Note that this won’t work if the result of the lookup of a given row is empty (None). Then the [0] will raise an error.

# For loop over each couple of lat, lon
for lat,lon in zip(zips['Lat'], zips['Lon']:
    locations.append(gl.reverse((lat,lon)[0])

I hope this gets you going!

Answered By: Darter
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.