Wie normalisiere ich ein zweidimensionales Numpy-Array in Python, das weniger ausführlich ist?

87

Gegeben ein 3 mal 3 numpy Array

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

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

Um die Zeilen des zweidimensionalen Arrays zu normalisieren, dachte ich daran

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

Es muss einen besseren Weg geben, nicht wahr?

Vielleicht zur Verdeutlichung: Mit Normalisierung meine ich, dass die Summe der Einträge pro Zeile eins sein muss. Aber ich denke, das wird den meisten Menschen klar sein.

Aufwind
quelle
16
Vorsichtig bedeutet "normalisieren" normalerweise, dass die quadratische Summe der Komponenten eins ist. Ihre Definition wird für die meisten Menschen kaum klar sein;)
Coldfix

Antworten:

134

Der Rundfunk ist dafür wirklich gut:

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

row_sums[:, numpy.newaxis]formt row_sums von Sein (3,)zu Sein um (3, 1). Wenn Sie das tun a / b, aund bsind gegeneinander ausgestrahlt.

Sie können erfahren Sie mehr über Rundfunk hier oder noch besser hier .

Bi Rico
quelle
26
Dies kann noch weiter vereinfacht werden, indem a.sum(axis=1, keepdims=True)die Dimension der Singleton-Spalte beibehalten wird, die Sie dann ohne Verwendung mitsenden können np.newaxis.
Ali_m
6
Was ist, wenn eine der row_sums Null ist?
asdf
7
Dies ist die richtige Antwort auf die oben angegebene Frage - aber wenn eine Normalisierung im üblichen Sinne gewünscht wird, verwenden Sie np.linalg.normstattdessen a.sum!
Coldfix
1
ist das vorzuziehen row_sums.reshape(3,1)?
Paul
1
Es ist nicht so robust, da die Zeilensumme 0 sein kann.
Nr.
102

Scikit-learn verfügt über eine Normalisierungsfunktion, mit der Sie verschiedene Normalisierungen anwenden können. Die "Summe auf 1 bringen" ist die L1-Norm, und um das zu tun, tun Sie Folgendes:

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

Jetzt summieren sich Ihre Zeilen zu 1.

rogueleaderr
quelle
3
Dies hat auch den Vorteil, dass es auf dünn besetzten Arrays funktioniert, die nicht als dichte Arrays in den Speicher passen würden.
JEM_Mosig
10

Ich denke das sollte funktionieren,

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

a /=  a.sum(axis=1)[:,numpy.newaxis]
tom10
quelle
2
gut. Beachten Sie die Änderung von dtype zu arange, indem Sie den Dezimalpunkt an 27
anhängen
3

Wenn Sie versuchen, jede Zeile so zu normalisieren, dass ihre Größe eins ist (dh die Einheitslänge einer Zeile ist eins oder die Summe des Quadrats jedes Elements in einer Zeile ist eins):

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

Überprüfen:

np.sum( result**2, axis=-1 )
# array([ 1.,  1.,  1.]) 
Walzer
quelle
Die Achse scheint kein Parameter für np.linalg.norm zu sein (mehr?).
Ztyx
Dies entspricht insbesondere der l2-Norm (wobei die auf 1 summierenden Zeilen der l1-Norm entsprechen)
dpb
3

Ich denke, Sie können die Summe der Zeilenelemente auf 1 normalisieren, indem Sie : new_matrix = a / a.sum(axis=1, keepdims=1). Und die Spaltennormalisierung kann mit durchgeführt werden new_matrix = a / a.sum(axis=0, keepdims=1). Hoffe das kann hep.

Snoopy
quelle
2

Sie können die integrierte Numpy-Funktion verwenden: np.linalg.norm(a, axis = 1, keepdims = True)

Saurabh Gupta
quelle
1

es scheint, dass dies auch funktioniert

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

Sie können auch die Matrixtransposition verwenden:

(a.T / row_sums).T
Maciek
quelle
0

Oder mit Lambda-Funktion, wie

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

Jeder Vektor von vec hat eine Einheitsnorm.

XY.W
quelle
-2
normed_matrix = normalize(input_data, axis=1, norm='l1')
print(normed_matrix)

Dabei ist input_data der Name Ihres 2D-Arrays

sonali b
quelle