NumPy dizisi belirli bir aralıkta nasıl normalleştirilir?


136

Bir ses veya görüntü dizisi üzerinde bazı işlemler yaptıktan sonra, bir dosyaya geri yazılmadan önce bir aralık içinde normalleştirilmesi gerekir. Bu şu şekilde yapılabilir:

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

Bunu yapmanın daha az ayrıntılı, kolaylık işlevi bir yolu var mı? matplotlib.colors.Normalize()ilişkili görünmüyor.

Yanıtlar:


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

Kullanılması /=ve *=böylece bazı bellek tasarrufu, bir ara geçici diziyi ortadan kaldırmak için izin verir. Çarpma, bölmeden daha ucuzdur, bu nedenle

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

marjinal olarak daha hızlıdır

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

Burada temel uyuşturma yöntemlerini kullandığımız için, bunun olabildiğince verimli bir çözümle ilgili olduğunu düşünüyorum.


Yerinde işlemler, kapsayıcı dizisinin dtipini değiştirmez. İstenen normalleştirilmiş değerler yüzer olduğundan, yerinde işlemler gerçekleştirilmeden önce audiove imagedizilerinin kayan noktalı dtype'ye sahip olması gerekir. Zaten kayan noktalı dtype değilse, bunları kullanarak dönüştürmeniz gerekir astype. Örneğin,

image = image.astype('float64')

7
Çarpma neden bölmeden daha ucuzdur?
endolith

19
Tam olarak neden bilmiyorum. Ancak, zamanla kontrol ettiğim için iddiaya güveniyorum. Çarpma ile bir seferde bir rakamla çalışabilirsiniz. Bölme ile, özellikle büyük bölenlerle, çok sayıda basamakla çalışmanız ve bölenin temettüye kaç kez gittiğini "tahmin etmeniz" gerekir. Tek bir bölme problemini çözmek için birçok çarpma problemi yaparsınız. Bölme yapmak için bilgisayar algoritması, insan uzun bölme ile aynı olmayabilir, ancak yine de bunun çarpmadan daha karmaşık olduğuna inanıyorum.
unutbu

14
Muhtemelen boş görüntüler için sıfıra bölmeden bahsetmeye değer.
cjm2671

7
@endolith çarpımı, Meclis düzeyinde uygulanma şekli nedeniyle bölmeden daha ucuzdur. Bölme algoritmaları ve çarpma algoritmaları paralelleştirilemez. en.wikipedia.org/wiki/Binary_multiplier
mjones.udri

5
Bölme sayısını çarpma lehine en aza indirmek, iyi bilinen bir optimizasyon tekniğidir.
mjones.udri

73

Dizi hem pozitif hem de negatif veriler içeriyorsa, şununla giderim:

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: don't forget the parenthesis before astype(int)
c = (255*(a - np.min(a))/np.ptp(a)).astype(int)        

# Normalised [-1,1]
d = 2.*(a - np.min(a))/np.ptp(a)-1

Dizi içeriyorsa nan, bir çözüm bunları şu şekilde kaldırmak olabilir:

def nan_ptp(a):
    return np.ptp(a[np.isfinite(a)])

b = (a - np.nanmin(a))/nan_ptp(a)

Bununla birlikte, bağlama bağlı olarak nanfarklı şekilde davranmak isteyebilirsiniz . Örneğin, değerin enterpolasyonunu yapın, örneğin 0 ile değiştirin veya bir hata oluşturun.

Son olarak, OP'nin sorusu olmasa da standardizasyondan bahsetmeye değer :

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

2
Ne istediğinize bağlı olarak, verileri ters çevirdiği için bu doğru değildir. Örneğin [0, 1] 'e normalleştirme, maks. 0 ve min değerini 1'e koyar. [0, 1] için, doğru normalizasyonu elde etmek için sonucu 1'den basitçe çıkarabilirsiniz.
Alan Turing

@AlanTuring çok özensiz olduğunu belirttiğiniz için teşekkürler. Gönderildiği şekliyle kod, YALNIZCA veriler hem pozitif hem de negatif değerler içeriyorsa çalışmıştır. Bu, ses verileri için oldukça yaygın olabilir. Ancak yanıt, gerçek değerleri normalleştirmek için güncellenir.
Tactopoda

1
Sonuncusu olarak da mevcuttur scipy.stats.zscore.
Lewistrick

d örneklerin işaretini tersine çevirebilir. İşareti tutmak istiyorsanız şunu kullanabilirsiniz: f = a / np.max(np.abs(a))... dizinin tamamı sıfır değilse (DivideByZero'dan kaçının).
Pimin Konstantin Kefaloukos

1
numpy.ptp()Bu aralıksa, ancak dizide nanbir tane varsa 0 döndürür nan. Ancak, aralık 0 ise, normalleştirme tanımlanmaz. Bu, 0 ile bölmeye çalışırken bir hataya neden olur.
Tactopoda

37

Ayrıca kullanarak yeniden ölçeklendirebilirsiniz sklearn. Avantajları, verileri ortalamaya ek olarak standart sapmayı normalleştirebilmeniz ve bunu her iki eksende, özelliklerle veya kayıtlarla yapabilmenizdir.

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

Anahtar kelime argümanlar axis, with_mean, with_stdkendini açıklayıcıdır ve varsayılan durumlarına gösterilmiştir. Bağımsız değişken copy, olarak ayarlanmışsa işlemi yerinde gerçekleştirir False. Belgeler burada .


X = ölçek ([1,2,3,4], axis = 0, with_mean = True, with_std = True, copy = True) bana bir hata veriyor
Yfiua

X = ölçek (np.array ([1,2,3,4]), axis = 0, with_mean = True, with_std = True, copy = True) bana bir [0,0,0,0] dizisi veriyor
Yfiua

sklearn.preprocessing.scale (), neler olup bittiğini bilmediğiniz bir geri çekime sahiptir. Faktör nedir? Aralığın hangi sıkıştırması?
MasterControlProgram

Bu scikit ön işleme yöntemlerinin (ölçek, minmax_scale, maxabs_scale) yalnızca bir eksen boyunca kullanılması amaçlanmıştır (yani örnekleri (satırları) veya özellikleri (sütunları) ayrı ayrı ölçeklendirin. Bu, makine öğrenen bir kurulumda mantıklıdır, ancak bazen tüm dizi üzerindeki aralığı hesaplamak veya ikiden fazla boyuta sahip dizileri kullanmak için.
Toby

11

"İ" (idiv, imul ..'deki gibi) sürümünü kullanabilirsiniz ve yarı kötü görünmüyor:

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

Diğer durum için, n boyutlu bir diziyi sütunlara göre normalleştirmek için bir işlev yazabilirsiniz:

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

Bunu açıklayabilir misin? Parantezler, olmadan farklı davranmasını sağlar.
endolith

1
parantezler hiçbir şeyi değiştirmez. /== .. / ..
amaç

7

audio-1 ile +1 ve image0 ile 255 arasındaki değerleri min-max ölçeklendirmeye çalışıyorsunuz .

Kullanmak sklearn.preprocessing.minmax_scale, probleminizi kolayca çözmelidir.

Örneğin:

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

ve

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

not : Bir vektörün normunu (uzunluğunu) belirli bir değere (genellikle 1) ölçekleyen işlemle karıştırılmamalıdır , bu aynı zamanda genellikle normalleştirme olarak da adlandırılır.


4

Sklearn.preprocessing kitaplığı tarafından sunulan ölçekleyicileri kullanmak basit bir çözümdür.

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)

X_rec-X hatası sıfır olacaktır. Özellik aralığını ihtiyaçlarınıza göre ayarlayabilir veya hatta standart bir ölçekleyici skaler kullanabilirsiniz.


3

Aşağıdaki çalıştı bu ve hata var

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

numpyBen normalize etmeye çalışıyordu dizi bir oldu integerdizi. Görünüşe göre sürümlerde tür atamasını kaldırmışlar 1.10ve bunu numpy.true_divide()çözmek için kullanmanız gerekiyor.

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

imgbir PIL.Imagenesneydi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.