[英]Boosting time for multiple for loops in list comprehensions
我正在寻找一种方法来减少Python 3.5在清单推导中看起来像这样的两个for循环的执行时间:
[[(k1-k2)**power for k2 in range(m,n)] for k1 in range(m,n)]
因此,我从您当前的方法开始,发现虽然它确实有效,但速度很慢。 我的第一次尝试只是将您的列表理解转换为使用numpy
数组的合适方法。 这比您最初的方法快三倍,但是那时候我注意到了一些非常漂亮的东西:这是一个对称的Toeplitz矩阵 。 从该维基页面:
在线性代数中,以Otto Toeplitz命名的Toeplitz矩阵或对角常数矩阵是其中从左到右的每个对角线下降的常数的矩阵。
我首先使用了Toeplitz矩阵的默认scipy
实现,但是这种方法对于您的问题来说不必要太慢。 所以我给自己写了类似的方法,这是下面的第三次尝试。
我为每种方法运行了10个测试,每个单独的测试包含1000次运行。 我将参数设置为m = 10, n = 100
。 结果可以在下表中找到:
Your approach Numpy #1 Numpy #2 Numpy #3
1 4.573965 1.432406 1.060242 0.186767
2 4.341466 1.432237 1.060404 0.186872
3 4.442438 1.434460 1.144850 0.183120
4 4.318919 1.456928 1.072072 0.185626
5 4.249392 1.450684 1.072217 0.183273
6 4.202730 1.508863 1.070299 0.183019
7 4.224226 1.457543 1.065354 0.183591
8 4.234505 1.432971 1.082438 0.185711
9 4.256538 1.431828 1.080051 0.184290
10 4.241055 1.557204 1.083070 0.185845
AVG 4.308523 1.459512 1.079100 0.184811
STD 0.117433 0.041693 0.024538 0.001521
scipy
Toeplitz方法(表中的Numpy #2
)比您当前的方法快四倍,但是所有这些结果都与第三种方法(也是最后一种方法) scipy
:比最初的实现高出23倍!
现在,由于您对时间复杂度感兴趣,我让n
变化,保持m = 10
。 下图显示了每种方法的结果:
显然,第三种方法是要走的路!
完整代码:
import timeit
import numpy as np
from scipy.linalg import toeplitz
def your_approach(m, n):
print("\n\tlist comprehension")
k = range(m, n)
for i in range(1, 11):
start = timeit.default_timer()
for j in range(1, 1001):
data_list_comp = [[(k1 - k2) ** 2 for k2 in k] for k1 in k]
print("\t{}".format(timeit.default_timer() - start))
return data_list_comp
def numpy1(m, n):
print("\n\tnumpy")
k_n = np.array(range(m, n))
for i in range(1, 11):
start = timeit.default_timer()
for j in range(1, 1001):
data_numpy = [list((k_n - x) ** 2) for x in k_n]
print("\t{}".format(timeit.default_timer() - start))
return data_numpy
def numpy2(m, n):
print("\n\ttoeplitz")
k_n = np.array(range(0, n - m)) ** 2
toep = toeplitz(k_n)
for i in range(1, 11):
start = timeit.default_timer()
for j in range(1, 1001):
data_numpy = [list(toep[:, i]) for i in range(n - m)]
print("\t{}".format(timeit.default_timer() - start))
return data_numpy
def numpy3(m, n):
print("\n\ttoeplitz2")
k_n = list(np.array(range(0, n - m)) ** 2) # can obviously be done without numpy, but I was a bit lazy. :)
for i in range(1, 11):
start = timeit.default_timer()
for j in range(1, 1001):
data_numpy = [(k_n[i::-1] + k_n[1:-i]) if i != 0 else k_n for i in range(0, n - m)]
print("\t{}".format(timeit.default_timer() - start))
return data_numpy
m = 10
for n in [25, 50, 100, 150, 200]:
assert your_approach(m, n) == numpy1(m, n) == numpy2(m, n) == numpy3(m, n)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.