我有 36,742 个点的输入,这意味着如果我想计算距离矩阵的下三角形(使用 vincenty 近似值),我需要生成 36,742*36,741*0.5 = 1,349,974,563 距离。
我想保留彼此相距 50 公里以内的配对组合。我目前的设置如下
shops= [[id,lat,lon]...]
def lower_triangle_mat(points):
for i in range(len(shops)-1):
for j in range(i+1,len(shops)):
yield [shops[i],shops[j]]
def return_stores_cutoff(points,cutoff_km=0):
below_cut = []
counter = 0
for x in lower_triangle_mat(points):
dist_km = vincenty(x[0][1:3],x[1][1:3]).km
counter += 1
if counter % 1000000 == 0:
print("%d out of %d" % (counter,(len(shops)*len(shops)-1*0.5)))
if dist_km <= cutoff_km:
below_cut.append([x[0][0],x[1][0],dist_km])
return below_cut
start = time.clock()
stores = return_stores_cutoff(points=shops,cutoff_km=50)
print(time.clock() - start)
这显然需要几个小时。我想到的一些可能性:
- 使用 numpy 向量化这些计算,而不是循环遍历
- 使用某种散列来快速粗略截断(100 公里内的所有商店),然后只计算这些商店之间的准确距离
- 不要将点存储在列表中,而是使用四叉树之类的东西,但我认为这只有助于近距离点的排名而不是实际距离 - >所以我猜是某种地理数据库
- 我显然可以尝试使用haversine或project并使用欧几里得距离,但是我有兴趣使用最准确的测量方法
- 利用并行处理(但是我在想出如何剪切列表以仍然获得所有相关对时遇到了一些困难)。
编辑:我认为这里肯定需要geohashing - 一个例子来自:
from geoindex import GeoGridIndex, GeoPoint
geo_index = GeoGridIndex()
for _ in range(10000):
lat = random.random()*180 - 90
lng = random.random()*360 - 180
index.add_point(GeoPoint(lat, lng))
center_point = GeoPoint(37.7772448, -122.3955118)
for distance, point in index.get_nearest_points(center_point, 10, 'km'):
print("We found {0} in {1} km".format(point, distance))
但是,我还想对地理哈希返回的商店的距离计算进行矢量化(而不是循环)。
Edit2:Pouria Hadjibagheri - 我尝试使用 lambda 和 map:
# [B]: Mapping approach
lwr_tr_mat = ((shops[i],shops[j]) for i in range(len(shops)-1) for j in range(i+1,len(shops)))
func = lambda x: (x[0][0],x[1][0],vincenty(x[0],x[1]).km)
# Trying to see if conditional statements slow this down
func_cond = lambda x: (x[0][0],x[1][0],vincenty(x[0],x[1]).km) if vincenty(x[0],x[1]).km <= 50 else None
start = time.clock()
out_dist = list(map(func,lwr_tr_mat))
print(time.clock() - start)
start = time.clock()
out_dist = list(map(func_cond,lwr_tr_mat))
print(time.clock() - start)
它们都在61 秒左右(我将商店数量从 32,000 限制到 2000)。也许我用错了地图?