如何用Python实现地理位置和经纬度坐标之间的转换 ,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
做地图可视化时需要提供经纬度坐标,但一般来说我们手上拿到的通常只有地理位置,比如说 北京市东大街302号狗不理包子店,可视化之前需经纬度坐标转换
需要转换的数据如果仅有几个还好,可以直接借助谷歌地图自带经纬度查询手动转换,但真实场景下需要转换的数据量可能要上百甚至上千,再手动的话就比较头疼了
如何将地理位置批量转化为经纬度坐标?将针对这个问题,介绍两个用 Python 来实现的方法
最常见办法就是调用第三方 API,例如百度、高德地图等服务平台,提供了相应的功能接口,它们的这类技术已经非常成熟啦,准确稳定,关键还是免费的 ~,本期教程以百度为例(高德的用方类似),介绍一下其用法
百度地图开放平台
登录控制台之后,选择左侧 应用管理-> 我的应用 -> 创建应用
创建应用页面中有三项信息需要填写
应用名称,无限制随意填写即可;
应用类型 ,选择服务端;
IP 白名单,只是个人简单测试的话0.0.0.0/0 即可,如果考虑安全问题, 可以将自己的 IP 填进去, AK 参数泄露的话非本机 IP 无法访问,这样也不用担心额度被其他用户盗用
经纬度地理位置根据转换方向分为两类,接下来我们分别演示一下其用法:
地理编码:将地理地址转换为坐标点(经纬度);
逆地理编码,将经纬度转化为地理地址;
1.3.1 地理编码,
下面就是 Python 测试代码块,将 AK 参数(前面申请到的)和你需要转换的地理位置拼接到 官方提供的 url 中,用 requests 访问即可,
import requests import json import re AK = '你的AK' address ='北京市海淀区上地十街10号' url = 'http://api.map.baidu.com/geocoding/v3/?address={}&output=json&ak={}&callback=showLocation'.format(address,AK) res = requests.get(url) print(res.text) results = json.loads(re.findall(r'\((.*?)\)',res.text)[0]) print('\n') print('location is ',results['result']['location'])
输出结果如下
showLocation&&showLocation({"status":0,"result":{"location":{"lng":116.3084202915042,"lat":40.05703033345938},"precise":1,"confidence":80,"comprehension":100,"level":"门址"}}) location is {'lng': 116.3084202915042, 'lat': 40.05703033345938}
1.3.2 逆地理编码
逆地理编与地理编码用法相似
lat = '40.05703033345938' lng = '116.3084202915042' AK = '你的AK' url = 'http://api.map.baidu.com/reverse_geocoding/v3/?ak={}&output=json&coordtype=wgs84ll&location={},{}'.format(AK,lat,lng) res = requests.get(url) print(res.text) address = json.loads(res.text)['result']['formatted_address'] print('\n') print('address is ',address)
像我们这类免(bai) 费 piao) 用户,借助百度 API 每天最高可调用 6000 次,这个量级基本上能满足我们日常需要,但如果这个数量满足不了你的话,可以在线购买更高的使用额度
2.1 Geopy 库介绍
这里介绍一个Python 包 Geopy ,借助它也可以实现经纬度地理位置转换,
这款包之经纬度转换原理其实还是借助了第三方 API 平台,因为市面上提供经纬度转换 第三方平台很多,为了方便, Geopy 把这些接口都分别封装在一个类中,借助 Geopy 模块来调用,支持的第三放平台如下
Geopy作为一个专注于地理处理包之外, 除了能实现上面地理编码、逆地理编码功能之外,还有一个其它令我经验的功能, 提供两个经纬度坐标,计算他们在地球上的最短距离
下面将介绍一下 Geopy 的具体用法,
2. 2 地理编码
使用 地理编码功能时,需要借助 Geopy 的 geocoders 模块,Geopy 把所有第三方API封装到 geocoders 中
这里选用 OpenStreetMap 平台上提供的 Nominatim 地理编码器,因为可以免费供我们使用,不需要申请 API ,但缺点是限流,限额,不能大规模频繁访问,否则会返回 403,429错误代码
from geopy.geocoders import Nominatim geolocator=Nominatim() location= geolocator.geocode("北京市海淀区西二旗北路") print(location.address) print(location.latitude,location.longitude)
结果如下
西二旗北路, 东北旺村, 海淀区, 北京市, 102208, 中国 40.056793 116.305811
2.3 逆地理编码
from geopy.geocoders import Nominatim geolocator=Nominatim() location= geolocator.reverse("40.056793 116.305811") print(location.address)
结果如下
1#, 西二旗北路, 东北旺村, 海淀区, 北京市, 102208, 中国
结果看起来还不错,简单方便;但提醒一下,因为前面说过 Nominatim 模块是限额度的,不要频繁访问,否则会出现以下错误
2.4 根据经纬度计算距离
Geopy 最让我惊喜的是这个用法,提供两个经纬度坐标计算他们之间的距离,因为地球具体来说是椭圆,所以不能按照常规方法来计算 ,目前现有比较流行的几个模型有以下几个
model major (km) minor (km) flattening 'WGS-84': (6378.137, 6356.7523142, 1 / 298.257223563), 'GRS-80': (6378.137, 6356.7523141, 1 / 298.257222101), 'Airy (1830)': (6377.563396, 6356.256909, 1 / 299.3249646), 'Intl 1924': (6378.388, 6356.911946, 1 / 297.0), 'Clarke (1880)': (6378.249145, 6356.51486955, 1 / 293.465), 'GRS-67': (6378.1600, 6356.774719, 1 / 298.25), }
根据官方介绍,官网选择的是 WGS-84 模型,根据统计最终计算到的距离误差最高在0.5%左右;使用方法如下
from geopy import distance newport_ri = (41.49008, -71.312796) cleveland_oh = (41.499498, -81.695391) print(distance.distance(newport_ri, cleveland_oh).miles)#最后以英里单位输出 #output 538.39044536 wellington = (-41.32, 174.81) salamanca = (40.96, -5.50) print(distance.distance(wellington, salamanca).km)# 以 km 作为单位输出 19959.6792674
上面聊了这么多知识点,下面引入一个案例来简单回顾一下;本案例中借助百度API 来实现地理位置坐标转换,把一个 csv 表格内的所有地址位置数据批量转换为经纬度
3.1 数据读取
import pandas as pd import string data_path = 'H:/Data/Latlon/map-location.csv' df = pd.read_csv(data_path,encoding='GB18030') df
一共有 98 条数据,每条数据都表示一个地理位置;数据明显有一些扰乱项,例如左端的数字字符、以及数据中的分隔符\t;因此转换之前需要对数据进行一次预处理操作
3.2 数据预处理
def process_str(x): # 数据预处理,去掉前面的数字、及字符串中 \t x = str(x).replace('\t','') x = str(x).strip(string.digits) return x df['location'] = df['location'].apply(process_str) df
预处理结果如下
3.3 地理编码(经纬度转换)
import time start = time.time() AK = '你的AK' def get_location(str1): # 获取经纬度坐标 url = 'http://api.map.baidu.com/geocoding/v3/?address={}&output=json&ak={}&callback=showLocation'.format(str1,AK) res = requests.get(url) results = json.loads(re.findall(r'\((.*?)\)',res.text)[0]) return (results['result']['location']['lat'],results['result']['location']['lng']) df['(lat,lng)'] = df['location'].apply(get_location) print('耗时 {}s'.format(time.time()-start)) print(df)
为了测试转换效率,这里我加了一个计时器;98 条数据成功转换后共耗时 4.65s 左右,效率还不错,要比 Geopy 优秀得多,
3.5 案例源码数据
我已经把本案例中用到代码的数据打包再一起了,感兴趣的可以在公号后台回复关键字:210418 ,即可获取!
上面介绍了这么多,最后做个小结;聊一下这两种方法在 地理坐标转换方面 各自的优势和劣势
第三方API
优势:地理编码、逆编码比较准确,精度高;且支持高并发;
劣势:不支持国外,环境配置较为复杂;
Geopy (用 Nominatim 模块的话)
优势:简单方便,上手快;支持国外地理编码
劣势:不支持并发访问、效率低且精度较低;
这里给大家一个建议,如果地址数据在国内的话 经纬度转换 建议用第三方 API,稳定且准确;若是涉及下纬度距离计算、单位换算或地址数据在国外,建议用 Geopy
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注亿速云行业资讯频道,感谢您对亿速云的支持。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。