変数.shapeで配列の要素の数を取得できる
以下の例は2つの要素の配列が3つある事を示す
1 2 3 4 5 |
import numpy as np A = np.array([[1,2], [3,4], [5,6]]) A.shape # 出力 (3, 2) |
変数.shapeで配列の要素の数を取得できる
以下の例は2つの要素の配列が3つある事を示す
1 2 3 4 5 |
import numpy as np A = np.array([[1,2], [3,4], [5,6]]) A.shape # 出力 (3, 2) |
ホテリング法を用いた外れ値検出を、ホテリングのT二乗法と言いう
閾値のパラメータである誤報率は人間が設定する。
厳しく異常と判断する場合は誤報率を高くし、
やさしめにしたければ誤報率を低くする
値は一般的に0.05や0.01が使われる
データ量が十分あれば、ホテリング法で近似的にχ二乗検定で閾値設定が可能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from scipy import stats as st # 異常度a, 次元数df, 誤報率f1 a = 10 df = 4 f1 = 0.05 # 閾値の計算 threshold = st.chi2.ppf(1 - f1, df) # 閾値を越えているか判断 if threshold > a: print('normal') else: print('abnormal') |
閾値を設定後データから平均値と共分散行列を算出。
この2つを異常度の計算に使用する。
データdata
がベクトルで与えられている際の平均値mean
mean = np.mean(data, axis=0)
共分散行列
cov
cov = np.cov(data.T)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import numpy as np data = np.array([ [15, 16, 6, 5], [11, 19, 7, 3], [15, 19, 5, 7], [15, 17, 0, 6], [17, 21, 3, 7], [14, 15, 4, 5], [18, 24, 12, 6], [18, 17, 4, 7], [14, 17, 11, 6], [19, 23, 11, 6] ]) # 平均値 mean = np.mean(data, axis=0) # 共分散行列 cov = np.cov(data.T) print("平均値:\n" + str(mean)) print("共分散行列:\n" + str(cov)) |
1 2 3 4 5 6 7 |
平均値: [ 15.6 18.8 6.3 5.8] 共分散行列: [[ 5.82222222 4.02222222 1.91111111 2.13333333] [ 4.02222222 9.06666667 6.51111111 0.73333333] [ 1.91111111 6.51111111 15.56666667 -0.71111111] [ 2.13333333 0.73333333 -0.71111111 1.51111111]] |
異常度としてマハラノビス距離を算出
計算にはscipy.spatial
のdistance
を使用
距離を出したいデータx
に対し、
mahalanobis
は上記のmean
、cov
を用いて
maharanobis = distance.mahalanobis(x, mean, np.linalg.pinv(cov))
で計算
この結果と閾値を比較して、異常かどうかを判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import numpy as np from scipy.spatial import distance data = np.array([ [15, 16, 6, 5], [11, 19, 7, 3], [15, 19, 5, 7], [15, 17, 0, 6], [17, 21, 3, 7], [14, 15, 4, 5], [18, 24, 12, 6], [18, 17, 4, 7], [14, 17, 11, 6], [19, 23, 11, 6] ]) x = [7, 10, 16, 10] # 平均値、共分散行列 mean = np.mean(data, axis=0) cov = np.cov(data.T) # xのマハラノビス距離計算 maharanobis = distance.mahalanobis(x, mean, np.linalg.pinv(cov)) print(maharanobis) |
マハラノビス距離とは値とデータ平均値の距離のこと
通常ユークリッド距離を使いそうだが
異常度にユークリッド距離を使うともともとバラつきの大きい変数の
寄与が大きく、バラつきの小さい変数の寄与が小さくなるので適していない
これに対応するには各変数の距離を分散で割る
これをマハラノビス距離と呼びぶ
マハラノビス距離の計算方法
1 2 3 4 5 6 |
from scipy.spatial import distance # データ集合の平均値mean, データ集合の共分散行列(分散を集めたもの)cov mean = np.mean(data, axis=0) cov = np.cov(data.T) # データx, 平均値mean, 共分散行列の逆行列np.linalg.pinv(cov) から距離を計算 distance.mahalanobis(x, mean, np.linalg.pinv(cov)) |
データx
, y
に対して、与えられた平均値mean
、共分散行列cov
〇マハラノビス距離
〇mean
とのユークリッド距離
の計算結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import numpy as np from scipy.spatial import distance # データx,y x = [6, 18, 5] y = [4, 0, 21] # xとyが属する母集団の平均 mean = np.array([4, 2, 5]) # と共分散行列 cov = np.array([ [1, 0, 0], [0,64, 0], [0, 0, 3] ]) # xとyの各マハラノビス距離とユークリッド距離を計算し、出力 >Out: マハラノビス距離 x:2.8284, y:9.2410 ユークリッド距離 x:16.1245, y:16.1245 |
マハラノビス距離の方がユークリッド距離と比べて
分散が大きい変数の距離への寄与が小さくなる
値の異常さを定量的に扱、異常値を算出する
閾値を設定して、ここから大幅にずれるものを異常とあつかう
閾値が7で11となったら異常
閾値が7で5となったら正常と扱う
閾値は数値ではなく割合で算出
正しいものを以上だと判断する事を誤報率と呼ぶ
誤報率は以下の手法で計算する
閾値thに対して異常度xが X > th の時に異常と判断する
1 2 3 4 5 6 7 8 9 |
import numpy as np # 異常度X、ラベルy、閾値threshold X = np.array([17, 2, 19, 7, 6, 19, 4, 8, 2, 1]) y = np.array([ 1, 0, 1, 1, 0, 1, 0, 0, 0, 0]) threshold = 2 # 誤報率の計算 err_rate = X[(X > threshold) & (y == 0)].size / X[X > threshold].size print(err_rate) |
>0.42857142857142855
まずXの配列の中から2を超えるものが以上なので9個中8個が該当
その8個の内Yのラベル(1が異常と判断され0が正常と判断された)が0であるものは
正常であると判断したにも拘わらず異常だったという事になる
この数は上記では5個になる
err_rateはXの配列の中から閾値である2を超えるものかつYが0であるものの個数を出し
それをXの配列の中から閾値である2を超えるもので割るという計算で
誤報率を計算する
Jupyterの同じ階層にcsvをアップする
1 |
sales_sparkring = pd.read_csv('monthly-australian-wine-sales-th-sparkling.csv') |