gpt4 book ai didi

python - 如何避免在列表理解中运行致命函数 30,000 次?

转载 作者:太空狗 更新时间:2023-10-30 02:16:02 25 4
gpt4 key购买 nike

我有两个长度相同的列表。我想检查一个列表中的条件。如果条件为真,则在另一个列表上运行内存/处理密集型函数。

我的第一次尝试是这样的:

records = [(a, deadly_func(b)) for a, b in zip(listA, listB) if a == "condition"]

这立即分配了我桌面上的所有内存,并在我杀死它之前继续了一段时间。显然,它对 listB 中的所有 30,000 个项目运行了 deadly_func(b),而其目的是使用“if”语句将 listB 过滤到大约 30 个项目。

我能够制作一个工作版本:

records = [(a, i) for a, i in zip(listA, range(len(listB)) if a == "condition"]
records = [(a, deadly_func(listB[i]) for a, i in records]

为什么我的第一次尝试没有成功?是否有更 pythonic 的方法来完成这项工作?


编辑:感谢您的回复。这是两个版本的实际代码

无效:

import shapefile, shapely.geometry as shpgeo

lat = 42.3968243
lon = -71.0313479

sf = shapefile.Reader("/opt/ziplfs/tl_2014_us_zcta510.shp")

records = [(r[0], shpgeo.shape(s.__geo_interface__)) for r, s in zip(sf.records(), sf.shapes()) if haversine(lon, lat, float(r[8]), float(r[7])) < 10]

haversine() 是用户创建的 haversine 函数,采用两对纬度和经度并返回以公里为单位的距离。

from math import sqrt, sin, cos, radians, asin
def haversine(lon1, lat1, lon2, lat2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees). Return is in kilometers
"""
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])

# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers. Use 3956 for miles
return c * r

shapefile ('tl_2014_us_zcta510.shp') 是美国的所有邮政编码,来自人口普查局。下载 here如果您真的喜欢 shapefile,并且您的硬盘上有 800 MB,您将不知道如何处理。

此脚本应返回代表美国所有邮政编码的元组列表,其质心在马萨诸塞州切尔西 10 公里范围内。

对于工作版本,将记录行替换为:

records = [(r[0], i) for r, i in zip(sf.records(), range(len(sf.records()))) if haversine(lon, lat, float(r[8]), float(r[7])) < 10]
shapes = [shpgeo.shape(sf.shape(i).__geo_interface__) for r, i in records]

我做了一些计时测试。 “非工作”版本:

$ python test.py 
Time Elapsed: 0:00:14.221533
$ python test.py
Time Elapsed: 0:00:14.637827
$ python test.py
Time Elapsed: 0:00:14.253425

和工作版本:

$ python test.py 
Time Elapsed: 0:00:01.887987
$ python test.py
Time Elapsed: 0:00:01.886635
$ python test.py
Time Elapsed: 0:00:01.982547

也许不是说“致命”,但当你重复 30k 次时就很重要了。

最佳答案

没有复现?此代码不会listB 的所有元素运行deadly_func。只有那些对应的 listA 值为 True 的:

listA = [True, False, True, False]
listB = [1, 2, 3, 4]

def deadly_func(x):
print("Called with {}".format(x))
return x

print([(a, deadly_func(b)) for a, b in zip(listA, listB) if a])

# Output:
# Called with 1
# Called with 3
# [(True, 1), (True, 3)]

编辑

根据更新后的问题,我的猜测是 sf.shapes() 是昂贵的部分。因此,仅在您想要的元素子集上调用 sf.shape(i) 效率更高。

如果我的猜测是正确的,这应该可以解决问题:

records = [(r[0], shpgeo.shape(sf.shape(i).__geo_interface__)) for i, r in enumerate(sf.records()) if haversine(lon, lat, float(r[8]), float(r[7])) < 10]

(当然,这主要是你已经做过的。)

关于python - 如何避免在列表理解中运行致命函数 30,000 次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46480196/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com