Como normalizar uma matriz Numpy para dentro de um determinado intervalo?
-
20-09-2019 - |
Pergunta
Depois de fazer algum processamento em uma matriz de áudio ou imagem, ele precisa ser normalizado dentro de um intervalo antes de ser gravado de volta para um arquivo. Isso pode ser feito assim:
# 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)
Existe uma maneira menos detalhada da função de conveniência de fazer isso? matplotlib.colors.Normalize()
não parece estar relacionado.
Solução
audio /= np.max(np.abs(audio),axis=0)
image *= (255.0/image.max())
Usando /=
e *=
Permite eliminar uma matriz temporária intermediária, economizando alguma memória. A multiplicação é mais barata que a divisão, então
image *= 255.0/image.max() # Uses 1 division and image.size multiplications
é marginalmente mais rápido que
image /= image.max()/255.0 # Uses 1+image.size divisions
Como estamos usando métodos básicos de Numpy aqui, acho que é uma solução tão eficiente quanto possível.
As operações no local não alteram o DTYPE da matriz de contêineres. Como os valores normalizados desejados são flutuantes, o audio
e image
As matrizes precisam ter o ponto de ponto flutuante DTYPE antes que as operações no local sejam executadas. Se eles ainda não são de Dtype de ponto flutuante, você precisará convertê-los usando astype
. Por exemplo,
image = image.astype('float64')
Outras dicas
Se a matriz contiver dados positivos e negativos, eu iria com:
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
Além disso, vale a pena mencionar mesmo que não seja a pergunta do OP, estandardização:
e = (a - np.mean(a)) / np.std(a)
Você também pode redimensionar usando sklearn
. As vantagens são que você pode ajustar normalizar o desvio padrão, além de centrar os dados e que você pode fazer isso no eixo, por recursos ou por registros.
from sklearn.preprocessing import scale
X = scale( X, axis=0, with_mean=True, with_std=True, copy=True )
Os argumentos da palavra -chave axis
, with_mean
, with_std
são auto -explicativos e são mostrados em seu estado padrão. O argumento copy
executa a operação no local se estiver definida como False
. Documentação aqui.
Você pode usar a versão "I" (como na IDIV, Imul ..), e não parece tão ruim:
image /= (image.max()/255.0)
Para o outro caso, você pode escrever uma função para normalizar uma matriz n-dimensional da Colums:
def normalize_columns(arr):
rows, cols = arr.shape
for col in xrange(cols):
arr[:,col] /= abs(arr[:,col]).max()
Uma solução simples é usar os Sconers oferecidos pela Biblioteca Sklearn.Precessing.
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)
O erro x_rec-x será zero. Você pode ajustar o recurso_Range para suas necessidades ou até mesmo usar um scaler scaler sk.standardscaler ()
Você está tentando escalar min-max os valores de audio
entre -1 e +1 e image
entre 0 e 255.
Usando sklearn.preprocessing.minmax_scale
, deve resolver facilmente seu problema.
por exemplo:
audio_scaled = minmax_scale(audio, feature_range=(-1,1))
e
shape = image.shape
image_scaled = minmax_scale(image.ravel(), feature_range=(0,255)).reshape(shape)
Nota: Não deve ser confundido com a operação que escala o norma (comprimento) de um vetor a um determinado valor (geralmente 1), que também é comumente referido como normalização.
Eu tentei seguir isto, e obteve o erro
TypeError: ufunc 'true_divide' output (typecode 'd') could not be coerced to provided output parameter (typecode 'l') according to the casting rule ''same_kind''
o numpy
Array que eu estava tentando normalizar era um integer
variedade. Parece que eles depreciaram o tipo de fundição em versões> 1.10
, e você tem que usar numpy.true_divide()
para resolver isso.
arr = np.array(img)
arr = np.true_divide(arr,[255.0],out=None)
img
eram um PIL.Image
objeto.