如何将一个numpy数组归一化为单位向量

312
我想将一个NumPy数组转换为单位向量。更具体地说,我正在寻找与这个归一化函数等效的版本:
def normalize(v):
    norm = np.linalg.norm(v)
    if norm == 0: 
       return v
    return v / norm

这个函数处理向量 v 的范数值为0的情况。 sklearn 或者 numpy 中有类似的函数吗?

14
你所写的有什么问题? - ali_m
7
如果这是真正的问题,你应该检查范数 < epsilon,其中epsilon是一个小公差。此外,我不会默默地返回一个零向量,我会 raise(抛出)一个异常! - Hooked
8
我的函数能够正常工作,但我想知道Python的常用库中是否有类似的功能。我正在编写不同的机器学习函数,并希望避免定义过多的新函数,以使代码更加清晰易读。 - Donbeo
2
我进行了几个快速测试,发现在CPU上,numpy 1.15.1中x/np.linalg.norm(x)x/np.sqrt((x**2).sum())慢不了多少(大约15-20%)。 - Bill
16个回答

7

不使用sklearn,仅使用numpy。只需定义一个函数:

假设行是变量列是样本axis = 1):

import numpy as np

# Example array
X = np.array([[1,2,3],[4,5,6]])

def stdmtx(X):
    means = X.mean(axis =1)
    stds = X.std(axis= 1, ddof=1)
    X= X - means[:, np.newaxis]
    X= X / stds[:, np.newaxis]
    return np.nan_to_num(X)

输出:

X
array([[1, 2, 3],
       [4, 5, 6]])

stdmtx(X)
array([[-1.,  0.,  1.],
       [-1.,  0.,  1.]])


这些输出数组没有单位范数。减去平均值并使样本具有单位方差不能产生单位向量。 - crypdick

7
如果您正在使用3D向量,可以使用工具包vg来简洁地完成此操作。它是numpy的轻量级封装,在支持单个值的同时也支持堆叠向量。
import numpy as np
import vg

x = np.random.rand(1000)*10
norm1 = x / np.linalg.norm(x)
norm2 = vg.normalize(x)
print np.all(norm1 == norm2)
# True

我在上一个创业公司创建了这个库,它的动机是解决 NumPy 中过于繁琐的简单问题。


4
对于一个二维数组,您可以使用以下一行代码对每行进行归一化处理。要对每列进行归一化处理,只需将 axis=0 设置即可。
a / np.linalg.norm(a, axis=1, keepdims=True)

感谢提到keepdims=True,这对于形状不变的情况确实非常有用。 - Maksym Ganenko

1
一个简单的点积就可以完成任务,不需要任何额外的包。
x = x/np.sqrt(x.dot(x))

顺便说一下,如果向量x的范数为零,则它本质上是一个零向量,无法转换为单位向量(其范数为1)。如果你想捕捉np.array([0,0,...0])的情况,那么请使用:

norm = np.sqrt(x.dot(x))
x = x/norm if norm != 0 else x

3
我经常使用这个技巧: x_normalised = x / (norm+(norm==0))所以在所有规范为零的情况下,你只需除以一。 - user111950

1
如果您想使 1d-array 中的所有值在 [0; 1] 范围内,则只需使用以下代码:
(a - a.min(axis=0)) / (a.max(axis=0) - a.min(axis=0))

其中a代表你的一维数组。

示例:

>>> a = np.array([0, 1, 2, 4, 5, 2])
>>> (a - a.min(axis=0)) / (a.max(axis=0) - a.min(axis=0))
array([0. , 0.2, 0.4, 0.8, 1. , 0.4])

方法说明。 为了保存值之间的比例,有一个限制条件: 1d-array 必须至少有一个 0,并且由 0正数 组成。


0
很不幸,简单的解决方案 x/numpy.linalg.norm(x)x 是一个向量数组时无法工作。但是通过简单的 reshape(),你可以将其强制转换为一个平坦的列表,使用列表推导式,并再次使用 reshape() 来恢复原始形状。
s=x.shape
np.array([ v/np.linalg.norm(v)  for v in x.reshape(-1, s[-1])]).reshape(s)

首先,我们存储数组的形状。
s=x.shape

然后我们将其重新塑造成一个简单的(一维)向量数组。
x.reshape(-1, s[-1])

通过利用reshape()的'-1'参数,它实际上意味着"取所需数量",例如,如果x是一个(4,5,3)的数组,x.reshape(-1,3)的形状将是(20,3)。使用s[-1]允许向量的任意维度。
然后,我们使用列表推导式逐个遍历数组,并计算每个向量的单位向量。
[ v/np.linalg.norm(v)  for v in x.reshape(-1, s[-1])]

最后,我们将其转换回一个numpy数组,并恢复其原始形状。
np.array([ v/np.linalg.norm(v)  for v in x.reshape(-1, s[-1])]).reshape(s)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接