前の記事の最後で、
異常時の前処理として、1〜99パーセンタイルでクリップするって話を少し書いたので、
それをnumpyで実現する関数の紹介です。
と言っても、わざわざ専用関数を使わなくても容易に実装できるのですが、せっかく用意されているのがあるので知っておくと便利です。
ドキュメントはこちら。
numpy.clip
np.clip(配列, 最小値, 最大値)
と指定すると、
配列の値のうち、区間[最小値, 最大値]からはみ出た値を、その範囲に収まるように区切ってくれます。
ためしに、標準正規分布に従う値20個を生成して、[-1, 1]の範囲にクリッピングしてみましょう。
import numpy as np
data = np.random.randn(20)
print(data)
'''
[-1.71434343 0.33093523 -0.0648882 1.34432289 -0.15426638 -1.05988754
-0.41423379 -0.8896041 0.12403786 1.40810052 0.61199047 1.60193951
-0.72897283 -0.00861939 -0.38774556 0.40188148 0.08256356 1.61743754
-0.12320721 1.45184382]
'''
data = np.clip(data, -1, 1)
print(data)
'''
[-1. 0.33093523 -0.0648882 1. -0.15426638 -1.
-0.41423379 -0.8896041 0.12403786 1. 0.61199047 1.
-0.72897283 -0.00861939 -0.38774556 0.40188148 0.08256356 1.
-0.12320721 1. ]
'''
-1 より小さかった値は-1に、 1より大きかった値は1になりました。
ちなみに下記のコードでも同じことができます。
data[data < -1] = -1
data[data > 1] = 1
前回紹介した、percentileと組み合わせて使うことで、
nパーセンタイルからmパーセンタイルにクリップするということも簡単に実現できます。
試しに 5〜95パーセンタイルにクリップしたのが次のコードです。
data = np.random.randn(10)
print(data)
'''
[-0.41127091 -1.34043164 0.09598778 -1.19662011 -0.04607188 -0.02745831
0.23184919 0.85601106 0.58430572 0.88205005]
'''
c_min, c_max = np.percentile(data, [5, 95])
print(c_min, c_max)
'''
-1.2757164503037743 0.8703325037861378
'''
data = np.clip(data, c_min, c_max)
'''
[-0.41127091 -1.27571645 0.09598778 -1.19662011 -0.04607188 -0.02745831
0.23184919 0.85601106 0.58430572 0.8703325 ]
'''
print(data)
この例だけ見てもありがたみを感じないのですが、実際のデータを決定木などにかける時、
ほんの数件のデータだけ極端な外れ値になっていたりすると、
いい感じの範囲にデータを収めることができるので便利です。
また、scikit-learnなどのライブラリのコードを見てみると、
値を 0より大きく1より小さい範囲に収める目的などでも使われています。
ここなど。
n以上m以下、ではなくnより大きいmより小さい、で区切る時は便宜上、eps=1e-15
のような非常に小さい値を用意して、
[n+eps, m-eps]で代用するようですね。
こういう書き方も参考になります。