使用 numpy 数组乘法和 "appending" 更快地创建 FOR 循环
Make a FOR LOOP with numpy arrays multiplication and "appending" faster
这是我当前的代码。
当第二个“for循环”中的元素数量较少(大约10k)并且只需要几秒钟时它工作正常,但是当第二个“for循环”中的元素数量很高时(大约 40k) 所需的时间大约为 60 秒或更长时间:为什么?
例如:有时当第二个 for 循环有 28k 个元素时,执行它所花费的时间比它有 7k 个元素时要少。我不明白为什么时间与操作次数不是线性相关的。
还有,一般来说,代码运行的时间越长,循环次数就越大。
要回顾,执行时间通常遵循以下规则:
- 当操作 < 10k 时,时间 < 5 秒
- 当 10k < operations < 40k 时,10s < time < 30s(似乎是随机的)
- 当操作 > 40k 时,时间 ~ 60 秒
.
from random import random
import numpy as np
import time
import gc
from collections import deque
import random
center_freq = 20000000
smpl_time = 0.03749995312*pow(10,-6)
mat_contents = []
for i in range(10):
mat_contents.append(np.ones((3600, random.randint(3000,30000))))
tempo = np.empty([0,0])
for i in range(3600):
tempo = np.append(tempo, center_freq*smpl_time*i)
ILO = np.cos(tempo)
check = 0
for element in mat_contents:
start_time = time.time()
Icolumn = np.empty([0,0])
Imatrix = deque([])
gc.disable()
for colonna in element.T:
Imatrix.append(np.multiply(ILO, colonna))
gc.enable()
varI = np.var(Imatrix)
tempImean = np.mean(Imatrix)
print('\nSize: ', len(element.T))
print("--- %s seconds ---" % (time.time() - start_time))
print("--- ", check, ' ---')
check += 1
你的代码终止了我的会话,大概是因为数组维度对于内存来说太大了。用较小的数字重试:
In [1]: from collections import deque
...: import random
...:
...: center_freq = 20000000
...: smpl_time = 0.03749995312*pow(10,-6)
...:
...: mat_contents = []
...:
...: for i in range(10):
...: mat_contents.append(np.ones((36, random.randint(30,300))))
...:
...: tempo = np.empty([0,0])
...:
...: for i in range(3600):
...: tempo = np.append(tempo, center_freq*smpl_time*i)
...:
...: ILO = np.cos(tempo)
...:
...: check = 0
In [2]:
In [2]: tempo.shape
Out[2]: (3600,)
In [3]: ILO
Out[3]:
array([ 1. , 0.73168951, 0.07073907, ..., -0.63602366,
-0.99137119, -0.81472814])
In [4]: len(mat_contents)
Out[4]: 10
快速说明 - 虽然在 mat_contents
循环中添加列表相对较快,但下一个循环中的 np.append
很糟糕。不要那样用。
我不知道我现在是否有时间看下一个循环,但是,你为什么要在那里使用 deque
?为什么不是列表?我没有使用 deque
太多,但我不认为它比右侧 append
.
的列表有任何优势
更正ILO
缩小的形状
In [16]: tempo = np.empty([0,0])
...: ...:
...: ...: for i in range(36):
...: ...: tempo = np.append(tempo, center_freq*smpl_time*i)
...:
In [17]: tempo.shape
Out[17]: (36,)
In [18]: ILO = np.cos(tempo)
我怀疑循环可以用一个 numpy
表达式代替,但我不会深入研究它。
In [19]: %%timeit
...: for element in mat_contents:
...: Icolumn = np.empty([0,0])
...: Imatrix = deque([])
...: for colonna in element.T:
...: Imatrix.append(np.multiply(ILO, colonna))
...: varI = np.var(Imatrix)
...: tempImean = np.mean(Imatrix)
...:
5.82 ms ± 6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
时间与 Imatrix = []
相同,因此使用 deque
不会造成伤害。
mat_contents
包含不同形状的数组(第二维):
In [22]: [x.shape for x in mat_contents]
Out[22]:
[(36, 203),
(36, 82),
(36, 194),
(36, 174),
(36, 119),
(36, 190),
(36, 272),
(36, 68),
(36, 293),
(36, 248)]
现在让我们检查一下您担心的慢循环:
In [23]: ILO.shape
Out[23]: (36,)
In [24]: element=mat_contents[0]
In [25]: element.T.shape
Out[25]: (203, 36)
In [26]: Imatrix =[]
...: for colonna in element.T:
...: Imatrix.append(np.multiply(ILO, colonna))
...: arr = np.array(Imatrix)
In [27]: arr.shape
Out[27]: (203, 36)
要将 (36,) 数组与 (203,36) 相乘,我们不需要循环。
In [28]: np.allclose(ILO*element.T, arr)
Out[28]: True
In [29]: %%timeit
...: Imatrix =[]
...: for colonna in element.T:
...: Imatrix.append(np.multiply(ILO, colonna))
...: arr = np.array(Imatrix)
...:
...:
405 µs ± 2.72 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
whole-array操作快多了:
In [30]: timeit ILO*element.T
19.4 µs ± 14.3 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
在您最初的问题中,您加载了一个 .mat
文件。您要翻译 MATLAB 代码吗? numpy
类似于 old-time MATLAB,其中 whole-matrix 操作要快得多。 numpy
不执行 jit
循环编译。
这是我当前的代码。
当第二个“for循环”中的元素数量较少(大约10k)并且只需要几秒钟时它工作正常,但是当第二个“for循环”中的元素数量很高时(大约 40k) 所需的时间大约为 60 秒或更长时间:为什么?
例如:有时当第二个 for 循环有 28k 个元素时,执行它所花费的时间比它有 7k 个元素时要少。我不明白为什么时间与操作次数不是线性相关的。
还有,一般来说,代码运行的时间越长,循环次数就越大。
要回顾,执行时间通常遵循以下规则:
- 当操作 < 10k 时,时间 < 5 秒
- 当 10k < operations < 40k 时,10s < time < 30s(似乎是随机的)
- 当操作 > 40k 时,时间 ~ 60 秒
.
from random import random
import numpy as np
import time
import gc
from collections import deque
import random
center_freq = 20000000
smpl_time = 0.03749995312*pow(10,-6)
mat_contents = []
for i in range(10):
mat_contents.append(np.ones((3600, random.randint(3000,30000))))
tempo = np.empty([0,0])
for i in range(3600):
tempo = np.append(tempo, center_freq*smpl_time*i)
ILO = np.cos(tempo)
check = 0
for element in mat_contents:
start_time = time.time()
Icolumn = np.empty([0,0])
Imatrix = deque([])
gc.disable()
for colonna in element.T:
Imatrix.append(np.multiply(ILO, colonna))
gc.enable()
varI = np.var(Imatrix)
tempImean = np.mean(Imatrix)
print('\nSize: ', len(element.T))
print("--- %s seconds ---" % (time.time() - start_time))
print("--- ", check, ' ---')
check += 1
你的代码终止了我的会话,大概是因为数组维度对于内存来说太大了。用较小的数字重试:
In [1]: from collections import deque
...: import random
...:
...: center_freq = 20000000
...: smpl_time = 0.03749995312*pow(10,-6)
...:
...: mat_contents = []
...:
...: for i in range(10):
...: mat_contents.append(np.ones((36, random.randint(30,300))))
...:
...: tempo = np.empty([0,0])
...:
...: for i in range(3600):
...: tempo = np.append(tempo, center_freq*smpl_time*i)
...:
...: ILO = np.cos(tempo)
...:
...: check = 0
In [2]:
In [2]: tempo.shape
Out[2]: (3600,)
In [3]: ILO
Out[3]:
array([ 1. , 0.73168951, 0.07073907, ..., -0.63602366,
-0.99137119, -0.81472814])
In [4]: len(mat_contents)
Out[4]: 10
快速说明 - 虽然在 mat_contents
循环中添加列表相对较快,但下一个循环中的 np.append
很糟糕。不要那样用。
我不知道我现在是否有时间看下一个循环,但是,你为什么要在那里使用 deque
?为什么不是列表?我没有使用 deque
太多,但我不认为它比右侧 append
.
更正ILO
缩小的形状
In [16]: tempo = np.empty([0,0])
...: ...:
...: ...: for i in range(36):
...: ...: tempo = np.append(tempo, center_freq*smpl_time*i)
...:
In [17]: tempo.shape
Out[17]: (36,)
In [18]: ILO = np.cos(tempo)
我怀疑循环可以用一个 numpy
表达式代替,但我不会深入研究它。
In [19]: %%timeit
...: for element in mat_contents:
...: Icolumn = np.empty([0,0])
...: Imatrix = deque([])
...: for colonna in element.T:
...: Imatrix.append(np.multiply(ILO, colonna))
...: varI = np.var(Imatrix)
...: tempImean = np.mean(Imatrix)
...:
5.82 ms ± 6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
时间与 Imatrix = []
相同,因此使用 deque
不会造成伤害。
mat_contents
包含不同形状的数组(第二维):
In [22]: [x.shape for x in mat_contents]
Out[22]:
[(36, 203),
(36, 82),
(36, 194),
(36, 174),
(36, 119),
(36, 190),
(36, 272),
(36, 68),
(36, 293),
(36, 248)]
现在让我们检查一下您担心的慢循环:
In [23]: ILO.shape
Out[23]: (36,)
In [24]: element=mat_contents[0]
In [25]: element.T.shape
Out[25]: (203, 36)
In [26]: Imatrix =[]
...: for colonna in element.T:
...: Imatrix.append(np.multiply(ILO, colonna))
...: arr = np.array(Imatrix)
In [27]: arr.shape
Out[27]: (203, 36)
要将 (36,) 数组与 (203,36) 相乘,我们不需要循环。
In [28]: np.allclose(ILO*element.T, arr)
Out[28]: True
In [29]: %%timeit
...: Imatrix =[]
...: for colonna in element.T:
...: Imatrix.append(np.multiply(ILO, colonna))
...: arr = np.array(Imatrix)
...:
...:
405 µs ± 2.72 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
whole-array操作快多了:
In [30]: timeit ILO*element.T
19.4 µs ± 14.3 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
在您最初的问题中,您加载了一个 .mat
文件。您要翻译 MATLAB 代码吗? numpy
类似于 old-time MATLAB,其中 whole-matrix 操作要快得多。 numpy
不执行 jit
循环编译。