Jak znormalizować dwuwymiarową tablicę numpy w Pythonie mniej gadatliwym?


87

Biorąc pod uwagę tablicę numpy 3 razy 3

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

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

Aby znormalizować wiersze dwuwymiarowej tablicy, o której myślałem

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

Musi być lepszy sposób, prawda?

Być może dla wyjaśnienia: przez normalizację mam na myśli, że suma wpisów na wiersz musi wynosić jeden. Ale myślę, że dla większości ludzi będzie to jasne.


17
Ostrożnie, „normalizuj” zwykle oznacza, że suma kwadratowa składników wynosi jeden. Twoja definicja nie będzie jasna dla większości ludzi;)
coldfix

Odpowiedzi:


138

Nadawanie jest naprawdę dobre do tego:

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

row_sums[:, numpy.newaxis]przekształca sumy_wierszów z bycia (3,)w bycie (3, 1). Kiedy to robisz a / b, ai bsą nadawane przeciwko sobie.

Możesz dowiedzieć się więcej o nadawaniu tutaj, a nawet lepiej tutaj .


29
Można to jeszcze bardziej uprościć, a.sum(axis=1, keepdims=True)zachowując wymiar pojedynczej kolumny, którą można następnie transmitować bez konieczności używania np.newaxis.
ali_m

6
co się stanie, jeśli którakolwiek z sum_wierszów wynosi zero?
asdf

7
To jest poprawna odpowiedź na powyższe pytanie - ale jeśli pożądana jest normalizacja w zwykłym sensie, użyj np.linalg.normzamiast a.sum!
coldfix

1
czy to jest preferowane row_sums.reshape(3,1)?
Paweł,

1
Nie jest tak solidna, ponieważ suma wierszy może wynosić 0.
nr

103

Scikit-learn ma funkcję normalizacji, która umożliwia stosowanie różnych normalizacji. „Zrób to sumę do 1” to norma L1, i aby to zrobić:

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

Teraz twoje wiersze będą sumowane do 1.


3
Ma to również tę zaletę, że działa na rzadkich tablicach, które nie pasowałyby do pamięci jako tablice gęste.
JEM_Mosig

10

Myślę, że to powinno działać,

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

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

2
dobry. zwróć uwagę na zmianę typu dtype na arange, dodając kropkę dziesiętną do 27.
wim

4

W przypadku, gdy próbujesz znormalizować każdy wiersz w taki sposób, aby jego wielkość wynosiła jeden (tj. Długość jednostki wiersza wynosi jeden lub suma kwadratów każdego elementu w wierszu wynosi jeden):

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

Weryfikacja:

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

Axis nie wydaje się być parametrem np.linalg.norm (już?).
Ztyx

w szczególności odpowiada to normie l2 (gdzie jako wiersze sumujące się do 1 odpowiada normie l1)
dpb

3

Myślę, że można znormalizować sumę elementów wiersz na 1 przez to: new_matrix = a / a.sum(axis=1, keepdims=1). I normalizację kolumny można wykonać za pomocą new_matrix = a / a.sum(axis=0, keepdims=1). Mam nadzieję, że to może pomóc.



1

wydaje się, że to też działa

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

1

Możesz również użyć transpozycji macierzy:

(a.T / row_sums).T

0

Lub używając funkcji lambda, takiej jak

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

każdy wektor vec będzie miał normę jednostkową.


0

Oto jeszcze jeden możliwy sposób użycia reshape:

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

Lub też używanie Nonedziała:

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

Wyjście :

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)

gdzie dane_wejściowe to nazwa tablicy 2D

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.