python geohash算法逆地址编码原理初探
1、geohash有什么用途呢?
这几天刚好有个测试任务是关于设备信息位置处理的,里面提及到geohash;抱着测试的警觉性,打算研读一下这个geohash到底是什么?Geohash 是一种地理编码系统,地球上的任何一个物体可以通过经纬度来定位其在地球位置,而作为程序猿通过经纬度两个信息很难(或者说很麻烦)在数据层面上进行检索和比对,这个时候geohash编码系统出现了,更可以说geohash是一种算法可以把经纬度坐标转换为短字符串。当所有的位置信息都可以通过一个字符串代替时,大大提高了地址检索和比对的效率,通过一个字符串可以知道你的位置信息,广泛应用于定位服务和餐饮服务。同时通过字符串比对可以知道所处位置附近的地址信息。
2、python-geohash如何安装
python3安装python-geohash时一直报错无法安装,但是可以安装geohash,安装完geohash时引用模块会ImportError: No module named ‘geohash’报错,解决方法:
找到site-packages将里面的Geohash文件夹改为geohash,同时在文件夹内部的__init__文件内容改为
from .geohash import decode_exactly, decode, encode
3、geohash源码文件
这里先贴出整个geohash精简源码,预览一下
from math import log10
__base32 = '0123456789bcdefghjkmnpqrstuvwxyz'
__decodemap = { }
for i in range(len(__base32)):
__decodemap[__base32[i]] = i
del i def decode_exactly(geohash):
lat_interval, lon_interval = (-90.0, 90.0), (-180.0, 180.0)
lat_err, lon_err = 90.0, 180.0
is_even = True
for c in geohash:
cd = __decodemap[c]
for mask in [16, 8, 4, 2, 1]:
if is_even:
lon_err /= 2
if cd & mask:
lon_interval = ((lon_interval[0]+lon_interval[1])/2, lon_interval[1])
else:
lon_interval = (lon_interval[0], (lon_interval[0]+lon_interval[1])/2)
else:
lat_err /= 2
if cd & mask:
lat_interval = ((lat_interval[0]+lat_interval[1])/2, lat_interval[1])
else:
lat_interval = (lat_interval[0], (lat_interval[0]+lat_interval[1])/2)
is_even = not is_even
lat = (lat_interval[0] + lat_interval[1]) / 2
lon = (lon_interval[0] + lon_interval[1]) / 2
return lat, lon, lat_err, lon_err def decode(geohash):
lat, lon, lat_err, lon_err = decode_exactly(geohash)
lats = "%.*f" % (max(1, int(round(-log10(lat_err)))) - 1, lat)
lons = "%.*f" % (max(1, int(round(-log10(lon_err)))) - 1, lon)
if '.' in lats: lats = lats.rstrip('')
if '.' in lons: lons = lons.rstrip('')
return lats, lons def encode(latitude, longitude, precision=12):
lat_interval, lon_interval = (-90.0, 90.0), (-180.0, 180.0)
geohash = []
bits = [ 16, 8, 4, 2, 1 ]
bit = 0
ch = 0
even = True
while len(geohash) < precision:
if even:
mid = (lon_interval[0] + lon_interval[1]) / 2
if longitude > mid:
ch |= bits[bit]
lon_interval = (mid, lon_interval[1])
else:
lon_interval = (lon_interval[0], mid)
else:
mid = (lat_interval[0] + lat_interval[1]) / 2
if latitude > mid:
ch |= bits[bit]
lat_interval = (mid, lat_interval[1])
else:
lat_interval = (lat_interval[0], mid)
even = not even
if bit < 4:
bit += 1
else:
geohash += __base32[ch]
bit = 0
ch = 0
return ''.join(geohash)
整个算法通过代码的形式就只有不到100行,里面涵盖了正逆地址编码,这里主要看一下逆地址编码算法是如何实现字符串转换为经纬度的。
__base32 = '0123456789bcdefghjkmnpqrstuvwxyz'
__decodemap = { }
for i in range(len(__base32)):
__decodemap[__base32[i]] = i
del i
这段代码的主要作用就是将字符串赋予一个序号如这样,在最后将残余的i删除掉,这一步可以看出作者写代码的规范还是很好的,值得学习!
def decode_exactly(geohash):
lat_interval, lon_interval = (-90.0, 90.0), (-180.0, 180.0)
lat_err, lon_err = 90.0, 180.0
is_even = True
for c in geohash:
cd = __decodemap[c]
for mask in [16, 8, 4, 2, 1]:
if is_even:
lon_err /= 2
if cd & mask:
lon_interval = ((lon_interval[0]+lon_interval[1])/2, lon_interval[1])
else:
lon_interval = (lon_interval[0], (lon_interval[0]+lon_interval[1])/2)
else:
lat_err /= 2
if cd & mask:
lat_interval = ((lat_interval[0]+lat_interval[1])/2, lat_interval[1])
else:
lat_interval = (lat_interval[0], (lat_interval[0]+lat_interval[1])/2)
is_even = not is_even
lat = (lat_interval[0] + lat_interval[1]) / 2
lon = (lon_interval[0] + lon_interval[1]) / 2
return lat, lon, lat_err, lon_err
decode_exactly主要是将geohash解码为它的确切值,包括错误结果的边距。返回四个浮点值:纬度、经度、纬度的正负误差(为正)、经度的正负误差(为正)。
1、先遍历geohash字符串得到每一个字符对应的十进制序号。如k:18 10010
2、判断语句if is_even+mask使整个函数体默认开始是取经度信息(所以在地址编码时偶数位放经度序列奇数为放维度序列合并为二进制字符然后base32编码得到geohash,这里的偶数位是从0开始;扩展如 北京(39.928167 ,116.389550) 编码后(10111 00011 , 11010 01011) , 组码后 :11100 11101 00100 01111 , base32编码后得到最后的geohash值是wx4g)
3、然后通过cd & mask按位与运算符得到当前区间是前半部分还是后半部分(二分法)
4、mask循环体下通过is_even = not is_even实现切换经纬度信息获取机制
5、通过不断的二分规则知道不能在分得到纬度、经度、纬度的正负误差(为正)、经度的正负误差(为正)
def decode(geohash):
lat, lon, lat_err, lon_err = decode_exactly(geohash)
lats = "%.*f" % (max(1, int(round(-log10(lat_err)))) - 1, lat)
lons = "%.*f" % (max(1, int(round(-log10(lon_err)))) - 1, lon)
if '.' in lats: lats = lats.rstrip('')
if '.' in lons: lons = lons.rstrip('')
return lats, lons
这段为逆地址编码主函数,通过表达式%.*f来决定数值的精度有多少为,通过if '.' in lats: lats = lats.rstrip('0')去除尾部的数值0,及2.3000=2.3
至此逆地址源码解析完成,而地址编码其实就是反过来而已。二分法的具体示意图如下
在这段源码中我们需要得到什么呢?
1、一种二分法的使用思路,通过奇数偶数位相错的二进制组合将两个信息合成一个信息然后编码实现可观性字符串
2、通过二分法不断细分保留了所需要的精度值
3、代码精简采用了独特的is_even = not is_even和for mask in [16, 8, 4, 2, 1]来不断的切换奇偶位置
4、geohash应用讨论
1、通过geohash可以详细的知道位置信息
通过源码我们会发现在逆地址解码时存在一定的经纬度数据误差,这就导致了geohash实际表示的是一种很小的范围而不是精准的位置信息,也有助于保护隐私
2、geohash越相近、经纬度越相近
通过逆地址解码源码我们可以知道,解码时时不断的通过二分法对整个平面不断的细分为更小的平面,这就导致会出现平面右下角和平面左下角的值相近的geohash,而经纬度相距较大。
python geohash算法逆地址编码原理初探的更多相关文章
- Python源代码剖析笔记3-Python运行原理初探
Python源代码剖析笔记3-Python执行原理初探 本文简书地址:http://www.jianshu.com/p/03af86845c95 之前写了几篇源代码剖析笔记,然而慢慢觉得没有从一个宏观 ...
- SHA-256算法和区块链原理初探
组内技术分享的内容,目前网上相关资料很多,但读起来都不太合自己的习惯,于是自己整理并编写一篇简洁并便于(自己)理解和分享的文章. 因为之前对密码学没有专门研究,自己的体会或理解会特别标注为" ...
- geohash算法原理及实现方式
1.geohash特点 2.geohash原理 3.geohash的php .python.java.C#实现代码 4.观点讨论 w微博:http://weibo.com/dxl0321 geohas ...
- geohash 算法原理及实现方式
转自:http://www.cnblogs.com/dengxinglin/archive/2012/12/14/2817761.html geohash 算法原理及实现方式 1.geohash 特点 ...
- Python下探究随机数的产生原理和算法
资源下载 #本文PDF版下载 Python下探究随机数的产生原理和算法(或者单击我博客园右上角的github小标,找到lab102的W7目录下即可) #本文代码下载 几种随机数算法集合(和下文出现过的 ...
- 【python测试开发栈】带你彻底搞明白python3编码原理
在之前的文章中,我们介绍过编码格式的发展史:[文章传送门-todo].今天我们通过几个例子,来彻底搞清楚python3中的编码格式原理,这样你之后写python脚本时碰到编码问题,才能有章可循. 我们 ...
- Python动态网页爬虫-----动态网页真实地址破解原理
参考链接:Python动态网页爬虫-----动态网页真实地址破解原理
- 转发:吐血总结,彻底明白 python3 编码原理
吐血总结,彻底明白 python3 编码原理 写的不错,转发学习一下,侵删.. 原文地址https://zhuanlan.zhihu.com/p/40834093 防止原文看不到了 这里粘贴复制一下: ...
- LBS地理位置距离计算方法之geohash算法
随着移动终端的普及,很多应用都基于LBS功能,附近的某某(餐馆.银行.妹纸等等).基础数据中,一般保存了目标位置的经纬度:利用用户提供的经纬度,进行对比,从而获得是否在附近.这里需要在设置出一个字段, ...
随机推荐
- jsp页面时间的转换js
/** * 日期 转换为 Unix时间戳 * @param <string> 2014-01-01 20:2 ...
- 将训练集构建成ImageNet模型
以下程序实现将训练集构建为ImageNet模型,训练集图片为56个民族 import java.io.File; import java.io.FileNotFoundException; impor ...
- pat 1084 Broken Keyboard(20 分)
1084 Broken Keyboard(20 分) On a broken keyboard, some of the keys are worn out. So when you type som ...
- hdu 1087 Super Jumping! Jumping! Jumping!(动态规划DP)
Super Jumping! Jumping! Jumping!Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 ...
- Bootstrap——导航条(navbar)
导航条和导航从外观上差别不是太多,但在实际使用中导航条要比导航复杂得多. 导航条(navbar)中有一个背景色.而且导航条可以是纯链接(类似导航).表单以及表单和导航一起结合等多种形式. 在制作一个基 ...
- 理解MySQL数据库事务-隔离性
Transaction事务是指一个逻辑单元,执行一系列操作的SQL语句. 事务中一组的SQL语句,要么全部执行,要么全部回退.在Oracle数据库中有个名字,叫做transaction ID 在关系型 ...
- Linux\CentOS 安装 vsftpd 服务器
安装 查看电脑是否存在 vsftpd 服务器 rmp -qa|grep vsftpd 如果有就删除,没有就使用yum 安装 vsftpd yum -y install vsftpd 配置 在根目录下创 ...
- 安装win7和ubuntu16.04双系统
硬件:2012年本子 话硕A55V Service 准备: 首先通过一键还原备份win7系统!不清楚某些失误会不会备份也不能拯救! 清出100g硬盘空间,ubuntu会安装在这里 查看当前win7启 ...
- 命令序列 ; & && ||
; 从左到右依次被执行,返回最后一个命令的执行状态 & 该命令将在后台被执行,即在子bash中执行(或ctrl+z,bg, jobs,bg 命令号)(变量$!.$one.$two.$three ...
- 023.掌握Pod-Pod扩容和缩容
一 Pod的扩容和缩容 Kubernetes对Pod的扩缩容操作提供了手动和自动两种模式,手动模式通过执行kubectl scale命令或通过RESTful API对一个Deployment/RC进行 ...