我在优化以下for循环方面遇到了一些麻烦。我已经查看了map函数,理解表达式以及一些itertools和generator,但我不确定如何对嵌套循环进行优化。非常感谢任何帮助或建议。提前谢谢!
请注意,对象架构是:
self.variables.parameters.index1/index2/value
self.variables.rate
self.state.num
循环1:
mat1 = np.zeros(m, n)
for idx, variable in enumerate(self.variables):
for parameter in variable.parameters:
tracking_idx = parameter.index1 + parameter.index2
mat1[tracking_idx, idx] = parameter.value
循环2:
mat2 = []
for variable in self.variables:
rate = variable.rate
for parameter in variable.parameters:
if parameter.value < 0 and self.state.num[parameter.index1, parameter.index2] <= 0:
rate = 0
mat2.append(rate)
答案 0 :(得分:1)
使用numpy
标记我假设'optimize'意味着将这些循环转换为已编译的numpy数组表达式。我不认为没有先将所有数据收集为numpy数组,这将需要相同的循环。
您有n
variables
的列表。每个变量都有一个?
参数列表。每个参数都有3或4个属性。
所以
rates = np.array([v.rate for v in variables])
values = np.array([[p.value for p in v.parameters] for v in variables]
index1s = <dito> (?,n) array
index2s = <dita> (?,n) array
self.state.num
已经是一个二维数组,其大小与index1s
和index2s
中的值范围兼容。
鉴于这些1和2d数组,我们应该能够使用整数组运算派生mat1
和mat2
。如果?
相对于m
较小且index1
和index2
中的值范围较小,则可能值得这样做。我对你的数据没有真实的感觉。
===========
你提到the map function, comprehension expressions, and a bit of itertools and generators
。这些可以使代码看起来更清晰,但速度没有太大差异。
我展示了列表推导的使用。这些表达可以更复杂,但通常以可读性为代价。我喜欢编写辅助函数来隐藏细节。生成器理解可以替换为另一个提供的列表理解。地图涵盖相同的功能。
由于variables
和parameters
具有属性,我假设您已在类中定义它们。您可以编写将这些属性提取为简单列表或数组的方法。
class Variable(....):
....
def get_values(self):
return [p.value for p in self.parameters]
def get_rate(self, state):
rate = self.rate
for parameter in self.parameters:
if parameter.value < 0 and
state.num[parameter.index1, parameter.index2] <= 0:
rate = 0
return rate
values = [v.get_values() for v in variables]
rates = [v.get_rate(self.state) for v in variables]
你甚至可以在没有类结构的情况下编写这些辅助函数。
这不会加速任何事情;它只是隐藏了对象中的一些细节。