kaggle初日にTitanicをやってみた記録

kaggle初日にTitanicをやってみた記録
えびかずき
えびかずき

こんにちは、えびかずきです。

kaggle始めました!

今回は初日にTitanicにトライしてみた記録を残しておきます。

こんな人におすすめ:
・kaggleを始めてみたいが始め方がよくわからない

数ヶ月前にユーザーアカウントだけ作って放置していたkaggle。

いまいちやり方というかノリが分からず放置していたのですが、転職を機にまとまった時間ができたのでトライしてみることにしました。

まだ1日しかまともに触っていなくて初心者もいいところなのですが、

これから始めてみたいという方の参考になればと思って記録を残しておきます。

https://www.kaggle.com/ebikazuki

開発環境

kaggle上のnotebookでも開発ができるみたいですが、今回は使い慣れているローカル環境でトライしました。

マシン:MacOS BigSur 11.2.1/MacBook Pro

Python 3.7.3

scikit-learn 0.24.2
Pandas 1.2.4
seaborn 0.11.1

IDE:jupyter Notebook

筆者のレベル

一応、筆者のレベルについて記載しておこうと思います。
専門のバックグラウンドは他分野(化学)ですが、最近機械学習に興味を持ち始めて勉強している最中です。

こういう人って最近多いんじゃないかなと思います。

所属:
地方国立大の理系院卒→化学メーカー研究職(2021/6退社予定)
2021/5現在は有給消化中、AIエンジニアへ転職予定

Python歴:
丸2年くらい、主に研究業務のRPAに活用
(Rは使ったことありません)

関連資格:
統計検定2級
TOEIC600点くらい

機械学習関連で読んだ本:
・『はじめてのパターン認識』通称はじパタ
・『Pythonではじめる機械学習』
・『ゼロから作るDeepLearning』

kaggleを始めるために必要なスキル

1日kaggleをやってみて、必要だなと感じたスキルについて書いておこうと思います。

必須スキル:
・Python or R (orその他機械学習向け言語スキル)

機械学習ができる何らかのプログラミングスキルが必要です。
仮にPythonをメインで使うならば、Pandas、NumPy、scikit-learnあたりは自由に使えるレベルでないと厳しいと思います。

あった方が良いスキル:
・リーディング英語

まあ英語が分からなくてもChromeの自動翻訳でなんとかなると思います。

私は英語があまり得意な方ではないですが、kaggleのチュートリアル等はほぼストレスなく日本語で読めました。
ただし、ほかのkaggler達のnotebookを読んだり、コミュニケーションを取ったりできた方が楽しいと思うので、できるに越したことはないです。

Titanicにトライしてみた記録

Titanicとは

出典:https://www.kaggle.com/c/titanic

Titanicは、kaggleで継続的に開放されている練習用のコンペです。

簡単に言えば、kaggleに登録したユーザーが最初にトライするお試しコンペ。

賞金もメダルもありません。

内容はご想像の通り、1912年4月15日に氷山への衝突が原因で沈没した「タイタニック号」に関するもの。

学習データとして、当時の乗客891名分の以下データと、それぞれの生死情報が与えられます。

  • PassengerId(乗客ID)
  • Pclass(乗船等級)
  • Name(乗客の名前)
  • Sex(性別)
  • Age(年齢)
  • SibSp(同乗した兄弟または配偶者の数)
  • Parch(同乗した親または子の数)
  • Ticket(チケット番号)
  • Fare(乗船料金)
  • Cabin(キャビン番号)
  • Embarked(乗船港)
  • Survived(生死)‥これが教師データ

これを元にテストデータとして別の乗客418名の生死を予測するというものです。

2021/5/26現在のリーダーズボード(参加者の成績一覧)をグラフ化したものがこちら↓

Titanic-leadersboardのスコア分布
Titanic-leadersboardのスコア分布(積算値)

これをみると大体0.77~0.78あたりがボリュームゾーンになっているようです。

要するに初心者は、0.77を超えることがひとまずの目標となりそうです。

データの可視化

まずは与えられたデータを可視化して、よく観察してみましょう。

import pandas as pd

# 訓練データの読み込み
titanic = pd.read_csv('train.csv')
titanic.head()

このうちぱっと可視化できそうなデータをグラフ化して並べてみます。

# 生データの可視化

import seaborn as sns; sns.set()
import matplotlib.pyplot as plt

fig, ax = plt.subplots(3, 2,figsize=(8, 12))

sns.barplot(x="Sex", y="Survived", data=titanic , ax=ax[0,0])
sns.barplot(x="Pclass", y="Survived" , data=titanic , ax=ax[0,1])
sns.barplot(x="SibSp", y="Survived" , data=titanic , ax=ax[1,0])
sns.barplot(x="Parch", y="Survived" , data=titanic , ax=ax[1,1])
sns.barplot(x="Embarked", y="Survived" , data=titanic , ax=ax[2,0]);

なるほど、女性の方が生き残りやすかったのか。

あと等級は1に近いほど(高い側?)生き残りやすいのね。

その他はぱっと見では傾向がよくわからないです。

続いて年齢のデータを可視化してみましょう。

plt.figure(figsize=(32, 12))
sns.barplot(x="Age", y="Survived" , data=titanic);

いまいち傾向がよく分からない。。。

ところで全体の生死の割合はどうかと言うと、

sns.histplot(x="Survived", hue="Survived" , data=titanic )

1が生き残った方を表していますが、全体としては生き残った方の方が少ないみたいです。

データの前処理

それでは、データの学習を進めていきましょう。

まずはデータの前処理をしました。

予測に使うデータは、使いやすそうな以下7項目に制限し、質的データはダミー変数に変換、欠損値を含む行は削除しました。

  • Pclass(乗船等級)
  • Sex(性別)
  • Age(年齢)
  • SibSp(同乗した兄弟または配偶者の数)
  • Parch(同乗した親または子の数)
  • Fare(乗船料金)
  • Embarked(乗船港)
# 質的データのダミー変数化
from sklearn.preprocessing import LabelEncoder
encoder = LabelEncoder()


titanic_en = titanic #エンコード用のdfを作る

# Sex
Sex_en = encoder.fit_transform(titanic['Sex'])
titanic_en["Sex"] = Sex_en
# Embarked
Embarked_en = encoder.fit_transform(titanic['Embarked'])
titanic_en["Embarked"] = Embarked_en

# 使わない質的データとNaNを落とす
titanic_en = titanic_en.drop(['PassengerId','Name','Ticket','Cabin'], axis=1).dropna()
titanic_en.head()

続いて、scikit-learnに入れられるようにデータ形式をndarrayに変換します。

# 訓練データの生成
X = titanic_en.drop(['Survived'], axis=1).values
y = titanic_en["Survived"].values

SVM(サポートベクターマシン)を試す

データの前処理が済んだので、まずはSVMを試してみます。

SVMで調整すべきパラメータは「C」と「gamma」なので、交差確認法を使ってそれぞれ最適化していきます。

#SVM gamma opt./交差確認法

from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
import pandas as pd

log_gamma = []
score = []

for i in range(-5, 3):
    svc = SVC(C=1, gamma=10**i)
    scores = cross_val_score(svc, X, y, cv = 10)
    log_gamma.append(i)
    score.append(np.mean(scores))
    
# seabornでグラフ化
import seaborn as sns; sns.set()

opt = pd.DataFrame()
opt["log_gamma"] = log_gamma
opt["score"] = score

sns.lineplot(x="log_gamma",y="score",data=opt);

gammaは\(10^{-3}〜10^{-2}\)に指定するのが良さそうです。

続いてCの最適化。

#SVM C opt./交差確認法
from sklearn.svm import SVC
from sklearn.model_selection import cross_val_score
import pandas as pd

log_C = []
score = []

for i in range(0, 5):
    svc = SVC(C=10**i, gamma=0.001)
    scores = cross_val_score(svc, X, y, cv = 10)
    log_C.append(i)
    score.append(np.mean(scores))
    
# seabornでグラフ化
import seaborn as sns; sns.set()

opt_C = pd.DataFrame()
opt_C["log_C"] = log_C
opt_C["score"] = score

sns.lineplot(x="log_C",y="score",data=opt_C);

Cは\(10^{2}〜10^{4}\)あたりに指定するのが良さそうです。

ということで上であたりをつけた数値の周辺で最適化した結果、C=143、gamma=0.0018の性能が最も良さそうでした。

このパラメータで分類器を生成します。

# 分類器生成
clf_svc = SVC(C=143, gamma=0.0018)
clf_svc.fit(X,y)

テストと結果csvの書き出し

学習ができたので、kaggleへ報告するファイルを作ります。

テストデータに含まれる欠損値は平均値で穴埋めしました。

import pandas as pd
from sklearn.preprocessing import LabelEncoder

# DataFrameの読み込み
titanic_test = pd.read_csv('test.csv')
titanic_test.head()

# ダミー変数化
encoder = LabelEncoder()
titanic_test_en = titanic_test #エンコード用のdfを作る

# Sex
Sex_en = encoder.fit_transform(titanic_test['Sex'])
titanic_test_en["Sex"] = Sex_en
# Embarked
Embarked_en = encoder.fit_transform(titanic_test['Embarked'])
titanic_test_en["Embarked"] = Embarked_en

# 質的データを落とす
titanic_test_en = titanic_test_en.drop(['PassengerId','Name','Ticket','Cabin'], axis=1)

# 欠損値を平均で置き換え
titanic_test_en = titanic_test_en.fillna(titanic_test_en.mean())

titanic_test_en.head()
テストデータの前処理結果

# 予測の実行
X_test = titanic_test_en.values
result = clf_svc.predict(X_test)

# gender_submission.csv(結果テンプレ)の呼び出し
pd_temp = pd.read_csv('gender_submission.csv')

# 予測結果の書き換え
pd_temp['Survived'] = result

# DataFrameの書き出し
pd_temp.to_csv('titanic_1_3.csv', index=False, encoding='utf-8')

さてこれで提出ファイルができました。

kaggleに送信してみましょう。わくわく。

その結果がこちら↓

SVMで予測した結果

結果はscore=0.71770でした。

リーダーズボードのボリュームゾーンは0.77あたりだったので、まだ改良の余地がありますね。

ということで次はランダムフォレストを試してみます。

ランダムフォレストを試す

ランダムフォレストで調整すべきパラメータは、決定木の数(n_estimators)です。

場合によっては、各決定木で使う特徴量の最大数(max_features)を調整すると性能が上がる場合があります。

#RandomForest(n=500,features=4)/交差確認
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score

forest = RandomForestClassifier(n_estimators=500, max_features=4,random_state=0)
scores = cross_val_score(forest, X, y, cv = 10)
print(np.mean(scores))

# OUTPUT:
# 0.811

この二つで最適化を進めた結果、n_estimatorsは100以上、max_featuresは4が良さそうでした。

と言うことで、ランダムフォレストの方も分類器をつくって、予測結果をkaggleへ送信してみます。

# 分類器生成
clf_rf = RandomForestClassifier(n_estimators=500, max_features=4, random_state=0)
clf_rf.fit(X, y)
clf_rf.score(X,y)
# 予測の実行
result = clf_rf.predict(X_test)

# 提出ファイル作成
pd_temp = pd.read_csv('gender_submission.csv')
pd_temp.head()
pd_temp['Survived'] = result
pd_temp.to_csv('titanic_1_4.csv', index=False, encoding='utf-8')

その結果がこちら↓

結果はscore=0.75837。

SVMよりもスコアは向上しました。

しかしリーダーズボードのボリュームゾーンには惜しくも届かず。

まだ改良の余地がありそうです。

おそらく、欠損値の取り扱いと使っていない学習データの取り込みをもう少しうまくやれば性能が強化できるでしょう。

まとめ

今回はkaggleを始めた記念に、Titanicにトライしてみた記録を残しておきました。

Titanicは練習用のコンペなので、まだkaggleを始めたとも言えないような状態かもしれませんがとにかく走り始めました。

この先1ヶ月ほどまとまった時間があるので、時間のある限りkaggleに注力していこうと思っています。

今後の目標はExpertになること!

今年度中にはExpertまで手が届くといいな。

また何か進展があれば、記事に残そうと思います。

参考書籍

kaggleを始めるにあたって以下の書籍が参考になりました。

データ分析の方法についてはさほど詳しくありませんが、kaggleというコンペの背景や規模、価値についておおまかに知ることができました。

これからkaggleを始めたい人におすすめです。

機械学習カテゴリの最新記事