P.V*_*.V. 6 python optimization
我有一个命名元组列表。每个命名元组都是DataPoint
我创建的一种类型,如下所示:
class DataPoint(NamedTuple):
data: float
location_zone: float
analysis_date: datetime
error: float
Run Code Online (Sandbox Code Playgroud)
在我的代码的各个阶段,我必须DataPoints
通过特定属性来获取列表中的所有内容。这是我的处理方式analysis_date
,其他属性也有类似的功能:
def get_data_points_on_date(self, data_points, analysis_date):
data_on_date = []
for data_point in data_points:
if data_point.analysis_date == analysis_date:
data_on_date.append(data_point)
return data_on_date
Run Code Online (Sandbox Code Playgroud)
在具有数千个点的列表上,这被称为> 100,000次,因此它大大降低了我的脚本的速度。
我可以用字典代替列表,以显着提高速度,但是由于我需要搜索多个属性,因此没有明显的关键。我可能会选择占用最多时间的函数(在本例中为analysis_date
),并将其用作键。但是,这将大大增加我的代码的复杂性。除了哈希之外,还有什么让我逃脱的聪明的哈希方法吗?
如果数据可以预先计算一次,您希望避免执行 100,000 次本质上的线性搜索,这是对的。为什么不使用多个字典,每个字典都由不同的感兴趣属性作为关键字?
每个字典将被预先计算一次:
self.by_date = defaultdict(list)
for point in data_points:
self.by_date[point.analysis_date].append(point)
Run Code Online (Sandbox Code Playgroud)
现在你的get_data_points_for_date
函数变成了一行:
def get_data_points_for_date(self, date):
return self.by_date[date]
Run Code Online (Sandbox Code Playgroud)
您可能可以完全删除此方法,然后使用self.by_date[date]
它。
这不会增加代码的复杂性,但它确实会预先转移一些簿记负担。您可以通过使用 set_data 方法来预先计算您想要的所有字典来处理这个问题:
from collections import defaultdict
from operator import attrgetter
def set_data(self, data_points):
keygetter):
d = defaultdict(list)
for point in data_points:
d[key(point)].append(point)
return d
self.by_date = make_dict(attrgetter('analysis_date'))
self.by_zone = make_dict(self.zone_code)
def zone_code(self, data_point):
return int(data_point.location_zone // 0.01)
Run Code Online (Sandbox Code Playgroud)
zone_code
将 s转换为整数是必要的,float
因为依赖float
s 作为键并不是一个好主意。