Python – 低效的空间距离计算(如何加速)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Python – 低效的空间距离计算(如何加速),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含3656字,纯文字阅读大概需要6分钟。
内容图文
![Python – 低效的空间距离计算(如何加速)](/upload/InfoBanner/zyjiaocheng/811/0b2e118b862049399d779cb4755f314c.jpg)
我目前正在尝试使用Python进行一些地理编码.过程如下:我有两个数据框(df1和df2,房屋和学校),具有纬度和经度值,并希望在df2中找到df1中每个观测值的最近邻居.我使用以下代码:
from tqdm import tqdm
import numpy as np
import pandas as pd
import math
def distance(lat1, long1, lat2, long2):
R = 6371 # Earth Radius in Km
dLat = math.radians(lat2 - lat1) # Convert Degrees 2 Radians
dLong = math.radians(long2 - long1)
lat1 = math.radians(lat1)
lat2 = math.radians(lat2)
a = math.sin(dLat/2) * math.sin(dLat/2) + math.sin(dLong/2) * math.sin(dLong/2) * math.cos(lat1) * math.cos(lat2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = R * c
return d
dists = []
schools =[]
for index, row1 in tqdm(df1.iterrows()):
for index, row2 in df2.iterrows():
dists.append(distance(row1.lat, row1.lng, row2.Latitude, row2.Longitude))
schools.append(min(dists))
del dists [:]
df1["school"] = pd.Series(schools)
代码有效,但需要很长时间.使用tqdm,我得到平均速度为每秒df1的2次迭代.作为比较,我使用geonear在STATA中完成了整个任务,并且在df1(950)中所有观察需要1秒.我在geonear的帮助文件中读到他们使用聚类,不计算所有距离,而只计算最接近的距离.但是,在我添加一个集群功能(也可能需要CPU功率)之前,我想知道是否有人看到了一些方法来加快进程的速度(我是python的新手,并且可能有一些低效的代码会降低进程的速度) .或者是否有一个包可以更快地完成这个过程?
如果它比STATA需要更长的时间我会好的,但不会接近7分钟……
先感谢您
解决方法:
你这样做的方式很慢,因为你使用的是O(n²)算法:每一行都会查看每一行. Georgy’s answer虽然引入了矢量化,但并未解决这种基本的低效问题.
我建议将数据点加载到kd-tree:这种数据结构提供了一种快速查找多维度最近邻居的方法.这种树的构造在O(n log n)中,并且查询采用O(log n),因此总时间在O(n log n)中.
如果您的数据已本地化为可以通过平面很好地逼近的地理区域,则投影数据,然后在两个维度中执行查找.否则,如果您的数据是全局分散的,请投影到spherical cartesian coordinates并在那里执行查找.
您可以如何执行此操作的示例如下所示:
#/usr/bin/env python3
import numpy as np
import scipy as sp
import scipy.spatial
Rearth = 6371
#Generate uniformly-distributed lon-lat points on a sphere
#See: http://mathworld.wolfram.com/SpherePointPicking.html
def GenerateUniformSpherical(num):
#Generate random variates
pts = np.random.uniform(low=0, high=1, size=(num,2))
#Convert to sphere space
pts[:,0] = 2*np.pi*pts[:,0] #0-360 degrees
pts[:,1] = np.arccos(2*pts[:,1]-1) #0-180 degrees
#Convert to degrees
pts = np.degrees(pts)
#Shift ranges to lon-lat
pts[:,0] -= 180
pts[:,1] -= 90
return pts
def ConvertToXYZ(lonlat):
theta = np.radians(lonlat[:,0])+np.pi
phi = np.radians(lonlat[:,1])+np.pi/2
x = Rearth*np.cos(theta)*np.sin(phi)
y = Rearth*np.sin(theta)*np.sin(phi)
z = Rearth*np.cos(phi)
return np.transpose(np.vstack((x,y,z)))
#For each entry in qpts, find the nearest point in the kdtree
def GetNearestNeighbours(qpts,kdtree):
pts3d = ConvertToXYZ(qpts)
#See: https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.spatial.KDTree.query.html#scipy.spatial.KDTree.query
#p=2 implies Euclidean distance, eps=0 implies no approximation (slower)
return kdtree.query(pts3d,p=2,eps=0)
#Generate uniformly-distributed test points on a sphere. Note that you'll want
#to find a way to extract your pandas columns into an array of width=2, height=N
#to match this format.
df1 = GenerateUniformSpherical(10000)
df2 = GenerateUniformSpherical(10000)
#Convert df2 into XYZ coordinates. WARNING! Do not alter df2_3d or kdtree will
#malfunction!
df2_3d = ConvertToXYZ(df2)
#Build a kd-tree from df2_3D
kdtree = sp.spatial.KDTree(df2_3d, leafsize=10) #Stick points in kd-tree for fast look-up
#Return the distance to, and index of, each of df1's nearest neighbour points
distance, indices = GetNearestNeighbours(df1,kdtree)
内容总结
以上是互联网集市为您收集整理的Python – 低效的空间距离计算(如何加速)全部内容,希望文章能够帮你解决Python – 低效的空间距离计算(如何加速)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。