NumPyで配列を正規化する方法は?


203

1つのNumPy配列のノルムが欲しいのですが。より具体的には、この関数の同等のバージョンを探しています

def normalize(v):
    norm = np.linalg.norm(v)
    if norm == 0: 
       return v
    return v / norm

skearnまたはそのようなものはありますかnumpy

この関数vは、が0ベクトルである状況で機能します。


3
あなたが書いたものの何が問題になっていますか?
ali_m 2014年

5
これが本当に問題になる場合は、ノルム<イプシロン(イプシロンは小さな許容誤差)を確認する必要があります。さらに、私はノーマルゼロのベクトルを黙って返さないでしょうraise、例外です!
2014年

4
私の関数は機能しますが、Pythonのより一般的なライブラリ内に何かがあるかどうか知りたいのですが。私はさまざまな機械学習関数を書いており、コードをより明確で読みやすくするためにあまりにも多くの新しい関数を定義しないようにしたいと思います
Donbeo

1
私はいくつかの簡単なテストを行いましたx/np.linalg.norm(x)x/np.sqrt((x**2).sum())、CPUのnumpy 1.15.1 よりもそれほど遅くない(約15〜20%)ことがわかりました。
ビル・

回答:


160

scikit-learnを使用している場合は、次を使用できますsklearn.preprocessing.normalize

import numpy as np
from sklearn.preprocessing import normalize

x = np.random.rand(1000)*10
norm1 = x / np.linalg.norm(x)
norm2 = normalize(x[:,np.newaxis], axis=0).ravel()
print np.all(norm1 == norm2)
# True

2
回答ありがとうございます。sklearn.preprocessing.normalizeは、shape =(n、)または(n、1)のベクトルでも機能しますか?このライブラリに問題があります
Donbeo

normalize2D入力が必要です。axis=引数を渡して、入力配列の行または列に正規化を適用するかどうかを指定できます。
ali_m 2014年

9
正規化関数の 'norm'引数は 'l1'または 'l2'のいずれかであり、デフォルトは 'l2'であることに注意してください。ベクトルの合計を1にしたい場合(たとえば、確率分布)、正規化関数でnorm = 'l1'を使用する必要があります。
アッシュ

2
またnp.linalg.norm(x)、デフォルトでは「l2」ノルムを計算することに注意してください。ベクトルの合計を1にしたい場合は、使用する必要がありますnp.linalg.norm(x, ord=1)
Omid

注:xはndarraynormalize()関数で機能するためのものでなければなりません。それ以外の場合は可能list
Ramin Melikov

46

そのような機能が含まれている電池の一部であったらいいと思います。しかし、私の知る限りではそうではありません。これは任意の軸のバージョンであり、最適なパフォーマンスを提供します。

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

私はali_mソリューションを深くテストしませんでしたが、いくつかの単純なケースではそれが機能しているようです。機能が向上する状況はありますか?
Donbeo 2014年

1
知りません; しかし、これは任意の軸で機能し、長さ0のベクトルに対して何が起こるかを明示的に制御します。
Eelco Hoogendoorn 2014年

1
非常に素晴らしい!これは乱暴なはずです—私の意見ではおそらく軸の前に来るべきです。
Neil G

@EelcoHoogendoorn order = 2が他よりも選ばれた理由を知りたいですか?
Henry Thornton、2015

7
ユークリッド/ピタゴランノルムが最も頻繁に使用されるものだからです。同意しませんか?
Eelco Hoogendoorn 2015

21

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

6
[inf, 1, 2]利回りを正規化しますが[nan, 0, 0]、そうではありません[1, 0, 0]か?
pasbi

12

これもうまくいくかもしれません

import numpy as np
normalized_v = v / np.sqrt(np.sum(v**2))

v長さが0の場合は失敗します。


10

多次元データがあり、各軸をその最大値または合計に正規化する場合:

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

元の行列ですべての値が同じである場合は注意してください。ptpは0になります。0で除算するとnanが返されます。
ミルソ

8

Christoph Gohlkeによるunit_vector()一般的な変換モジュールには、ベクトルを正規化する関数もあります。

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

7

sci-kitの学習について説明されたので、別のソリューションを共有したいと思います。

サイエンスキットは学ぶ MinMaxScaler

sci-kit learnには、次のAPIがあります。 MinMaxScaler、値の範囲を好きなようにカスタマイズできる。

また、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)
参照

6

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

4

3Dテンソルに保存されている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()

4

3Dベクトルで作業している場合は、toolbelt 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で非常に冗長である単純なアイデアが次のような使用によって動機付けられました。



3

多次元配列で作業する場合、次の高速ソリューションが可能です。

一部の行のノルムがゼロである一方で、最後の軸で正規化したい2D配列があるとします。

import numpy as np
arr = np.array([
    [1, 2, 3], 
    [0, 0, 0],
    [5, 6, 7]
], dtype=np.float)

lengths = np.linalg.norm(arr, axis=-1)
print(lengths)  # [ 3.74165739  0.         10.48808848]
arr[lengths > 0] = arr[lengths > 0] / lengths[lengths > 0][:, np.newaxis]
print(arr)
# [[0.26726124 0.53452248 0.80178373]
# [0.         0.         0.        ]
# [0.47673129 0.57207755 0.66742381]]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.