python - 我怎样才能加快这种远程计算算法?
问题描述
我正在用 Python 构建一个程序,该程序加载我所在国家/地区所有地址的地理位置,然后通过考虑每个地址与所有其他地址的距离来计算每个地址的“远程”值。由于我国有 3-5 百万个地址,我最终需要运行 3-5 百万次计算索引的算法迭代。
我已经采取了一些措施来缩短运行时间,包括:
- 尝试使用 numPy 有效地处理数据
- 我不是每个地址都查看其与其他地址的距离,而是将国家划分为多个区域,每个区域都已经分配了一个人口,然后每个地址只知道有多少这些区域中心位于每个距离内“RADII”中列举的值
通过 5000 个地址的列表仍然需要 23 秒,这意味着我预计 3-5 百万的完整数据集需要 24 小时以上的运行时间。
所以我的问题是:为了节省时间,我的算法的哪些部分应该改进?对您来说,什么是缓慢、冗余或低效的代码?例如,我对 JSON 和 numPy 的使用是否有意义?简化“距离”函数会有很大帮助吗?或者我会通过全力以赴并使用 Python 之外的另一种语言来获得显着优势吗?
任何建议将不胜感激。我是一个新手程序员,所以很容易出现我不知道的问题。
这是代码。它目前正在处理一个有限的数据集(一个小岛),约占整个数据集的 0.1%。该算法从第 30 行开始(#Main 循环):
import json
import math
import numpy as np
RADII = [888, 1480, 2368, 3848, 6216, 10064, 16280]
R = 6371000
remoteness = []
db = SQL("sqlite:///samsozones.db")
def main():
with open("samso.json", "r") as json_data:
data = json.load(json_data)
rows = db.execute("SELECT * FROM zones")
#Establish amount of zones with addresses in them
ZONES = len(rows)
#Initialize matrix with location of the center of each zone and the population of the zone
zonematrix = np.zeros((ZONES, 3), dtype="float")
for i, row in enumerate(rows):
zonematrix[i,:] = row["x"], row["y"], row["population"]
#Initialize matrix with distance from current address to centers of each zone and the population of the zone (will be filled out for each address in the main loop)
distances = np.zeros((ZONES, 2), dtype="float")
#Main loop (calculate remoteness index for each address)
for address in data:
#Reset remoteness index for new address
index = 0
#Calculate distance from address to each zone center and insert the distances into the distances matrix along with population
for j in range(ZONES):
distances[j, 0] = distance(address["x"], address["y"], zonematrix[j, 0], zonematrix[j, 1])
distances[j, 1] = zonematrix[j, 2]
#Calculate remoteness index
for radius in RADII:
#Calculate amount of zone centers within each radius and add up their population
allwithincircle = distances[distances[:,0] < radius]
count = len(allwithincircle)
pop = allwithincircle[:,1].sum()
#Calculate average within-radius zone population
try:
factor = pop / count
except:
factor = 0
#Increment remoteness index:
index += (1 / radius) * factor
remoteness.append((address["betegnelse"], index))
# Haversine function by Deduplicator, adapted from https://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula
def distance(lat1,lon1,lat2,lon2):
dLat = deg2rad(lat2-lat1)
dLon = deg2rad(lon2-lon1)
a = math.sin(dLat/2) * math.sin(dLat/2) + math.cos(deg2rad(lat1)) * math.cos(deg2rad(lat2)) * math.sin(dLon/2) * math.sin(dLon/2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = R * c
return d;
def deg2rad(deg):
return deg * (math.pi / 180)
if __name__ == "__main__":
main()
# Running time (N = 5070): 23 seconds
# Results quite reasonable
# Scales more or less linearly```
解决方案
我可以推荐一些潜在的加速:
不要使用 Haversine 来计算您的距离。为您所在的国家/地区找到一个好的本地投影(您没有说您在哪里,所以我不能)并将您的数据重新投影到该 CRS 中,这将允许您使用计算速度更快的简单欧几里得距离(尤其是如果您在距离的平方工作以节省一堆平方根)。
我会避免计算与所有可能区域的距离,方法是将计算转换为人口的栅格表面,然后计算每个像元的距离,然后查看该栅格上的地址点。如果我街道上的一所房子很偏僻,那么我不需要查找其余的房子!例如,我会看看我的前同事 Carver、Evan 和 Fritz在英国的 Wilderness 属性映射,以作为很好的例子。
推荐阅读
- php - 从 laravel nova 工具中删除侧边栏
- html - 尝试在输入时使用很棒的字体
- discord - 如何从 Id discord.py 中获取成员对象
- python-3.x - 有没有办法让 ["Kari","can","keep","her","car."] 生成输出 "Kari" "can" "keep" "her" "car"
- python - 如何使用 if 语句调用函数,然后打印 if 语句中返回的值?
- java - 关于最大流量的一些事实令人惊讶
- javascript - 如果子元素包含某个字符串链,如何更改父元素的 CSS 类
- tls1.2 - 是否有解决 nmap ssl-enum-ciphers 不返回所有 TLS 1.2 密码套件的解决方案?
- laravel - Laravel - 使用 FormRequest 验证时以多对多方式更新模型失败
- javascript - 使用闭包无限滚动页面?