2012-04-13 24 views
22

Tengo el siguiente código que intenta normalizar los valores de una matriz m x n (Se usará como entrada a una red neuronal, donde m es el número de ejemplos de capacitación y n es el número de características).Numpy modify array in place?

Sin embargo, cuando inspecciono la matriz en el intérprete después de ejecutar la secuencia de comandos, veo que los valores no están normalizados; es decir, todavía tienen los valores originales. Supongo que esto se debe a que la asignación a la variable array dentro de la función solo se ve dentro de la función.

¿Cómo puedo hacer esta normalización en su lugar? ¿O debo devolver una nueva matriz de la función normalizar?

import numpy 

def normalize(array, imin = -1, imax = 1): 
    """I = Imin + (Imax-Imin)*(D-Dmin)/(Dmax-Dmin)""" 

    dmin = array.min() 
    dmax = array.max() 

    array = imin + (imax - imin)*(array - dmin)/(dmax - dmin) 
    print array[0] 


def main(): 

    array = numpy.loadtxt('test.csv', delimiter=',', skiprows=1) 
    for column in array.T: 
     normalize(column) 

    return array 

if __name__ == "__main__": 
    a = main() 

Respuesta

19

Si desea aplicar operaciones matemáticas a una matriz numpy en el lugar, sólo tiene que utilizar el estándar en el lugar operadores +=, -=, /=, etc. Así, por ejemplo:

>>> def foo(a): 
...  a += 10 
... 
>>> a = numpy.arange(10) 
>>> a 
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 
>>> foo(a) 
>>> a 
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]) 
El

en el lugar versión de estas operaciones es un poco más rápido para el arranque, especialmente para los más grandes arrays:

>>> def normalize_inplace(array, imin=-1, imax=1): 
...   dmin = array.min() 
...   dmax = array.max() 
...   array -= dmin 
...   array *= imax - imin 
...   array /= dmax - dmin 
...   array += imin 
...  
>>> def normalize_copy(array, imin=-1, imax=1): 
...   dmin = array.min() 
...   dmax = array.max() 
...   return imin + (imax - imin) * (array - dmin)/(dmax - dmin) 
... 
>>> a = numpy.arange(10000, dtype='f') 
>>> %timeit normalize_inplace(a) 
10000 loops, best of 3: 144 us per loop 
>>> %timeit normalize_copy(a) 
10000 loops, best of 3: 146 us per loop 
>>> a = numpy.arange(1000000, dtype='f') 
>>> %timeit normalize_inplace(a) 
100 loops, best of 3: 12.8 ms per loop 
>>> %timeit normalize_copy(a) 
100 loops, best of 3: 16.4 ms per loop 
+0

¿Qué es '% timeit'? Eso parece interesante, ¿está incorporado? – User

+0

La versión que uso aquí solo está integrada en [ipython] (http://ipython.org/). Pero se basa en la función 'timeit' del módulo [' timeit'] (http://docs.python.org/library/timeit.html#module-timeit). – senderle

+0

Ah, finalmente miré ipython. Es curioso que siempre lo haya asociado con Ironpython, por error, ahora lo veo. – User

3
def normalize(array, imin = -1, imax = 1): 
    """I = Imin + (Imax-Imin)*(D-Dmin)/(Dmax-Dmin)""" 

    dmin = array.min() 
    dmax = array.max() 


    array -= dmin; 
    array *= (imax - imin) 
    array /= (dmax-dmin) 
    array += imin 

    print array[0] 
+0

En cuanto a rendimiento, ¿hay algún problema al hacerlo de esta manera? ¿Cómo se compara con crear una nueva matriz? – User

+0

Quiero decir, para eso tendrías que comparar. Depende del tamaño de la matriz. Para pequeños problemas, ciertamente crearía la nueva matriz. – ely

1

Hay una buena manera de hacer la normalización in situ cuando se usa numpy. np.vectorize es muy útil cuando se combina con una función lambda cuando se aplica a una matriz. Vea el ejemplo a continuación:

import numpy as np 

def normalizeMe(value,vmin,vmax): 

    vnorm = float(value-vmin)/float(vmax-vmin) 

    return vnorm 

imin = 0 
imax = 10 
feature = np.random.randint(10, size=10) 

# Vectorize your function (only need to do it once) 
temp = np.vectorize(lambda val: normalizeMe(val,imin,imax)) 
normfeature = temp(np.asarray(feature)) 

print feature 
print normfeature 

Se puede comparar el rendimiento con una expresión de generador, sin embargo, hay muchas otras maneras de hacerlo.

%%timeit 
temp = np.vectorize(lambda val: normalizeMe(val,imin,imax)) 
normfeature1 = temp(np.asarray(feature)) 
10000 loops, best of 3: 25.1 µs per loop 


%%timeit 
normfeature2 = [i for i in (normalizeMe(val,imin,imax) for val in feature)] 
100000 loops, best of 3: 9.69 µs per loop 

%%timeit 
normalize(np.asarray(feature)) 
100000 loops, best of 3: 12.7 µs per loop 

Así que vectorizar definitivamente no es el más rápido, pero puede ser conveniente en casos donde el rendimiento no es tan importante.

+0

Hace el trabajo, pero es muy lento ya que se implementa como un bucle for, de acuerdo con la documentación. – Michael

+0

¿Hay puntos de referencia para este tipo de cosas? Esperarías que vectorize pueda ayudarlo a ir mucho más rápido. – user48956

0

Este es un truco que es un poco más general que las otras respuestas útiles aquí:

def normalize(array, imin = -1, imax = 1): 
    """I = Imin + (Imax-Imin)*(D-Dmin)/(Dmax-Dmin)""" 

    dmin = array.min() 
    dmax = array.max() 

    array[...] = imin + (imax - imin)*(array - dmin)/(dmax - dmin) 

Aquí estamos asignando valores a la vista array[...] en lugar de asignar estos valores a una nueva variable local dentro del ámbito de la función.

x = np.arange(5, dtype='float') 
print x 
normalize(x) 
print x 

>>> [0. 1. 2. 3. 4.] 
>>> [-1. -0.5 0. 0.5 1. ]