"BOKU"のITな日常

62歳・文系システムエンジニアの”BOKU”は日々勉強を楽しんでます

Pandas:crosstabを使った目標変数と特徴変数の関係把握と外れ値判定/構造化データ

目的変数が3値以上ある構造化データの内容にあたりをつけるのにcrontabを使ったり、はずれ値の判定をやってみたりします。

f:id:arakan_no_boku:20200329000112p:plain

 

前提

 

コード例は、以下がインポートされている前提とします。

import pandas as pd

以下の要領でCSVファイルを読み込んで「t」というDataFrameがある想定です。

train = pd.read_csv('./csvdata/train.csv')

 

特徴変数と目的変数の関連をクロス集計してみる

 

例えば、こんなデータがあったとします。

f:id:arakan_no_boku:20200516231202p:plain
target列が目的変数です。

0~12まである多クラス分類にしました。

他の列は特徴変数候補として、重要なものと不要なもののあたりをつけていきます。

方法としては、目的変数と特徴変数の関係を目安にしようと思います。

pandasにはそういう用途に使える「crosstab」という非常に便利な機能があります。

pandas.pydata.org

 

pandasのcrosstabでnormalize='columns'

 

例の「prl」列を特徴変数に選んでやってみます。

pd.crosstab(index=train['target'], columns=train['brl'], margins=True, normalize='columns')

結果はこんな感じ。

f:id:arakan_no_boku:20200516232336p:plain

brlが「0」の時、「1」の時に、各targetの値ごとの出現率が計算されてます。

各列の縦計は「概ね1.0・・つまり100%」です。

厳密にみると99.999999%や100.00000001%だったりとかもしますけど、目安として使うには十分かと思っています。

上記は列方向の計が100%になっています。

 

pandasのcrosstabでnormalize='index'

 

オプションを「normalize='index'」に変更すると、行方向の計が100%になります。

pd.crosstab(index=train['target'], columns=train['brl'], margins=True, normalize='index')

結果はこう変わります。

f:id:arakan_no_boku:20200516233330p:plain

横計が概ね100%になります。

 

indexとcolumnsを入れ替えてみる

 

上記はindexに目標変数、columnsに特徴変数を指定しています。

今度は、それを入れ替えてみます。

pd.crosstab(index=train['brl'],columns=train['target'],margins=True,normalize='index')

 そうすると、以下のように横長になります。

f:id:arakan_no_boku:20200520203743p:plain

ブログの画像にすると見づらいですが、実際には、たくさんの項目を並べて表示するので、このほうもよく使います。

 

crosstabの結果をheatmap(ヒートマップ)にする

 

crosstabの出力を数字だけだと見づらいときには視覚化します。

出力をprintではなく、左辺のDataFrameに渡し、All列は邪魔なのでdropした後、seabornのheatmap()に渡して表示するだけですけど。

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

 

dfheat = pd.crosstab(index=train['target'], columns=train['prl'], margins=True, normalize='columns')
dfheat.drop(['All'], axis=1, inplace=True)
sns.heatmap(dfheat, annot=True)
plt.show()

すると、こういうグラフになって、視覚的に把握しやすい・・かどうかは好みですが・・カッコいいです。

 

f:id:arakan_no_boku:20200517004515p:plain

 

はずれ値にあたりをつける

 

はずれ値は「他のデータからみて、極端に大きいか小さい値」のことです。

学習データとして使うには、これをみつけて「外れ値=異常値」なのか、「はずれ値だけど異常値ではない」のかを判断しないといけません。

どの値がはずれ値なのかを判定する方法には「スミルノフ・グラブス検定」とか「四分位範囲(IQR)を利用した判定」等があります。

今回はシンプルな後者の方法でやります。

四分位範囲(IQR)とは「第3四分位点 - 第1四分位点」で計算します。

それを使って

  • 「第3四分位数から四分位範囲×1.5倍を足した値」以上
  • 「第1四分位数から四分位範囲×1.5倍を引いた値」以下

を外れ値だと判定する方法です。

例にdescribe()で以下のような結果になった列を使います。

f:id:arakan_no_boku:20200517161004p:plain
25%が第一四分位、75%が第三四分位にあたります。

なので、外れ値判定の基準値を求めるのは。

q1 = train['rnd'].describe()['25%']
q3 = train['rnd'].describe()['75%']
iqr = q3 - q1

outlier_min = q1 - (iqr) * 1.5
outlier_max = q3 + (iqr) * 1.5

みたいな感じになります。

上記の例だとoutlier_minは「 -61.5」で、元データのminより小さいので基準値以下の外れ値はありません。

でも、outlier_maxは「142.5」で、maxより小さいので基準値以上の外れ値はあります。

あとは、以下のように基準値以上の外れ値の行を抽出したりして

outmax = train[train['rnd'] >= outlier_max]

あたりをつけ、必要に応じて置き換えたり、行を削除したりすれば、なんとかなりそうな気はします。 

今回はこんなところで。

ではでは。