

今回は、データの前処理から機械学習までを一貫して解説していきます。データを目の前にして、いきなり機械学習もモデルを作成することはありえません。データの前処理や可視化、特徴量エンジニアリングなどをしてから、モデルの作成、モデルの評価を行っていきます。
データはタイタニックのデータセットを使って、実際のコードで解説していきます。
タイタニックデータセットは機械学習を学ぶ上で、もっとも基本的で、もっとも最初に扱うデータをいわれています。
Pythonの環境構築はAnacondaをインストールし、Jupyter Labを使っていきます。
以下の過去記事を参照して下さい。
【2021年最新】M1 mac でanacondaをインストールする方法
【2021年最新】WindowsでAnacondaをインストールする方法
必要なライブラリをインポート
import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns %matplotlib inline plt.style.use('ggplot') # 警告メッセージを出さないようにする import warnings warnings.filterwarnings('ignore')
タイタニックのデータセットを読み込む
titanic = sns.load_dataset('titanic') # seabornにある titanicのデータセットを読み込む titanic
訓練用とテスト用にデータを分割する
データの前処理や可視化のまえに、訓練用とテスト用にデータを分割します。そして、訓練用のデータのみを使ってデータの詳細を確認します。
X = titanic.iloc[:,1:] # 2列目以降の変数を説明変数に指定 y = titanic.iloc[:,0] # 1列目の変数を目的変数に指定 # データを訓練用とテスト用に分割する 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, # もとのデータの 0.25をテストデータ random_state = 1, stratify = y)
訓練用のデータを確認する
df_train = pd.concat([y_train,X_train], axis=1) # 目的変数を説明変数を合体 df_train
【Python初心者】 直感的に理解できるデータの結合 concat・merge
各変数の詳細
- survived:生死(1=生存、0=死亡)
- pclass:チケットクラス(1=上級、2=中級、3=下級)
- sex:性別(male=男性、female=女性)
- age:年齢
- sibsp:同乗している兄弟/配偶者の数
- parch:同乗している親/子の数
- fare:乗船料金
- embarked:出港地(C=Cherbourg、S=Southampton、Q=Queenstown)
- who:性別(man=男性、woman=女性)
- adult_male:成人男性であるかどうか(True=成人男性、False=成人男性以外)
- deck:乗船していたデッキ(First=上級、Second=中級、Third=下級)
- embarck_town:出港地
- alive:生死(no=0、yes=1)
- alone:一人であったかどうか
「adult_male」は成人男性かどうかですが、何歳からを成人としているかを確認してみましょう。
df_train[df_train["adult_male"]==True]["age"].min() # 「adult_male」の年齢の最小値を確認
出力:
16.0
「adult_male」の最少年齢は 16 です。
sum(df_train[df_train["adult_male"]==True]["sex"]=="female") # 「adult_male」が女性であるデータ数
出力:
0
「adult_male」に女性がいないことが確認できました。
つまり、「adult_male」は「age」と「sex」で説明できるため、情報が重複しています。
「alone」が一人であるかを、「sibsp」と「parch」から確認してみましょう。
len(df_train[(df_train["sibsp"]+df_train["parch"])==0])==len(df_train[df_train["alone"]==True]) # 「sibsp」と「parch」が Oと、「alone」である場合の真偽
出力:
True
「sibsp」と「parch」の合計が0(同乗者なし)であれば、「alone」であることが確認できました。
つまり、「alone」は情報が重複しています。
訓練データの前処理
このタイタニックのデータセットは生存が目的になります。なので、生存に関係なさそうな変数や、情報が重複している変数を削除します。
必要なデータを削除する
df = df_train.drop(["pclass","deck","alive","adult_male","who","embark_town","alone"],axis=1) # 必要のない変数を削除 df
欠損値の処理
【Python初心者】直感的に分かる欠損値の取り扱い(削除・補完)
df.isnull().sum() # 欠損値の個数を確認
「age」に 133の欠損値が、「embarked」に 2も欠損値があります。
まずは、「age」の欠損を平均値で補完してみましょう。また、「embarked」の内容を確認してみましょう。
df["age"] = df["age"].fillna(df["age"].mean()) # 「age」の欠損値を平均値で補完 print(df.isnull().sum()) # 欠損値の個数を確認 print(df["embarked"].value_counts())# 欠損値の個数を確認
「age」を補完した結果、欠損値が0になりました。また、「embarked」はSが485、Cが127、Qが54でした。では、「embarked」を最頻値であるSで補完してみましょう。
df.fillna({"embarked":"S"},inplace=True) # 「enbarked」の欠損値を最頻値であった「S」で補完 print(df.isnull().sum()) # 欠損値の個数を確認 print(df["embarked"].value_counts()) # 欠損値の個数を確認
欠損値がなくなりました。また、「embarked」のSが485から487になり、補完できました。
【Python初心者】直感的に分かる欠損値の取り扱い(削除・補完)
データの可視化
生存の有無を棒グラフにしてみます。
print(df["survived"].value_counts()) # 「survived」のデータ数を確認 plt.figure(figsize=(7,5)) sns.countplot(x="survived",data=df,palette="hls") plt.show()
生存の有無を「embarked」別で棒グラフを作成してみましょう。
print(pd.crosstab(df["survived"], df["embarked"])) # 「survived」のデータ数を「embarked」別でデータ数を確認 plt.figure(figsize=(10,5)) sns.countplot(x="embarked", data=df, hue="survived",palette="hls") plt.show()
今度は、「class」別で生存の有無を確認してみます。
print(pd.crosstab(df["survived"], df["class"])) # 「survived」のデータ数を「class」別でデータ数を確認 plt.figure(figsize=(10,5)) sns.countplot(x="class", data=df, hue="survived",palette="hls") plt.show()
次は、生存の有無で分けた年齢をヒストグラムにしてみましょう。
plt.figure(figsize=(10,5)) sns.distplot(df[df["survived"]==0]["age"], bins=30, color='g') # 「survived」が0、つまり死亡したデータの「age」 sns.distplot(df[df["survived"]==1]["age"], bins=30, color='r') # 「survived」が1、つまり生存したデータの「age」 plt.xlabel("Age",fontsize=15) plt.show()
生存の有無で分けた「fare」(乗船料金)をヒストグラムで確認する
plt.figure(figsize=(10,5)) sns.distplot(df[df["survived"]==0]["fare"], bins=30, color='g') # 「survived」が0、つまり死亡したデータの「fare」 sns.distplot(df[df["survived"]==1]["fare"], bins=30, color='r') # 「survived」が0、つまり死亡したデータの「fare」 plt.xlabel("Fare",fontsize=15) plt.show()
いろいろしましたが、以下のコードでは簡単にデータの可視化ができます。データと目的変数を引数に指定するだけです。
import dabl dabl.plot(df, target_col = 'survived') # データフレーム、目的変数を引数に指定
【Python初心者】matplotlibとseabornで散布図を描いてみよう(データの可視化)
【Python初心者が知らない】ドットプロットでデータを可視化する簡単な方法
訓練データの前処理
機械学習の精度を上げるために、変数のデータを変換します。
具体的には、カテゴリ変数をダミー変数に、連続変数を標準化(平均値が0、標準偏差が1)します。
df = pd.get_dummies(df,drop_first=True) # カテゴリ変数をダミー変数に変換する from sklearn.preprocessing import StandardScaler std = StandardScaler() df["fare"] = std.fit_transform(df[["fare"]]) # 「fare」を標準化する df["age"] = std.fit_transform(df[["age"]]) # 「age」を標準化する df
【Python初心者】カテゴリ変数をダミー変数に置き変える方法|機械学習に必要な前処理
【Python初心者】正規化・標準化する方法|機械学習に必要な前処理
X_train = df.iloc[:,1:].values # 2列目以降の変数を説明変数に指定 y_train = df.iloc[:,0].values # 1列目の変数を目的変数に指定
テストデータの前処理
テストデータも訓練データを同じように前処理します。
X_test = X_test.drop(["pclass","deck","alive","adult_male","who","embark_town","alone"],axis=1) # 必要ない変数を削除する X_test["age"] = X_test["age"].fillna(X_test.groupby("sex")["age"].transform("mean")) # 「age」の欠損値を補完する(性別の平均値) X_test.fillna({"embarked":"S"},inplace=True) # 「embarked」の欠損値を補完する(最頻値:S) X_test = pd.get_dummies(X_test,drop_first=True) # ダミー変数へ X_test["fare"] = std.fit_transform(X_test[["fare"]]) # 「fare」を標準化する X_test["age"] = std.fit_transform(X_test[["age"]]) # 「age」を標準化する X_test = X_test.values y_test = y_test.values
機械学習(確率的勾配降下法)
機械学習のアルゴリズムは深層学習(一応)の確率的勾配降下法を使います。
学習モデルを作成しましょう。比較的単純なコードだと思います。
from keras.models import Sequential from keras.layers import Dense, Dropout from keras.optimizers import SGD model=Sequential() model.add(Dense(200, activation="relu", input_dim=X_train.shape[1])) model.add(Dropout(0.2)) model.add(Dense(200, kernel_initializer="uniform", activation="relu")) model.add(Dropout(0.2)) model.add(Dense(1,activation="sigmoid")) model.summary()
モデルの内容が出力されています。少し難しいですね。まあこのコードはコピペで大丈夫です。
では、作成したモデルを実行していきましょう。
sgd=SGD(lr=0.01,momentum=0.9,decay=1e-7) model.compile(optimizer=sgd, loss="binary_crossentropy", metrics=["accuracy"]) history=model.fit(X_train, y_train, batch_size=64, epochs=50, verbose=1, validation_split=0.2)
テストデータを使って予測精度を評価
print('訓練データの正解率 :{0}'.format(round(history.history['accuracy'][-1],4))) results = model.evaluate(X_test, y_test, verbose=0) print('テストデータの正解率:{0}'.format(round(results[1],4)))
出力:
訓練データの正解率 :0.8296
テストデータの正解率:0.8296
マトリクスで結果を確認しましょう。
from sklearn.metrics import confusion_matrix y_pred = model.predict_classes(X_test, verbose=0) # 予測データを作成 # テストと予測のデータから混合行列を生成 confmat = confusion_matrix(y_true=y_test, y_pred=y_pred) plt.style.use('default') fig, ax = plt.subplots(figsize=(4, 4),dpi=100) # matshow関数で行列からヒートマップを描画 ax.matshow(confmat, cmap=plt.cm.Blues, alpha=0.3) for i in range(confmat.shape[0]): # クラス0の繰り返し処理 for j in range(confmat.shape[1]): # クラス1の繰り返し処理 ax.text(x=j, y=i, s=confmat[i, j], va='center', ha='center') # 件数を表示 plt.xlabel('Predicte label') plt.ylabel('True label') plt.tight_layout() plt.show()
from sklearn.metrics import precision_score, recall_score, f1_score, roc_auc_score print('Test accuracy: %.3f' % model.evaluate(X_test, y_test, verbose=0)[1]) print('Precision: %.3f' % precision_score(y_test, y_pred)) print('Recall: %.3f' % recall_score(y_test, y_pred)) print('F1: %.3f' % f1_score(y_test, y_pred)) print('roc_auc: %.3f' % roc_auc_score(y_test, y_pred))
テストデータの結果は正解率が0.839でした。データ解析のコンペティションであるkaggleでもタイタニックデータセットを使った機械学習があります。0.839はなかなかの正解率です(実際はKaggleのデータセットとseabornのデータセットは少し違いますが)

コメント