統計学において、他の値から大きく外れた値のことを外れ値というが、あるデータセットからこの外れ値を検出する方法を今回は紹介する。
コンテンツ
サンプルデータの用意
まずはサンプルとして、1000行・4列の正規分布をした乱数の入ったデータフレームを用意する。
import pandas as pd
df = pd.DataFrame(np.random.randn(1000, 4))
データフレームに対し、describeメソッドを実行し各種統計データを確認してみよう。
df.describe()
# 0 1 2 3
# count 1000.000000 1000.000000 1000.000000 1000.000000
# mean 0.061963 -0.018152 -0.009255 -0.071885
# std 0.981119 1.003547 1.025437 1.036963
# min -3.561692 -3.090631 -3.084243 -3.396022
# 25% -0.573395 -0.710958 -0.747221 -0.788857
# 50% 0.055481 -0.027430 0.002876 -0.059368
# 75% 0.702462 0.664116 0.688545 0.624966
# max 3.102698 3.604496 3.354750 2.952821
外れ値を検出する
今回4つの列を用意したが、まずはそのうち一つから外れ値を検出してみる。
例として、外れ値を絶対値3以上と設定して考える。
data = df[2]
data[np.abs(data > 3)]
# 453 3.164858
# 572 3.360151
# 979 3.459101
# Name: 2, dtype: float64
上記の例では3つの外れ値が見つかった。
外れ値を持つ行を選択する
次は絶対値3以上の外れ値を一つでも持つ行を全て選択してみる。
data = df[(np.abs(df) > 3).any(1)]
print(data)
# 0 1 2 3
# 138 0.541298 0.018690 -0.262796 -3.301846
# 143 -2.993869 0.656929 1.150055 3.275890
# 221 -2.262992 0.022498 3.085838 0.669413
# 374 -1.625388 0.352799 3.252707 -0.709602
# 417 3.058626 -0.454211 0.418938 -0.363925
# 773 -1.074662 -0.137747 -3.461462 1.753082
# 971 3.813151 -0.544527 1.194872 -1.384824
# 981 -0.996548 -3.589028 -0.538962 -2.114824
# 993 0.087114 3.100599 0.895598 0.642445
外れ値を別の値に変換する
検出した外れ値を別の値に変換する例も紹介しておこう。
df[np.abs(df) > 3] = np.sign(df) * 3
df.describe()
# 0 1 2 3
# count 1000.000000 1000.000000 1000.000000 1000.000000
# mean -0.008462 0.034518 -0.032374 0.004564
# std 1.028697 1.003309 1.019777 0.990512
# min -2.820792 -3.000000 -3.000000 -3.000000
# 25% -0.705405 -0.676406 -0.722525 -0.675062
# 50% -0.024764 0.058775 -0.054462 -0.031949
# 75% 0.662883 0.712612 0.625067 0.673057
# max 3.000000 2.813415 3.000000 2.814021
上記のコードで、np.sign(df)という文があるが、これは引数の値の正負に応じて「1」または「-1」を返す。
headメソッドで最初の5行を取り出してみたが、こうして見ると分かりやすいだろう。
df.head()
# 0 1 2 3
# 0 -0.622233 -0.614729 1.845212 -0.801630
# 1 0.617012 -0.554088 0.634067 0.676856
# 2 0.165701 0.235992 -1.468626 0.638006
# 3 0.933732 1.353240 0.301985 -0.045967
# 4 -0.682327 -0.790911 -1.655082 -1.581637
np.sign(df).head()
# 0 1 2 3
# 0 -1.0 -1.0 1.0 -1.0
# 1 1.0 -1.0 1.0 1.0
# 2 1.0 1.0 -1.0 1.0
# 3 1.0 1.0 1.0 -1.0
# 4 -1.0 -1.0 -1.0 -1.0