探索的データ解析(回帰問題)

スポンサーリンク
Python




探索的データ解析(Exploratory data analysis:EDA)とはデータの確認作業です。一般的にデータ解析は、仮説検証的に行うものです。

つまり、「恐らくこんな関係性があるであろうから、本当にそうなのか、はたまた違うのかを確認してみよう」などです。しかし、仮説にない関係性が存在するかもしれません。

それを確認する作業がEDAです。

現場感覚だけでは発見できないものが、EDAでは発見できる可能性があります。

回帰問題は値の量や程度を予測する問題です。そこで、scikit-learnにあるbostonデータセットを用いてEDAを確認していきましょう。

開発環境は以下の記事を参考にして下さい。

M1 mac でanacondaをインストールし、Pythonを動作確認
M1 mac miniを購入したので、anacondaのインストールし、Pythonの動作を確認しました。 以前はWindowsでのanacondaのインストール方法を提示しました。 macでのイ...
【2021年最新】WindowsでAnacondaをインストールする方法、初心者がPythonの環境を構築する
Pythonの環境構築におすすめなのが、「anaconda」です。anacondaのなかにある、Jupyter Labはデータ解析や機械学習に非常に相性がいいです。理由は、コードを実行すると結果を返してくれます。その結果をみて、新たなコード

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の相関が強いですね。
データ分析では関連性が強い(この出力の上位)変数だけを使ってもいいかもしれませんね。
探索的データ解析はこんな感じです。コードは難しくないと思います。

この後は機械学習などで分析を進めていきましょう。

【初心者】コピペでできる線形回帰

【初心者】コピペでできるRidge・Lasso回帰

【初心者】コピペでできる決定木回帰

【初心者】コピペでできるランダムフォレス回帰

【初心者】コピペでできるXGBoost回帰

初心者のための回帰問題の評価指標





コメント

タイトルとURLをコピーしました