冗長性の少ないPythonで2次元のnumpy配列を正規化する方法は?


87

与えられた3×3numpy配列

a = numpy.arange(0,27,3).reshape(3,3)

# array([[ 0,  3,  6],
#        [ 9, 12, 15],
#        [18, 21, 24]])

私が考えた2次元配列の行を正規化するために

row_sums = a.sum(axis=1) # array([ 9, 36, 63])
new_matrix = numpy.zeros((3,3))
for i, (row, row_sum) in enumerate(zip(a, row_sums)):
    new_matrix[i,:] = row / row_sum

もっと良い方法があるはずですよね?

おそらく明確にするために:私が意味する正規化とは、行ごとのエントリの合計が1でなければなりません。しかし、それはほとんどの人にとって明らかだと思います。


17
注意してください、「正規化」は通常、成分の二乗和が1であることを意味します。あなたの定義はほとんどの人にとってほとんど明確ではありません;)
コールドフィックス2015

回答:


138

放送はこれに本当に適しています:

row_sums = a.sum(axis=1)
new_matrix = a / row_sums[:, numpy.newaxis]

row_sums[:, numpy.newaxis]row_sumsを存在(3,)から存在に再形成し(3, 1)ます。あなたがするときa / baそしてbお互いに対して放送されます。

あなたはここで放送 についてもっと学ぶことができます、あるいはここでさらによく学ぶことができます


29
これはa.sum(axis=1, keepdims=True)、シングルトン列のディメンションを維持するために使用するとさらに簡略化でき、を使用せずにブロードキャストできますnp.newaxis
ali_m 2015

6
row_sumsのいずれかがゼロの場合はどうなりますか?
asdf 2015

7
これは、上記の質問に対する正解ですが、通常の意味での正規化が必要な場合は、!のnp.linalg.norm代わりに使用してa.sumください。
コールドフィックス2015

1
これはより好ましいrow_sums.reshape(3,1)ですか?
ポール

1
行合計は0とすることができるので、それはのように堅牢ではない
番号

103

Scikit-learnには、さまざまな正規化を適用できる正規化関数があります。「合計を1にする」はL1の基準であり、それを行うには次のようにします。

from sklearn.preprocessing import normalize
matrix = numpy.arange(0,27,3).reshape(3,3).astype(numpy.float64)

#array([[  0.,   3.,   6.],
#   [  9.,  12.,  15.],
#   [ 18.,  21.,  24.]])

normed_matrix = normalize(matrix, axis=1, norm='l1')

#[[ 0.          0.33333333  0.66666667]
#[ 0.25        0.33333333  0.41666667]
#[ 0.28571429  0.33333333  0.38095238]]

これで、行の合計は1になります。


3
これには、密な配列としてメモリに収まらない疎な配列で機能するという利点もあります。
JEM_Mosig

10

これでうまくいくと思いますが、

a = numpy.arange(0,27.,3).reshape(3,3)

a /=  a.sum(axis=1)[:,numpy.newaxis]

2
良い。27に小数点を追加することによって、arangeにDTYPEの変更に注意してください
WIM

3

大きさが1になるように各行を正規化しようとしている場合(つまり、行の単位長が1であるか、行の各要素の2乗の合計が1である場合):

import numpy as np

a = np.arange(0,27,3).reshape(3,3)

result = a / np.linalg.norm(a, axis=-1)[:, np.newaxis]
# array([[ 0.        ,  0.4472136 ,  0.89442719],
#        [ 0.42426407,  0.56568542,  0.70710678],
#        [ 0.49153915,  0.57346234,  0.65538554]])

検証:

np.sum( result**2, axis=-1 )
# array([ 1.,  1.,  1.]) 

Axisはnp.linalg.normのパラメーターではないようです(もう?)。
ztyx 2014年

特に、これはl2ノルムに対応します(1に合計される行はl1ノルムに対応します)
dpb 2014年

3

これにより、行要素の合計を1に正規化できると思います new_matrix = a / a.sum(axis=1, keepdims=1)。また、列の正規化はで実行できますnew_matrix = a / a.sum(axis=0, keepdims=1)。これが肝にできることを願っています。


2

組み込みのnumpy関数を使用できます。 np.linalg.norm(a, axis = 1, keepdims = True)


1

これも機能するようです

def normalizeRows(M):
    row_sums = M.sum(axis=1)
    return M / row_sums


0

または、次のようなラムダ関数を使用します

>>> vec = np.arange(0,27,3).reshape(3,3)
>>> import numpy as np
>>> norm_vec = map(lambda row: row/np.linalg.norm(row), vec)

vecの各ベクトルには、単位ノルムがあります。


0

以下を使用するもう1つの可能な方法がありreshapeます:

a_norm = (a/a.sum(axis=1).reshape(-1,1)).round(3)
print(a_norm)

またはNone作品の使用も:

a_norm = (a/a.sum(axis=1)[:,None]).round(3)
print(a_norm)

出力

array([[0.   , 0.333, 0.667],
       [0.25 , 0.333, 0.417],
       [0.286, 0.333, 0.381]])

-2
normed_matrix = normalize(input_data, axis=1, norm='l1')
print(normed_matrix)

ここで、input_dataは2D配列の名前です

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.