Comment normaliser un tableau numpy à l'intérieur d'une certaine plage?
-
20-09-2019 - |
Question
Après avoir fait un peu de traitement sur un tableau audio ou image, il doit être normalisé dans une plage avant de pouvoir être réécrites dans un fichier. Cela peut se faire comme ceci:
# 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)
Y at-il une façon moins bavard, la fonction de commodité pour le faire? matplotlib.colors.Normalize()
ne semble pas être liée.
La solution
audio /= np.max(np.abs(audio),axis=0)
image *= (255.0/image.max())
Utilisation /=
et *=
vous permet d'éliminer un tableau temporaire intermédiaire, économisant ainsi de la mémoire. La multiplication est moins cher que la division, donc
image *= 255.0/image.max() # Uses 1 division and image.size multiplications
est légèrement plus rapide que
image /= image.max()/255.0 # Uses 1+image.size divisions
Puisque nous utilisons des méthodes de numpy de base ici, je pense que cela est sur une solution aussi efficace dans numpy que possible.
Opérations en place ne changent pas la DTYPE du tableau de conteneurs. Etant donné que les valeurs normalisées souhaitées sont flotteurs, les tableaux de audio
et image
doivent avoir le point à virgule flottante DTYPE avant que les opérations sont effectuées en place.
Si elles ne sont pas déjà de DTYPE à virgule flottante, vous aurez besoin de les convertir à l'aide astype
. Par exemple,
image = image.astype('float64')
Autres conseils
Si le tableau contient à la fois des données positives et négatives, je partirais avec:
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
En outre, de mentionner, même si ce n'est pas question de l'OP, normalisation :
e = (a - np.mean(a)) / np.std(a)
Vous pouvez également rééchelonner en utilisant sklearn
. Les avantages sont que vous pouvez régler normalise l'écart-type, en plus de moyenne-centrage des données, et que vous pouvez le faire sur l'un des axes, par des caractéristiques ou par des enregistrements.
from sklearn.preprocessing import scale
X = scale( X, axis=0, with_mean=True, with_std=True, copy=True )
Les arguments de mot-clé axis
, with_mean
, with_std
sont explicites et sont présentés dans leur état par défaut. Le copy
argument effectue l'opération en place si elle est définie à False
. Documentation .
Vous pouvez utiliser le "i" la version (comme dans IDIV, imul ..), et il ne semble pas mal:
image /= (image.max()/255.0)
Pour l'autre cas, vous pouvez écrire une fonction de normaliser un tableau de n dimensions par colums:
def normalize_columns(arr):
rows, cols = arr.shape
for col in xrange(cols):
arr[:,col] /= abs(arr[:,col]).max()
Une solution simple utilise les détartreurs offerts par la bibliothèque 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)
L'erreur X_rec-X sera égal à zéro. Vous pouvez régler la feature_range pour vos besoins, ou même utiliser un scaler standart sk.StandardScaler ()
Vous essayez d'échelle min-max les valeurs de audio
entre -1 et +1 et image
entre 0 et 255.
Utilisation sklearn.preprocessing.minmax_scale
, devrait facilement résoudre votre problème.
par exemple:.
audio_scaled = minmax_scale(audio, feature_range=(-1,1))
et
shape = image.shape
image_scaled = minmax_scale(image.ravel(), feature_range=(0,255)).reshape(shape)
Remarque : À ne pas confondre avec l'opération qui redimensionne le norme (longueur) d'un vecteur à une certaine valeur (généralement 1), qui est également communément appelé normalisation.
J'ai essayé cette , et a obtenu l'erreur
TypeError: ufunc 'true_divide' output (typecode 'd') could not be coerced to provided output parameter (typecode 'l') according to the casting rule ''same_kind''
Le tableau de numpy
je tentais de normaliser était un tableau de integer
. Il semble qu'ils déconseillés clichage dans les versions> 1.10
, et vous devez utiliser numpy.true_divide()
pour résoudre ce problème.
arr = np.array(img)
arr = np.true_divide(arr,[255.0],out=None)
img
était un objet PIL.Image
.