前回、SVMのモデルで77%の精度でした。
(その4-3) タイタニックの乗客の生存有無をSVMで予測してみた
前回、ロジスティック回帰のモデルで75%の精度でした。今回はSupport vector machine(SVM)を使って予測してみようと思います。評価指標タイタニックのデータセットは生存有無を正確に予測できた乗客の割合(Accuracy)...
今回はk-Nearest Neighbor(KNN)を使って予測してみようと思います。
論文を読んでいるとKNNがよかったみたいな内容も読んだことがあるので少し期待をしています。
評価指標
タイタニックのデータセットは生存有無を正確に予測できた乗客の割合(Accuracy)を評価指標としています。
KNN
分析用データの準備
事前に欠損値処理や特徴量エンジニアリングを実施してデータをエクスポートしています。
本記事と同じ結果にするためには事前に下記記事を確認してデータを用意してください。
タイタニックのモデリング用データの作成まとめ
(その3-5) タイタニックのデータセットの変数選択にてモデリング用のデータを作成し、エクスポートするコードを記載していましたが分かりずらかったので簡略しまとめました。上から順に流していけばtitanic_train.csvとtitanic...
学習データと評価データの読み込み
import pandas as pd
import numpy as np
# タイタニックデータセットの学習用データと評価用データの読み込み
df_train = pd.read_csv("/Users/hinomaruc/Desktop/notebooks/titanic/titanic_train.csv")
df_eval = pd.read_csv("/Users/hinomaruc/Desktop/notebooks/titanic/titanic_eval.csv")
概要確認
# 概要確認
df_train.info()
Out[0]
RangeIndex: 891 entries, 0 to 890 Data columns (total 22 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 PassengerId 891 non-null int64 1 Survived 891 non-null int64 2 Pclass 891 non-null int64 3 Name 891 non-null object 4 Sex 891 non-null object 5 Age 891 non-null float64 6 SibSp 891 non-null int64 7 Parch 891 non-null int64 8 Ticket 891 non-null object 9 Fare 891 non-null float64 10 Cabin 204 non-null object 11 Embarked 891 non-null object 12 FamilyCnt 891 non-null int64 13 SameTicketCnt 891 non-null int64 14 Pclass_str_1 891 non-null float64 15 Pclass_str_2 891 non-null float64 16 Pclass_str_3 891 non-null float64 17 Sex_female 891 non-null float64 18 Sex_male 891 non-null float64 19 Embarked_C 891 non-null float64 20 Embarked_Q 891 non-null float64 21 Embarked_S 891 non-null float64 dtypes: float64(10), int64(7), object(5) memory usage: 153.3+ KB
# 概要確認
df_eval.info()
Out[0]
RangeIndex: 418 entries, 0 to 417 Data columns (total 21 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 PassengerId 418 non-null int64 1 Pclass 418 non-null int64 2 Name 418 non-null object 3 Sex 418 non-null object 4 Age 418 non-null float64 5 SibSp 418 non-null int64 6 Parch 418 non-null int64 7 Ticket 418 non-null object 8 Fare 418 non-null float64 9 Cabin 91 non-null object 10 Embarked 418 non-null object 11 Pclass_str_1 418 non-null float64 12 Pclass_str_2 418 non-null float64 13 Pclass_str_3 418 non-null float64 14 Sex_female 418 non-null float64 15 Sex_male 418 non-null float64 16 Embarked_C 418 non-null float64 17 Embarked_Q 418 non-null float64 18 Embarked_S 418 non-null float64 19 FamilyCnt 418 non-null int64 20 SameTicketCnt 418 non-null int64 dtypes: float64(10), int64(6), object(5) memory usage: 68.7+ KB
# 描画設定
import seaborn as sns
from matplotlib import ticker
import matplotlib.pyplot as plt
sns.set_style("whitegrid")
from matplotlib import rcParams
rcParams['font.family'] = 'Hiragino Sans' # Macの場合
#rcParams['font.family'] = 'Meiryo' # Windowsの場合
#rcParams['font.family'] = 'VL PGothic' # Linuxの場合
rcParams['xtick.labelsize'] = 12 # x軸のラベルのフォントサイズ
rcParams['ytick.labelsize'] = 12 # y軸のラベルのフォントサイズ
rcParams['axes.labelsize'] = 18 # ラベルのフォントとサイズ
rcParams['figure.figsize'] = 18,8 # 画像サイズの変更(inch)
モデル作成
# https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html
from sklearn.neighbors import KNeighborsClassifier
neigh = KNeighborsClassifier()
# 訓練データとテストデータに分割する。
from sklearn.model_selection import train_test_split
x_train, x_test = train_test_split(df_train, test_size=0.20,random_state=100)
# 説明変数
FEATURE_COLS=[
'Age'
, 'Fare'
, 'SameTicketCnt'
, 'Pclass_str_1'
, 'Pclass_str_3'
, 'Sex_female'
, 'Embarked_Q'
, 'Embarked_S'
]
X_train = x_train[FEATURE_COLS] # 説明変数 (train)
Y_train = x_train["Survived"] # 目的変数 (train)
X_test = x_test[FEATURE_COLS] # 説明変数 (test)
Y_test = x_test["Survived"] # 目的変数 (test)
model = neigh.fit(X_train,Y_train)
モデルの精度の確認
# 訓練データへの当てはまりを確認
# Return the mean accuracy on the given test data and labels.
model.score(X_train,Y_train)
Out[0]
0.8103932584269663
# テストデータへの当てはまりを確認
# Return the mean accuracy on the given test data and labels.
model.score(X_test,Y_test)
Out[0]
0.6703910614525139
オーバーフィットしているし、精度もSVMより下がりました。
confusion matrixの確認
# https://scikit-learn.org/stable/modules/generated/sklearn.metrics.ConfusionMatrixDisplay.html
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.metrics import ConfusionMatrixDisplay
ConfusionMatrixDisplay.from_estimator(neigh,X_test,Y_test,cmap="Reds",display_labels=["非生存","生存"],normalize="all")
plt.show()
Out[0]
# モデルパラメーターの確認
model.get_params()
Out[0]
{'algorithm': 'auto', 'leaf_size': 30, 'metric': 'minkowski', 'metric_params': None, 'n_jobs': None, 'n_neighbors': 5, 'p': 2, 'weights': 'uniform'}
デフォルトの設定です。何も設定していません。
n_neighborsは特に調整すべきオプションかも知れません。
クロスバリデーションで精度を確認
# https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.cross_val_score.html
# StratifiedKFold with KFold = 10
from sklearn.model_selection import cross_val_score
X = df_train[FEATURE_COLS] # 説明変数 (train)
Y = df_train["Survived"] # 目的変数 (train)
np.mean(cross_val_score(neigh, X, Y, cv=10,verbose=3))
Out[0]
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers. [Parallel(n_jobs=1)]: Done 1 out of 1 | elapsed: 0.0s remaining: 0.0s [Parallel(n_jobs=1)]: Done 2 out of 2 | elapsed: 0.1s remaining: 0.0s [CV] END ................................ score: (test=0.644) total time= 0.0s [CV] END ................................ score: (test=0.719) total time= 0.0s [CV] END ................................ score: (test=0.697) total time= 0.0s [CV] END ................................ score: (test=0.708) total time= 0.0s [CV] END ................................ score: (test=0.719) total time= 0.0s [CV] END ................................ score: (test=0.708) total time= 0.0s [CV] END ................................ score: (test=0.719) total time= 0.0s [CV] END ................................ score: (test=0.708) total time= 0.0s [CV] END ................................ score: (test=0.674) total time= 0.0s [CV] END ................................ score: (test=0.753) total time= 0.0s [Parallel(n_jobs=1)]: Done 10 out of 10 | elapsed: 0.3s finished 0.7048938826466916
70%でした。
Kaggle提出用データの作成
df_eval["Survived"] = neigh.predict(df_eval[FEATURE_COLS])
df_eval[["PassengerId","Survived"]].to_csv("titanic_submission.csv",index=False)
Kaggleへアップロード
!/Users/hinomaruc/Desktop/notebooks/my-venv/bin/kaggle competitions submit -c titanic -f titanic_submission.csv -m "model #003. KNN"
Out[0]
100%|████████████████████████████████████████| 2.77k/2.77k [00:04<00:00, 569B/s] Successfully submitted to Titanic - Machine Learning from Disaster
コンペの精度確認
Out[0]
精度65%でした。
KNN (モデリング用データを正規化するver)
KNNのポテンシャルはこんなものではないはず!
考えた結果、距離が関わってくるので正規化した方がいいですよね。
ということで正規化してもう一度試してみました。
データを正規化してKNNを試す
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
neigh = make_pipeline(StandardScaler(),KNeighborsClassifier())
SVMの時に試したコードを改良しました。
KNNでも使えそうです。
# fitさせる
model = neigh.fit(X_train,Y_train)
精度確認 (正規化ver)
# 学習データの精度確認
model.score(X_train,Y_train)
Out[0]
0.8609550561797753
# テストデータの精度確認
model.score(X_test,Y_test)
Out[0]
0.8212290502793296
オーバーフィットも無くなり、テストデータに対する精度も上がりました。
# confusion matrixを確認
ConfusionMatrixDisplay.from_estimator(neigh,X_test,Y_test,cmap="Reds",display_labels=["非生存","生存"],normalize="all")
plt.show()
クロスバリデーションで精度確認 (正規化ver)
# クロスバリデーションでの精度を確認
np.mean(cross_val_score(neigh, X, Y, cv=10,verbose=3))
Out[0]
[CV] END ................................ score: (test=0.778) total time= 0.0s [CV] END ................................ score: (test=0.854) total time= 0.0s [CV] END ................................ score: (test=0.764) total time= 0.1s [CV] END ................................ score: (test=0.831) total time= 0.0s [CV] END ................................ score: (test=0.876) total time= 0.0s [CV] END ................................ score: (test=0.809) total time= 0.0s [CV] END ................................ score: (test=0.798) total time= 0.0s [CV] END ................................ score: (test=0.809) total time= 0.0s [CV] END ................................ score: (test=0.843) total time= 0.0s [CV] END ................................ score: (test=0.775) total time= 0.0s [Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers. [Parallel(n_jobs=1)]: Done 1 out of 1 | elapsed: 0.0s remaining: 0.0s [Parallel(n_jobs=1)]: Done 2 out of 2 | elapsed: 0.1s remaining: 0.0s [Parallel(n_jobs=1)]: Done 10 out of 10 | elapsed: 0.3s finished 0.813732833957553
81.4%でした。
Kaggleにアップロードして精度を確認する (正規化ver)
df_eval["Survived"] = neigh.predict(df_eval[FEATURE_COLS])
df_eval[["PassengerId","Survived"]].to_csv("titanic_submission.csv",index=False)
!/Users/hinomaruc/Desktop/notebooks/my-venv/bin/kaggle competitions submit -c titanic -f titanic_submission.csv -m "model #004. KNN ver2"
Out[0]
100%|████████████████████████████████████████| 2.77k/2.77k [00:05<00:00, 551B/s] Successfully submitted to Titanic - Machine Learning from Disaster
76.5%でした。
まとめ
KNNだと正規化した上でモデリングした方が良さそうですね。
SVMが77%だったので精度としては下がってしまいましたが、KNN(データ正規化ver)は76.5%なのでほぼ変わらないという結果になります。
やっぱりKNNは優秀なアルゴリズムでした。
一通りのモデル手法を試したら今度はパラメーターチューニングでさらなる精度向上を試したいと思います。