¿Cómo normalizar una matriz NumPy dentro de un cierto rango?

Después de realizar un procesamiento en una matriz de audio o imagen, debe normalizarse dentro de un rango antes de que se pueda escribir de nuevo en un archivo. Esto se puede hacer así:

# Normalize audio channels to between -1.0 and +1.0 audio[:,0] = audio[:,0]/abs(audio[:,0]).max() audio[:,1] = audio[:,1]/abs(audio[:,1]).max() # Normalize image to between 0 and 255 image = image/(image.max()/255.0) 

¿Hay una forma de verosimilitud y funcionalidad para hacer esto? matplotlib.colors.Normalize() no parece estar relacionado.

 audio /= np.max(np.abs(audio),axis=0) image *= (255.0/image.max()) 

El uso de /= y *= permite eliminar una matriz temporal intermedia, ahorrando así algo de memoria. La multiplicación es menos costosa que la división, por lo que

 image *= 255.0/image.max() # Uses 1 division and image.size multiplications 

es ligeramente más rápido que

 image /= image.max()/255.0 # Uses 1+image.size divisions 

Ya que estamos usando métodos básicos de numpy aquí, creo que esta es una solución tan eficiente en cuanto a numpy como puede ser.

También puedes sklearn escalar usando sklearn . Las ventajas son que puede ajustar normalizar la desviación estándar, además de centrar la media en los datos, y que puede hacer esto en cualquiera de los ejes, por características o por registros.

 from sklearn.preprocessing import scale X = scale( X, axis=0, with_mean=True, with_std=True, copy=True ) 

Los axis argumentos de palabras clave, with_mean , with_std se explican por sí mismos y se muestran en su estado predeterminado. La copy argumento realiza la operación en el lugar si se establece en False . Documentación aquí .

Si la matriz contiene datos positivos y negativos, me gustaría ir con:

 import numpy as np a = np.random.rand(3,2) # Normalised [0,1] b = (a - np.min(a))/np.ptp(a) # Normalised [0,255] as integer c = 255*(a - np.min(a))/np.ptp(a).astype(int) # Normalised [-1,1] d = 2*(a - np.min(a))/np.ptp(a)-1 

También, vale la pena mencionar, incluso si no es la pregunta de OP, la estandarización :

 e = (a - np.mean(a)) / np.std(a) 

Puedes usar la versión “i” (como en idiv, imul ..), y no se ve nada mal:

 image /= (image.max()/255.0) 

Para el otro caso, puede escribir una función para normalizar una matriz n-dimensional por columnas:

 def normalize_columns(arr): rows, cols = arr.shape for col in xrange(cols): arr[:,col] /= abs(arr[:,col]).max() 

Una solución simple es usar los escaladores ofrecidos por la biblioteca sklearn.preprocessing.

 scaler = sk.MinMaxScaler(feature_range=(0, 250)) scaler = scaler.fit(X) X_scaled = scaler.transform(X) # Checking reconstruction X_rec = scaler.inverse_transform(X_scaled) 

El error X_rec-X será cero. Puede ajustar el feature_range para sus necesidades, o incluso usar un escalador estándar sk.StandardScaler ()

Intenté seguir esto y me salió el error.

 TypeError: ufunc 'true_divide' output (typecode 'd') could not be coerced to provided output parameter (typecode 'l') according to the casting rule ''same_kind'' 

La matriz numpy que intentaba normalizar era una matriz integer . Parece que rechazaron la conversión de tipos en versiones> 1.10 , y tienes que usar numpy.true_divide() para resolver eso.

 arr = np.array(img) arr = np.true_divide(arr,[255.0],out=None) 

img era un objeto PIL.Image .

Está intentando escalar los valores de audio entre -1 y +1 de min-max y la image entre 0 y 255.

El uso de sklearn.preprocessing.minmax_scale debería resolver fácilmente su problema.

p.ej:

 audio_scaled = minmax_scale(audio, feature_range=(-1,1)) 

y

 shape = image.shape image_scaled = minmax_scale(image.ravel(), feature_range=(0,255)).reshape(shape) 

nota : personalmente no llamaría a la operación que está intentando realizar la normalización . La normalización se refiere más comúnmente a la operación que estandariza la norma (longitud) de un vector a un cierto valor (generalmente 1), no su rango de valores.