Python 如何将NumPy中的数组规格化为单位向量?

Python 如何将NumPy中的数组规格化为单位向量?,python,numpy,scikit-learn,statistics,normalization,Python,Numpy,Scikit Learn,Statistics,Normalization,我想把NumPy数组转换成单位向量。更具体地说,我正在寻找此函数的等效版本 def normalize(v): norm = np.linalg.norm(v) if norm == 0: return v return v / norm 在skearn或numpy中是否有类似的内容 此函数适用于v为0向量的情况。如果您使用的是scikit学习,则可以使用: 我同意,如果这种功能是附带电池的一部分,那就太好了。但据我所知,事实并非如此。这是一个适用于任意

我想把NumPy数组转换成单位向量。更具体地说,我正在寻找此函数的等效版本

def normalize(v):
    norm = np.linalg.norm(v)
    if norm == 0: 
       return v
    return v / norm
skearn
numpy
中是否有类似的内容


此函数适用于
v
为0向量的情况。

如果您使用的是scikit学习,则可以使用:


我同意,如果这种功能是附带电池的一部分,那就太好了。但据我所知,事实并非如此。这是一个适用于任意轴的版本,可提供最佳性能

import numpy as np

def normalized(a, axis=-1, order=2):
    l2 = np.atleast_1d(np.linalg.norm(a, order, axis))
    l2[l2==0] = 1
    return a / np.expand_dims(l2, axis)

A = np.random.randn(3,3,3)
print(normalized(A,0))
print(normalized(A,1))
print(normalized(A,2))

print(normalized(np.arange(3)[:,None]))
print(normalized(np.arange(3)))

您可以指定ord以获得L1范数。 为了避免零除法,我使用eps,但这可能不太好

def normalize(v):
    norm=np.linalg.norm(v, ord=1)
    if norm==0:
        norm=np.finfo(v.dtype).eps
    return v/norm

还有一个函数
unit_vector()
,用于规范Christoph Gohlke编写的流行模块中的向量:

import transformations as trafo
import numpy as np

data = np.array([[1.0, 1.0, 0.0],
                 [1.0, 1.0, 1.0],
                 [1.0, 2.0, 3.0]])

print(trafo.unit_vector(data, axis=1))

如果您有多维数据,并且希望将每个轴规格化为其最大值或总和:

def normalize(_d, to_sum=True, copy=True):
    # d is a (n x dimension) np array
    d = _d if not copy else np.copy(_d)
    d -= np.min(d, axis=0)
    d /= (np.sum(d, axis=0) if to_sum else np.ptp(d, axis=0))
    return d
使用numpys函数

a = np.random.random((5, 3))

b = normalize(a, copy=False)
b.sum(axis=0) # array([1., 1., 1.]), the rows sum to 1

c = normalize(a, to_sum=False, copy=False)
c.max(axis=0) # array([1., 1., 1.]), the max of each row is 1

这可能也适用于您

import numpy as np
normalized_v = v / np.sqrt(np.sum(v**2))
但当
v
的长度为0时失败


在这种情况下,引入一个小常数以防止零除法可以解决此问题。

如果要规范化存储在三维张量中的n维特征向量,也可以使用PyTorch:

import numpy as np
from torch import FloatTensor
from torch.nn.functional import normalize

vecs = np.random.rand(3, 16, 16, 16)
norm_vecs = normalize(FloatTensor(vecs), dim=0, eps=1e-16).numpy()

如果使用三维矢量,可以使用工具带简洁地执行此操作。它是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中过于冗长。

你提到了sci kit learn,所以我想分享另一个解决方案

sci套件学习
MinMaxScaler
在sci kit learn中,有一个名为
MinMaxScaler
的API,它可以根据需要自定义值范围

它还为我们处理NaN问题

NAN被视为缺失值:在拟合中忽略,并保留 在转变中。。。见参考文献[1]

代码示例 代码很简单,只需键入

# Let's say X_train is your input dataframe
from sklearn.preprocessing import MinMaxScaler
# call MinMaxScaler object
min_max_scaler = MinMaxScaler()
# feed in a numpy array
X_train_norm = min_max_scaler.fit_transform(X_train.values)
# wrap it up if you need a dataframe
df = pd.DataFrame(X_train_norm)
参考文献
  • [1]

如果您不需要最高精度,您的功能可以简化为:

v_norm = v / (np.linalg.norm(v) + 1e-16)

没有
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.]])

输出:

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.]])


如果您使用多维数组,下面的快速解决方案是可能的

假设我们有2D数组,我们希望通过最后一个轴对其进行规格化,而有些行的范数为零

将numpy导入为np
arr=np.array([
[1, 2, 3], 
[0, 0, 0],
[5, 6, 7]
],dtype=np.float)
长度=np.linalg.norm(arr,轴=-1)
打印(长度)#[3.74165739 0.10.48808848]
arr[length>0]=arr[length>0]/length[length>0][:,np.newaxis]
打印(arr)
# [[0.26726124 0.53452248 0.80178373]
# [0.         0.         0.        ]
# [0.47673129 0.57207755 0.66742381]]


你写的东西有什么问题吗?如果这确实是一个问题,你应该检查normx/np.linalg.norm(x)
x/np.sqrt((x**2.sum())慢不了多少(大约15-20%)
在CPU上的numpy 1.15.1中。谢谢您的回答,但您确定sklearn.preprocessing.normalize也适用于shape=(n,)或(n,1)的向量吗?我对该库有一些问题
规范化
需要2D输入。您可以传递
axis=
参数来指定是否要跨输入数组的行或列应用规范化。请注意,规范化函数的“norm”参数可以是“l1”或“l2”,默认值为“l2”。如果希望向量的和为1(例如概率分布),则应在规格化函数中使用norm='l1'。另外请注意,
np.linalg.norm(x)
默认情况下计算'l2'norm。如果希望向量的和为1,则应使用
np.linalg.norm(x,ord=1)
注意:x必须为
ndarray
才能使用
normalize()
函数。否则它可能是一个
列表
;但它可以在任意轴上工作,我们可以明确控制长度为0的向量的情况。非常好!这应该是numpy——尽管在我看来,顺序应该排在轴心之前。@EELCoogendoorn好奇地想知道为什么顺序=2比其他的多?因为欧几里得/毕达哥拉斯规范恰好是最常用的;你不同意吗?很晚了,但我认为值得一提的是,这正是为什么不鼓励使用小写字母“L”作为变量名的原因。。。在我的字体中,“l2”与“12”是无法区分的,规范化
[inf,1,2]
产生
[nan,0,0]
,但它不应该是
[1,0,0]
?请注意,如果原始矩阵中的所有值都相同,那么ptp将是0。除以0将返回nan。这将执行不同类型的转换。OP希望缩放向量的大小,使每个向量的长度为1;MinMaxScaler单独缩放每个列,使其在一定范围内。这些输出数组没有单位范数。减去平均值并给予样本单位方差不会产生单位向量。