2012-01-18 3 views
59

Dato un 3 volte 3 NumPy matriceCome normalizzare un array numpy bidimensionale in python meno dettagliato?

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

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

Per normalizzare le righe della matrice 2-dimensionale ho pensato

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 

Ci deve essere un modo migliore, non c'è?

Forse per chiarire: Con la normalizzazione intendo, la somma degli accessi per riga deve essere uno. Ma penso che sarà chiaro alla maggior parte delle persone.

+6

attenzione, "normalizzare" di solito significa il quadrato * * somma dei componenti è uno. La tua definizione difficilmente sarà chiara alla maggior parte delle persone;) – coldfix

risposta

82

Broadcasting è veramente buono per questo:

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

row_sums[:, numpy.newaxis] rimodella row_sums dall'essere (3,) ad essere (3, 1). Quando si esegue a/b, a e b vengono trasmessi l'uno contro l'altro.

Ulteriori informazioni sulla trasmissione here o anche meglio here.

+0

grazie mille! – Aufwind

+8

Questo può essere ulteriormente semplificato usando 'a.sum (axis = 1, keepdims = True)' per mantenere la dimensione della colonna singleton, che può essere poi trasmessa senza dover usare 'np.newaxis'. –

+3

cosa succede se qualcuno dei row_sums è zero? – asdf

7

Penso che questo dovrebbe funzionare,

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

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

buono. nota il cambio di dtype in arange, aggiungendo il punto decimale a 27. – wim

51

scikit-learn ha una funzione normalizzare che consente di applicare varie normalizzazioni. Il "rendono somma da 1" è la norma L1, ed a prendere che:

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

Ora le righe si somma a 1.

+5

Infine una risposta che mostra l'output ... –

0

Nel caso in cui si sta tentando di normalizzare ogni riga tale che la sua grandezza è uno (cioè unità di lunghezza di una fila è uno o la somma del quadrato di ciascun elemento in una riga è uno):

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

Verifica:

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

L'asse non sembra essere un parametro per np.linalg.norm (più?). – Ztyx

+0

Funziona in python 2.7. – walt

+0

in particolare questo corrisponde alla norma l2 (dove le righe sommando a 1 corrisponde alla norma l1) – dpb

1

sembra che questo funziona anche

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

o utilizzando la funzione lambda, come

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

ogni vettore di VEC avrà una norma unità.

0

Si potrebbe anche usare matrice trasposizione:

(a.T/row_sums).T