如何从经纬度坐标列表获取城市、州和国家信息?

5

我有一个包含50万个经纬度坐标的列表,格式如下:

Latitude   Longitude  
42.022506  -88.168156  
41.877445  -87.723846  
29.986801  -90.166314  

我想使用Python获取每个坐标的城市、州和国家,并在新列中显示,如下所示:

Latitude   Longitude   City        State   Country
42.022506  -88.168156  Streamwood  IL      United States
41.877445  -87.723846  Chicago     IL      United States
29.986801  -90.166314  Metairie    LA      United States

有了这么大的数据集,怎样使用Python可以实现这个功能呢?我听说过Google的API、Nominatim的API和Geopy包。

如何让代码运行遍历所有行?目前我必须手动输入纬度和经度到最后一行中。

import csv 
import pandas as pd
import numpy as np
import math
from geopy.geocoders import Nominatim

input_file = "Lat-Log.csv" # file contains ID, Latitude, Longitude
output_file = "output.csv"
df = pd.read_csv(input_file) 

geolocator = Nominatim(user_agent="geoapiExercises")
def city_state_country(coord):
    location = geolocator.reverse(coord, exactly_one=True)
    address = location.raw['address']
    city = address.get('city', '')
    state = address.get('state', '')
    country = address.get('country', '')
    return city, state, country
print(city_state_country("47.470706, -99.704723"))

输出结果是 ('Bowdon', 'North Dakota', 'USA'),我想用我的列(纬度和经度)替换坐标并运行整个文档。如何将我的列输入代码以通过整个文档?

3
你是否有什么阻碍自己研究的东西?通常,StackOverflow 上的问题如果只是询问如何做某事却没有展示代码或尝试,往往会被投票降低并关闭。我认为你需要展示更多的研究/努力。否则这只是一个“我想要一些代码,请给我”的帖子。参见:Stack Overflow 用户期望进行多少研究工作? 编辑:好吧,看起来你提供了一些代码,但请解释一下你在列方面遇到的困难。 - Random Davis
输出会给我该确切位置的城市,州和国家。我必须手动将纬度和经度输入到print(city_state_country("47.470706, -99.704723"))中。我想用我的纬度和经度列替换坐标,并为每个坐标提供城市,州和国家,并将它们放入新列中。 - Nick
@Nick 好的,那么请告诉我们你需要什么具体帮助,而不是只是一般性地说出你想要实现什么。 - Random Davis
@Nick,所以你已经导入了 .csv 文件?但是你的问题中没有展示任何代码。答案可能就在这里:只需使用你存储值的变量并将它们传递给你的函数,而不是在问题中使用字符串常量。 - RufusVS
1
你是自己写的这个示例代码吗? - user2668284
显示剩余7条评论
1个回答

7
您想在每一行上运行一个函数,可以使用 apply() 实现。
有两个问题需要解决:1)您想向函数提供多个参数;2)您需要得到多个结果。
以下链接解释了如何解决这些问题: 以下是如何调整您的代码:
import pandas as pd
import io
from geopy.geocoders import Nominatim
geolocator = Nominatim(user_agent="geoapiExercises")

s = """Latitude   Longitude  
42.022506  -88.168156  
41.877445  -87.723846  
29.986801  -90.166314"""

df = pd.read_csv(io.StringIO(s), delim_whitespace=True)

def city_state_country(row):
    coord = f"{row['Latitude']}, {row['Longitude']}"
    location = geolocator.reverse(coord, exactly_one=True)
    address = location.raw['address']
    city = address.get('city', '')
    state = address.get('state', '')
    country = address.get('country', '')
    row['city'] = city
    row['state'] = state
    row['country'] = country
    return row

df = df.apply(city_state_country, axis=1)
print(df)

(我用内联定义的数据框替换了你的read_csv()调用。忽略它。对于示例来说不重要。 我这样做是为了使示例自包含。)

city_state_country() 函数针对数据框中的每一行都被调用。( axis=1 参数使得apply()按行而非列运行。) 该函数获取纬度和经度,并进行查询。然后,它修改该行以包括查询结果的信息。

这将得到以下结果:

    Latitude  Longitude     city      state        country
0  42.022506 -88.168156            Illinois  United States
1  41.877445 -87.723846  Chicago   Illinois  United States
2  29.986801 -90.166314           Louisiana  United States

与您的示例不同,但 Nominatim 似乎不会为您的两个坐标返回城市。(它称它们为城镇,而不是城市。)

1
你提供了一个非常好的解决方案来解决这种问题。然而,需要记住(对于这个特定的情况),如果你试图快速连续地发送50万个查询请求,地理定位服务(除非付费)很可能会停止工作。 - user2668284
@BrutusForcus 是的。有很多进行数十万个地理编码查询的选项,这些选项与Nominatim兼容。如果您想使用不同的提供商,则可以在构造函数中指定提供商的域,如此处所述here - Nick ODell
什么是我运行整个数据框的最佳方法?我需要用我的电子邮件地址替换“geoapiExercises”吗? - Nick
1
@Nick 我不确定你是否应该一次性运行整个数据框。Nominatim API指南建议每秒只进行1个请求。以这种速度,完成50万个请求需要超过五天的时间。如果你的互联网断开或计算机崩溃,你将不得不从头开始。你应该想出一个解决方案,可以处理一些请求,保存工作并继续,以及在崩溃后恢复。 - Nick ODell
2
@Nick,我建议你创建一个独立的职位和位置表,并仅请求唯一的职位,以便不重复请求。实际上,你应该过滤掉彼此相距几百英尺的位置,假设它们实际上在同一个城市中,因此无需请求。然后从这个查找数据库填充你的完整数据库。 - RufusVS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接