我正在尝试在python中进行数组赋值,但它很慢,有没有办法加速?
simi_matrix_img = np.zeros((len(annot), len(annot)), dtype='float16')
for i in range(len(annot)):
for j in range(i + 1):
score = 0
times = 0
if i != j:
x_idx = [p1 for (p1, q1) in enumerate(annot[i]) if np.abs(q1 - 1) < 1e-5]
y_idx = [p2 for (p2, q2) in enumerate(annot[j]) if np.abs(q2 - 1) < 1e-5]
for idx in itertools.product(x_idx, y_idx):
score += simi_matrix_word[idx]
times += 1
simi_matrix_img[i, j] = score/times
else:
simi_matrix_img[i, j] = 1.0
&#34; ANNOT&#34;是一个numpy数组。有没有办法加速呢?
答案 0 :(得分:1)
(1)在可能的情况下,您可以使用生成器而不是列表推导。例如:
x_idx = (p1 for (p1, q1) in enumerate(annot[i]) if np.abs(q1 - 1) < 1e-5)
y_idx = (p2 for (p2, q2) in enumerate(annot[j]) if np.abs(q2 - 1) < 1e-5)
有了这个,你只对这些项进行一次迭代(在for idx in itertools.product(x_idx, y_idx)
中),而不是两次(一次用于构造列表,然后再在所述for
循环中)。
(2)你用的是什么Python?如果&lt; 3,我预感到问题的一个重要部分是你正在使用range()
,这对于非常大的范围来说可能是昂贵的(因为我假设你在这里使用)。在Python 2.7中,range()
实际上构造了列表(在Python 3中不是这样),这可能是一个昂贵的操作。尝试使用简单的while
循环实现相同的结果。例如,代替for i in range(len(annot))
,执行:
i=0
while i < len(annot):
... do stuff with i ...
i += 1
(3)为什么要多次拨打len(annot)
?看起来好像你在改变annot
。虽然len(annot)
是快速O,但您可以将长度存储在var中,例如annot_len = len(annot)
,然后只引用它。不过不会刮掉很多东西,我很害怕。
答案 1 :(得分:1)
我认为这一行的缩进是错误的:
simi_matrix_img[i, j] = score/times
您希望在所有product
次迭代后执行该分配。但由于它是最后一次分配,结果将是相同的。
这是您的代码的部分修改
def foo1(annot, simi_matrix_word):
N = annot.shape[0]
simi_matrix_img = np.zeros((N,N))
for i in range(N):
for j in range(i + 1):
if i != j:
x_idx = np.nonzero(annot[i])[0]
y_idx = np.nonzero(annot[j])[0]
idx = np.ix_(x_idx, y_idx)
# print(idx, simi_matrix_word[idx])
score = simi_matrix_word[idx].mean()
simi_matrix_img[i, j] = score
else:
simi_matrix_img[i, j] = 1.0
return simi_matrix_img
对于小型测试用例,它返回相同的内容:
annot=np.array([[1,0,1],[0,1,1]])
simi_matrix_word = np.arange(12, dtype=float).reshape(3,4)
[[ 1. 0.]
[ 7. 1.]]
摆脱了所有内部迭代。下一步将减少外部迭代。例如,从np.eye(N)
开始,只迭代较低的三个索引:
In [169]: np.eye(2)
Out[169]:
array([[ 1., 0.],
[ 0., 1.]])
In [170]: np.tril_indices(2,-1)
Out[170]: (array([1]), array([0]))
请注意,对于2行annot
,我们只会在score
计算一个[1,0]
。
用布尔索引替换nonzero
:
def foo3(annot, simi_matrix_word):
N = annot.shape[0]
A = annot.astype(bool)
simi_matrix_img = np.eye(N,dtype=float)
for i,j in zip(*np.tril_indices(N,-1)):
score = simi_matrix_word[A[i],:][:,A[j]]
simi_matrix_img[i, j] = score.mean()
return simi_matrix_img
或者这可能会加快索引的速度:
def foo4(annot, simi_matrix_word):
N = annot.shape[0]
A = annot.astype(bool)
simi_matrix_img = np.eye(N,dtype=float)
for i in range(1,N):
x = simi_matrix_word[A[i],:]
for j in range(i):
score = x[:,A[j]]
simi_matrix_img[i, j] = score.mean()
return simi_matrix_img
由于annot
每行的非零值的数量可能不同,因此每个score
求和的术语数也不同。这有力地表明进一步的矢量化是不可能的。