Kaggle入門【Titanic】
初めに
以下のKernelsを参考にさせて頂きました.https://www.kaggle.com/omarelgabry/a-journey-through-titanic
Titanicでは乗客の特徴量を元に生死を予測するものです.
データセットをダウンロードはこちらからです.
Titanic: Machine Learning from Disaster | Kaggle
ダンロードしたら早速始めて行きます.
大まかに以下の手順で進めていきます.
1.不要データ削除
2.欠損値補完
3.文字を数値に変換
4.学習
データの確認
まずはデータをざっと見てみる
もろもろインポート# pandas import pandas as pd from pandas import Series,DataFrame # numpy, matplotlib, seaborn import numpy as np import matplotlib.pyplot as plt import seaborn as sns sns.set_style('whitegrid') %matplotlib inline # machine learning from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC, LinearSVC from sklearn.ensemble import RandomForestClassifier from sklearn.neighbors import KNeighborsClassifier from sklearn.naive_bayes import GaussianNB
head()で訓練データ・テストデータの最初の数行を見てみる
train.head()
test.head()
各カラムはこんな感じです
- PassengerId – 乗客識別のID
- Survived – 生存フラグ(0=死亡、1=生存)
- Pclass – チケットクラス
- Name – 乗客の名前
- Sex – 性別(male=男性、female=女性)
- Age – 年齢
- SibSp – タイタニックに同乗している兄弟/配偶者の数
- parch – タイタニックに同乗している親/子供の数
- ticket – チケット番号
- fare – 料金
- cabin – 客室番号
- Embarked – 出港地(タイタニックへ乗った港)
describe()で統計量の確認
train.describe()
欠損値はどれくらいか
info()で欠損値の確認
train.info() print("----------------------------") test.info()
まとめると
カラム | 訓練/テスト | 欠損具合 |
---|---|---|
Age(年齢) | 訓練 and テスト | 20% |
Cabin(客室番号) | 訓練 and テスト | 80% |
Embarked(出港地) | 訓練 | 2個 |
Fare(料金) | テスト | 1個 |
客室番号の欠損率は非常に高いですね.年齢の欠損率も高いです.出港地や料金は非常に少ないので問題にはならないでしょう.
不要データ削除
Cabinは欠損率が非常に高いので削除します.また,Name,Ticketは処理が面倒なので削除します.訓練データのPassengerIdも不要なので削除します.(テストデータのPassengerIdは提出するファイルを作成する際に使うので削除しない)train = train.drop(['Cabin','PassengerId','Name','Ticket'], axis=1) test = test.drop(['Cabin','Name','Ticket'], axis=1)
要素の補完・追加
欠損値の補完
EmbarkedとFareはデータ数が数個しかないので,平均値で補完します.# train['Embarked']の2個の欠損値は最頻値であるSを入れる train["Embarked"] = train["Embarked"].fillna("S") #test['Fare']の欠損値に平均を入れる test["Fare"].fillna(test["Fare"].median(), inplace=True)
しかしAgeは20%も抜けているので,単に平均値を入れるのではなく,
平均値±標準偏差内のランダムな値で補完することにします.(分布が正規分布に従う場合,平均値±標準偏差内にデータが含まれる確率は約68%)
#平均と標準偏差を求める average_age_titanic = train["Age"].mean() std_age_titanic = train["Age"].std() count_nan_age_titanic = train["Age"].isnull().sum() average_age_test = test["Age"].mean() std_age_test = test["Age"].std() count_nan_age_test = test["Age"].isnull().sum() # (mean - std) & (mean + std)内のランダムな値 rand_1 = np.random.randint(average_age_titanic - std_age_titanic, average_age_titanic + std_age_titanic, size = count_nan_age_titanic) rand_2 = np.random.randint(average_age_test - std_age_test, average_age_test + std_age_test, size = count_nan_age_test) # NaNに補完 train["Age"][np.isnan(train["Age"])] = rand_1 test["Age"][np.isnan(test["Age"])] = rand_2
大人と子どもを追加
大人と子どもで生存に差がありそうなので,大人か子どもかも区別したいと思います.
そこで,新たに'Person'というカラムを追加します'.
子どもの定義を16歳以下とし,'Person'には,16歳以下ならばchildで,そうでなければ,性別を格納するようにします.
'Person'を追加したら'Sex'は不要なので削除します.
# 16歳以下をchildとする #child・man・womanに分ける def get_person(passenger): age,sex = passenger return 'child' if age < 16 else sex #'Person'カテゴリを作成 train['Person'] = train[['Age','Sex']].apply(get_person,axis=1) test['Person'] = test[['Age','Sex']].apply(get_person,axis=1) # 'Sex'カテゴリを削除 train.drop(['Sex'],axis=1,inplace=True) test.drop(['Sex'],axis=1,inplace=True)
文字を数値に落とし込む
数値に直さなければならないカラムは- Sex – 性別(male=男性、female=女性)
- Embarked – 出港地(タイタニックへ乗った港)
get_dummies()でダミー変数を作り,join()で格納します.
#'Embarked'のダミー変数を作成 embark_dummies_titanic = pd.get_dummies(train['Embarked']) embark_dummies_test = pd.get_dummies(test['Embarked']) #格納する train = train.join(embark_dummies_titanic) test = test.join(embark_dummies_test) #'Embarked'は不要になったので削除 train.drop(['Embarked'], axis=1,inplace=True) test.drop(['Embarked'], axis=1,inplace=True) #'Person' person_dummies_titanic = pd.get_dummies(train['Person']) person_dummies_titanic.columns = ['Child','Female','Male'] person_dummies_test = pd.get_dummies(test['Person']) person_dummies_test.columns = ['Child','Female','Male'] train = train.join(person_dummies_titanic) test = test.join(person_dummies_test) train.drop(['Person'],axis=1,inplace=True) test.drop(['Person'],axis=1,inplace=True)
学習
今までの確認
実際に確認してみると,全て数値に変わっていて,欠損値もないので大丈夫そうです.train.head()
test.head()
train.isnull().any()
test.isnull().any()
ランダムフォレスト
ランダムフォレストで学習します.X_train = train.drop("Survived",axis=1) Y_train = train["Survived"] X_test = test.drop("PassengerId",axis=1) # Random Forests random_forest = RandomForestClassifier(n_estimators=100) random_forest.fit(X_train, Y_train) Y_pred = random_forest.predict(X_test) random_forest.score(X_train, Y_train)
訓練データのaccuracyは98%になりました.
ですが,テストデータに対するaccuracyが重要なので,これで安心してはいけません.
結果は・・・
提出するためにはテストデータを予測したcsvファイルを提出しなければなりません.テストデータを予測して,ファイルを作成します.submission = pd.DataFrame({ "PassengerId": test["PassengerId"], "Survived": Y_pred }) submission.to_csv('titanic.csv', index=False)
ファイルを作成したら「submit Predictions」を押して提出ページにアクセスしファイルをアップロードすれば完了です.
スコアは71%でした.見事に過学習していました.80%は目指したいところですので今後改善していこうと思います.