有没有比for循环和if语句更快的方法来查找python中另一个点的最近点?

如何解决有没有比for循环和if语句更快的方法来查找python中另一个点的最近点?

是否有更快的方法(在带cpu的Python中)执行与以下函数相同的操作?我使用了For循环和if语句,想知道是否有更快的方法?目前,每100个邮政编码大约需要1分钟才能运行此功能,而我大约需要70,000个电话才能通过。

使用的2个数据帧是:

postcode_df,其中包含71,092行和列:

  • 邮政编码,例如“ BL4 7PD”
  • 纬度,例如53.577653
  • 经度,例如-2.434136

例如

postcode_df = pd.DataFrame({"Postcode":["SK12 2LH","SK7 6LQ"],"Latitude":[53.362549,53.373812],"Longitude":[-2.061329,-2.120956]})

air,其中包含421行和列:

  • TubeRef例如“ ABC01”
  • 纬度,例如53.55108
  • 经度,例如-2.396236

例如

air = pd.DataFrame({"TubeRef":["Stkprt35","Stkprt07","Stkprt33"],"Latitude":[53.365085,53.379502,53.407510],"Longitude":[-2.0763,-2.120777,-2.145632]})

函数在postcode_df中的每个邮政编码中循环,对于每个邮政编码,在每个TubeRef中循环并计算(使用geopy)它们之间的距离,并以距邮政编码最短的距离保存TubeRef。

输出df postcode_nearest_tube_refs包含每个邮政编码最近的试管,并包含列:

  • 邮政编码,例如“ BL4 7PD”
  • 最近的空气管“ ABC01
  • 与空气管KM的距离,例如1.035848
# define function to get nearest air quality monitoring tube per postcode
def get_nearest_tubes(constituency_list):
    
    postcodes = []
    nearest_tubes = []
    distances_to_tubes = []
    
    for postcode in postcode_df["Postcode"]:
            closest_tube = ""
            shortest_dist = 500

            postcode_lat = postcode_df.loc[postcode_df["Postcode"]==postcode,"Latitude"]
            postcode_long = postcode_df.loc[postcode_df["Postcode"]==postcode,"Longitude"]
            postcode_coord = (float(postcode_lat),float(postcode_long))


            for tuberef in air["TubeRef"]:
                tube_lat = air.loc[air["TubeRef"]==tuberef,"Latitude"]
                tube_long = air.loc[air["TubeRef"]==tuberef,"Longitude"]
                tube_coord = (float(tube_lat),float(tube_long))

                # calculate distance between postcode and tube
                dist_to_tube = geopy.distance.distance(postcode_coord,tube_coord).km
                if dist_to_tube < shortest_dist:
                    shortest_dist = dist_to_tube
                    closest_tube = str(tuberef)

            # save postcode's tuberef with shortest distance
            postcodes.append(str(postcode))
            nearest_tubes.append(str(closest_tube))
            distances_to_tubes.append(shortest_dist)
            
    # create dataframe of the postcodes,nearest tuberefs and distance
    postcode_nearest_tube_refs = pd.DataFrame({"Postcode":postcodes,"Nearest Air Tube":nearest_tubes,"distance to Air Tube KM": distances_to_tubes})

    return postcode_nearest_tube_refs

我正在使用的图书馆是:

import numpy as np
import pandas as pd
# !pip install geopy
import geopy.distance

解决方法

这里是一个有效的示例,耗时数为10秒。

导入库

import pandas as pd
import numpy as np
from sklearn.neighbors import BallTree
import uuid

我生成一些随机数据,这也需要一秒钟,但至少我们有一些实际的数据。

np_rand_post = 5 * np.random.random((72000,2))
np_rand_post = np_rand_post + np.array((53.577653,-2.434136))

并使用UUID伪造邮政编码

postcode_df = pd.DataFrame( np_rand_post,columns=['lat','long'])
postcode_df['postcode'] = [uuid.uuid4().hex[:6] for _ in range(72000)]
postcode_df.head()

我们在空中做同样的事情

np_rand = 5 * np.random.random((500,2))
np_rand = np_rand + np.array((53.55108,-2.396236))

并再次使用uuid进行伪引用

tube_df = pd.DataFrame( np_rand,'long'])
tube_df['ref'] = [uuid.uuid4().hex[:5] for _ in range(500)]
tube_df.head()

将gps值提取为numpy

postcode_gps = postcode_df[["lat","long"]].values
air_gps = tube_df[["lat","long"]].values

创建一棵balltree

postal_radians =  np.radians(postcode_gps)
air_radians = np.radians(air_gps)

tree = BallTree(air_radians,leaf_size=15,metric='haversine')

查询最接近的第一位

distance,index = tree.query(postal_radians,k=1)

请注意,距离不是以KM为单位,您需要先进行转换。

earth_radius = 6371000
distance_in_meters = distance * earth_radius
distance_in_meters

例如,使用tube_df.ref[ index[:,0] ]

获取引用 ,

您可以使用numpy计算A组中任何点到B组中任何点的距离矩阵,然后仅取A组中与最小距离相对应的点。

import numpy as np
import pandas as pd

dfA = pd.DataFrame({'lat':np.random.uniform(0,30,3),'lon':np.random.uniform(0,'id':[1,2,3]})
dfB = pd.DataFrame({'lat':np.random.uniform(0,'id':['a','b','c']})
lat1 = dfA.lat.values.reshape(-1,1)
lat2 = dfB.lat.values.reshape(1,-1)
lon1 = dfA.lon.values.reshape(-1,1)
lon2 = dfB.lon.values.reshape(1,-1)
dists = np.sqrt((lat1 - lat2)**2 + (lon1-lon2)**2)
for id1,id2 in zip (dfB.id,dfA.id.iloc[np.argmin(dists,axis=1)]):
    print(f'the closest point in dfA to {id1} is {id2}')

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?