NumPy:如何快速归一化多个向量?
如何优雅地对NumPy中的向量列表进行归一化处理?
这里有一个示例,但这个示例不能正常工作:
from numpy import *
vectors = array([arange(10), arange(10)]) # All x's, then all y's
norms = apply_along_axis(linalg.norm, 0, vectors)
# Now, what I was expecting would work:
print vectors.T / norms # vectors.T has 10 elements, as does norms, but this does not work
最后的操作会出现“形状不匹配:对象无法广播到单一形状”的错误。
那么,如何才能优雅地对vectors
中的二维向量进行归一化呢?
编辑:为什么上面的代码不工作,而给norms
添加一个维度的做法却能正常工作(根据我下面的回答)?
6 个回答
16
好的,NumPy的数组形状广播是把维度加到数组形状的左边,而不是右边。不过,我们可以告诉NumPy把一个维度加到norms
数组的右边:
print vectors.T / norms[:, newaxis]
这样是可以工作的!
27
计算大小
我看到这个问题后,对你们的归一化方法产生了好奇。我用了一种不同的方法来计算大小。注意:我通常是在最后一个索引上计算范数(在这种情况下是行,而不是列)。
magnitudes = np.sqrt((vectors ** 2).sum(-1))[..., np.newaxis]
不过,通常我就是这样进行归一化的:
vectors /= np.sqrt((vectors ** 2).sum(-1))[..., np.newaxis]
时间比较
我做了一个测试来比较时间,发现我的方法快了不少,但Freddie Witherdon的建议更快。
import numpy as np
vectors = np.random.rand(100, 25)
# OP's
%timeit np.apply_along_axis(np.linalg.norm, 1, vectors)
# Output: 100 loops, best of 3: 2.39 ms per loop
# Mine
%timeit np.sqrt((vectors ** 2).sum(-1))[..., np.newaxis]
# Output: 10000 loops, best of 3: 13.8 us per loop
# Freddie's (from comment below)
%timeit np.sqrt(np.einsum('...i,...i', vectors, vectors))
# Output: 10000 loops, best of 3: 6.45 us per loop
不过要小心,因为这个StackOverflow的回答提到,使用einsum
时有一些安全检查没有进行,所以你要确保vectors
的dtype
足够好,能够准确存储大小的平方。
17
好吧,除非我错过了什么,这个确实可以用:
vectors / norms
你建议中的问题在于广播规则。
vectors # shape 2, 10
norms # shape 10
它们的形状长度不一样!所以规则是先在左边把小的形状扩展一下:
norms # shape 1,10
你可以通过手动调用来做到这一点:
vectors / norms.reshape(1,-1) # same as vectors/norms
如果你想计算vectors.T/norms
,你需要手动调整形状,方法如下:
vectors.T / norms.reshape(-1,1) # this works