2012-01-18 60 views
59

dado un 3 veces 3 numpy gama¿Cómo normalizar una matriz numpy bidimensional en python menos detallada?

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

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

Para normalizar las filas de la matriz de 2 dimensiones pensé en

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 

Tiene que haber una manera mejor, ¿no es verdad?

Quizás para aclarar: Al normalizar, quiero decir, la suma de las entradas por fila debe ser una. Pero creo que eso será claro para la mayoría de la gente.

+6

cuidadosa, "normalizar" generalmente significa la plaza * * suma de los componentes es uno. Su definición difícilmente será clara para la mayoría de la gente;) – coldfix

Respuesta

82

radiodifusión es muy bueno para esto:

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

row_sums[:, numpy.newaxis] remodela row_sums de ser (3,) de ser (3, 1). Cuando lo haga a/b, a y b se transmiten uno contra el otro.

Usted puede aprender más sobre difusiónhere o incluso mejor here.

+0

¡muchas gracias! – Aufwind

+8

Esto se puede simplificar aún más usando 'a.sum (axis = 1, keepdims = True)' para mantener la dimensión de la columna singleton, que luego puede transmitir sin tener que usar 'np.newaxis'. –

+3

¿Qué pasa si alguno de los row_sums es cero? – asdf

7

Creo que esto debería funcionar,

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

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

bien. observe el cambio de dtype a arange, agregando punto decimal a 27. – wim

51

scikit-learn tiene una función Normalizar que permite aplicar diferentes normalizaciones. El "hacen que sea sumar a 1" es la norma L1, y para tomar esa Do:

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

Ahora sus filas se suma a 1.

+5

Finalmente una respuesta que muestra la salida ... –

0

En caso de que usted está tratando de normalizar cada fila de modo que su magnitud es uno (es decir unidad de longitud de una fila es una o la suma del cuadrado de cada elemento en una fila es una):

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

Verificación:

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

Axis no parece ser un parámetro para np.linalg.norm (¿más?). – Ztyx

+0

Funciona en python 2.7. – walt

+0

notablemente esto corresponde a la norma l2 (donde como las filas que suman a 1 corresponde a la norma l1) – dpb

1

parece que esto también funciona

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

O usando la función lambda, como

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

cada vector de vec tendrá una norma unidad.

0

También es posible usar la transposición de la matriz:

(a.T/row_sums).T 
Cuestiones relacionadas