探索的データ解析(Exploratory data analysis:EDA)とはデータの確認作業です。一般的にデータ解析は、仮説検証的に行うものです。
つまり、「恐らくこんな関係性があるであろうから、本当にそうなのか、はたまた違うのかを確認してみよう」などです。しかし、仮説にない関係性が存在するかもしれません。
それを確認する作業がEDAです。
現場感覚だけでは発見できないものが、EDAでは発見できる可能性があります。
回帰問題は値の量や程度を予測する問題です。そこで、scikit-learnにあるbostonデータセットを用いてEDAを確認していきましょう。
開発環境は以下の記事を参考にして下さい。


bostonデータセットは、目的変数が住宅価格で、説明変数がその他の変数です。
自身でデータでも分類問題のEDAができるようにコードを書きました。bostonデータセットで確認後は、ぜひ自身のデータで確認してみてください。新たな発見があるかもしれません
必要なライブラリをインポート
import numpy as np import pandas as pd import matplotlib.pyplot as plt import japanize_matplotlib import seaborn as sns %matplotlib inline plt.style.use('fivethirtyeight') from sklearn.datasets import load_boston import warnings warnings.filterwarnings("ignore")
bostonデータセットをデータフレームに整える
boston = load_boston() df = pd.DataFrame(data = boston.data, columns = boston.feature_names) df['PRICE'] = boston.target df
目的変数(ターゲット):PRICE(住宅価格)
説明変数(特徴量):その他の変数
X = df.iloc[:,:-1] # 説明変数(最後の列以外) y = df.iloc[:,-1] # 目的変数(最後の列のみ)
目的変数をXに入れる。
説明変数をyにいれる。
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split( X, y, test_size = 0.25, random_state = 1)
探索的データ分析から、訓練データとテストデータに分割して訓練データのみで探索的データ分析する。
データ数を確認する。
print(X_train.shape) print(y_test.shape) print(X_test.shape) print(y_test.shape)
出力:
(379, 13)
(127,)
(127, 13)
(127,)
訓練データのみでデータセットを作る
df = pd.concat([X_train,y_train], axis=1) df
出力:
行数が379行になりました。データ数が少なくなりましたが、ここは仕方ありません。
訓練用データの中身を確認する
df.info()
出力:
各column(カラム、列)に対して、欠損値ではない数値(379は全データなので、欠損値なし)とDtypeは数値の種類(float64は小数点がある数値)が表示されています。
df.describe()
count:データの個数
mean:データの平均値
std:標準偏差(データのばらつき)
min:データの最小値
25%:最小値から25%のあたる数値
50%:中央値(最小値から50%にあたる数値)
75%:最小値から75%にあたる数値
max:データの最大値
データの可視化
これらが、変数(列)ごとに表示されます。
各変数ごとに分布を可視化してみましょう。
fig, axs = plt.subplots(ncols=7, nrows=2, figsize=(20, 10)) index = 0 axs = axs.flatten() for k,v in df.items(): sns.boxplot(y=k, data=df, ax=axs[index]) index += 1 plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=5.0)
出力:
各変数を箱ひげ図で表しています。
次に、目的変数であるPRICE(住宅価格)と説明変数との関係性を可視化してみましょう。
variable = 'PRICE' # 調べたい変数を ' ' に指定する import dabl plt.rcParams['figure.figsize'] = (18, 6) dabl.plot(df, target_col = variable)
PRICEのヒストグラムです。正規分布に従っていないですね。特に、50近くに多くのデータがあります。外れ値かもしれません。または、50以上はすべて50になっているかもしれません。
これは、PRICEとその他の説明変数との散布図が表出しています。すべての説明変数ではなく、相関の強い(上位6位)説明変数が出力されています。
二値変数であるCHASはPRICEの違いを箱ひげ図で出力されます。
簡単なコードで、これらが出力されます。すごいですね。
PRICEの50周辺は気になるので、外れ値として削除してみます。
df = df[~(df['PRICE'] >= 50.0)] print(np.shape(df))
出力:
(369, 14)
コードの1行目の ‘ ’ の中に目的変数の名前(ここではPRICE)を記入しましょう。
データ数(行数)が379から369に10行が削除されました。
では、ヒストグラムを確認してみましょう。
plt.hist(df.PRICE,bins=30) plt.ylabel("frequency") plt.xlabel("PRICE")
出力:
上のヒストグラムから50周辺が削除されています。
正規分布に従っているとは言い難いですが、少しはましになりました。
では、PRICEと説明変数との相関をみていきましょう。
df_corr=df.corr().abs() # 絶対値 df_corr['PRICE'].sort_values(ascending=False)
出力:
PRICE 1.000000
LSTAT 0.761115
RM 0.675959
INDUS 0.609295
TAX 0.559815
NOX 0.549558
AGE 0.534833
PTRATIO 0.534818
RAD 0.475407
CRIM 0.448171
ZN 0.433416
DIS 0.400364
B 0.351945
CHAS 0.085588
Name: PRICE, dtype: float64
これは、各変数ごとの相関係数(相関の強さ)が数値化されています。
相関が弱いと説明変数としては物足りないかもしれません。そんな変数は削除したほうがいいかもしれません。
相関が強い変数(ここでは、上から’LSTAT’, ‘RM’, ‘INDUS’, ‘TAX’, ‘NOX’, ‘AGE’, ‘PTRATIO’, ‘RAD’ を選択する)と目的変数であるPRICEを詳しくみていきましょう。
from sklearn import preprocessing # Let's scale the columns before plotting them against MEDV min_max_scaler = preprocessing.MinMaxScaler() column_sels = ['LSTAT', 'RM','INDUS', 'TAX', 'NOX','AGE','PTRATIO','RAD'] x = df.loc[:,column_sels] y = df['PRICE'] x = pd.DataFrame(data=x, columns=column_sels) fig, axs = plt.subplots(ncols=4, nrows=2, figsize=(20, 10)) index = 0 axs = axs.flatten() for i, k in enumerate(column_sels): sns.regplot(y=y, x=x[k], ax=axs[i]) plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=5.0)
出力:
各グラフのある点が線に収束しているほうが、関係性が強いです。
ここで気になるのは、TAXの650周囲に固まっている点ですね。これも外れ値かもしれません。TAXのヒストグラムをみてみましょう。
plt.hist(df.TAX,bins=20) plt.ylabel("frequency") plt.xlabel("TAX")
出力:
このTAXも700近くに多くのデータがありますね。TAXは税金なので、ここまで700近くにデータがるのはおかしいかもしれません。
700近くのデータを削除してみましょう。
df = df[~(df['TAX'] >= 600)] print(np.shape(df))
出力:
(271, 14)
データ数が271になりました。
では、もう一度目的変数であるPRICEと説明変数との関連性をみてみましょう。
from sklearn import preprocessing # Let's scale the columns before plotting them against MEDV min_max_scaler = preprocessing.MinMaxScaler() column_sels = ['LSTAT', 'RM','INDUS', 'TAX', 'NOX','AGE','PTRATIO','RAD'] x = df.loc[:,column_sels] y = df['PRICE'] x = pd.DataFrame(data=x, columns=column_sels) fig, axs = plt.subplots(ncols=4, nrows=2, figsize=(20, 10)) index = 0 axs = axs.flatten() for i, k in enumerate(column_sels): sns.regplot(y=y, x=x[k], ax=axs[i]) plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=5.0)
出力:
左上のLSTAT(低所得者の割合)やRM(平均部屋数)は点が線に収束されています。
逆にRADはばらばらで、関係性がないようにみえます。
もう一度相関の強さをみてみましょう。
df_corr=df.corr().abs() df_corr['PRICE'].sort_values(ascending=False)
出力:
PRICE 1.000000
RM 0.867652
LSTAT 0.687542
INDUS 0.481455
PTRATIO 0.425447
AGE 0.393779
ZN 0.377578
NOX 0.374022
TAX 0.338920
CRIM 0.334585
B 0.225192
DIS 0.185800
CHAS 0.037205
RAD 0.020335
Name: PRICE, dtype: float64
やはり、RMとLSTATの相関が強いですね。
データ分析では関連性が強い(この出力の上位)変数だけを使ってもいいかもしれませんね。
探索的データ解析はこんな感じです。コードは難しくないと思います。
この後は機械学習などで分析を進めていきましょう。
コメント