NumPy配列を特定の範囲内に正規化する方法は?


136

オーディオまたは画像配列で処理を行った後、ファイルに書き戻す前に、範囲内で正規化する必要があります。これは次のように行うことができます:

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

これを行うための冗長ではない便利な関数の方法はありますか?matplotlib.colors.Normalize()関係がないようです。

回答:


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

を使用する/=*=、中間の一時配列を削除できるため、メモリをいくらか節約できます。乗算は除算よりも安価なので、

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

よりわずかに速い

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

ここでは基本的なnumpyメソッドを使用しているので、これは可能な限りnumpyでの効率的なソリューションだと思います。


インプレース操作では、コンテナー配列のdtypeは変更されません。目的の正規化された値は浮動小数点数であるため、インプレース演算を実行する前に、audioおよびimage配列に浮動小数点dtypeが必要です。それらがまだ浮動小数点dtypeでない場合は、を使用して変換する必要がありますastype。例えば、

image = image.astype('float64')

7
乗算は除算よりも安価なのはなぜですか?
内部石

19
理由は正確にはわかりません。しかし、私は時宜を得てそれをチェックしたので、私は主張を確信しています。乗算を使用すると、一度に1桁を処理できます。除算では、特に大きな除数では、多くの桁を処理し、除数が被除数に入る回数を「推測」する必要があります。1つの除算問題を解決するために、多くの乗算問題を実行することになります。除算を行うためのコンピューターアルゴリズムは、人間の長い除算と同じではないかもしれませんが、それでも、乗算よりも複雑だと思います。
unutbu 2009年

14
おそらく空白の画像のゼロ除算について言及する価値があります。
cjm2671 14年

7
@endolith乗算は、アセンブリレベルでの実装方法により、除算よりも安価です。除算アルゴリズムは、乗算アルゴリズムと同様に並列化できません。en.wikipedia.org/wiki/Binary_multiplier
mjones.udri

5
乗算を優先して除算の数を最小限に抑えることは、よく知られている最適化手法です。
mjones.udri

73

配列に正と負の両方のデータが含まれている場合は、次のようにします。

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

配列にが含まれている場合のnan解決策の1つは、次のように削除することです。

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

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

ただし、状況によっては、nan別の方法で処理する必要があります。たとえば、値を補間して、たとえば0に置き換えたり、エラーを発生させます。

最後に、OPの質問でなくても言及する価値があります。標準化

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

2
必要に応じて、データが反転するため、これは正しくありません。たとえば、[0、1]に正規化すると、最大値が0になり、最小値が1になります。[0、1]の場合、1から結果を差し引くだけで、正しい正規化を得ることができます。
アランチューリング

@AlanTuringを指摘してくれてありがとう。投稿されたコードは、データに正と負の両方の値が含まれている場合にのみ機能しました。これは、オーディオデータではかなり一般的です。ただし、答えは実際の値を正規化するように更新されます。
タクトポダ

1
最後のものはとしても利用できますscipy.stats.zscore
Lewistrick

dはサンプルの符号を反転する場合があります。符号を保持したい場合は、次のように使用できますf = a / np.max(np.abs(a))。...配列全体がすべてゼロでない場合(DivideByZeroを避けます)。
Pimin Konstantin Kefaloukos

1
numpy.ptp()範囲の場合は0を返しますが、配列にnan1つの場合は0を返しますnan。ただし、範囲が0の場合、正規化は定義されていません。我々は0で除算しようとすると、これはエラーを発生させます
Tactopoda

37

を使用して再スケーリングすることもできsklearnます。利点は、データを平均中心化することに加えて、標準偏差を正規化して調整できること、およびこれを軸ごと、フィーチャごと、またはレコードごとに実行できることです。

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

キーワード引数はaxiswith_meanwith_std自明であり、そのデフォルト状態で示されています。にcopy設定されてFalseいる場合、引数は操作をインプレースで実行します。ドキュメントはこちら


X = scale([1,2,3,4]、axis = 0、with_mean = True、with_std = True、copy = True)はエラー
Yfiua

X = scale(np.array([1,2,3,4])、axis = 0、with_mean = True、with_std = True、copy = True)は[0,0,0,0]の配列を返します
イフィウア

sklearn.preprocessing.scale()には何が起こっているのか分からないバックドローがあります。要因は何ですか?間隔のどの圧縮?
MasterControlProgram 2016年

これらのscikit前処理メソッド(scale、minmax_scale、maxabs_scale)は、1つの軸に沿ってのみ使用されることを意図しています(したがって、サンプル(行)または機能(列)を個別にスケーリングします。これは、マシンリーリングセットアップでは理にかなっていますが、配列全体の範囲を計算するか、2次元を超える配列を使用する
Toby

11

"i"(idiv、imul ..のように)バージョンを使用できますが、見た目は悪くありません。

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

その他の場合は、列によってn次元配列を正規化する関数を記述できます。

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

これを明確にできますか?かっこは、それがない場合とは異なる動作をしますか?
内部石

1
括弧は何も変更しません。/=代わりに使用することが ポイントでした= .. / ..
u0b34a0f6ae 2009年

7

audio-1〜+1のimage間および0〜255の間の値をmin-maxスケールしようとしています。

を使用sklearn.preprocessing.minmax_scaleすると、問題を簡単に解決できます。

例えば:

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

そして

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

:ベクトルのノルム(長さ)を特定の値(通常は1)にスケーリングする操作と混同しないでください。これは一般に正規化とも呼ばれます。


4

簡単な解決策は、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)

エラーX_rec-Xはゼロになります。必要に応じてfeature_rangeを調整するか、標準のスケーラーsk.StandardScaler()を使用することもできます


3

私はこれを試してみましたが、エラーが発生しました

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

numpy私は正常化するためにしようとしていた配列をしたinteger配列。バージョンでの型キャストは非推奨であるようです> 1.10、それnumpy.true_divide()を解決するには使用する必要があります。

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

imgPIL.Imageオブジェクトが。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.