KaggleのTitanicでスコア0.77751を獲得

# KaggleのTitanicでスコア0.77751を獲得した際のプログラムの話
最後のまとめにプログラムの全貌を書いているのでプログラムの解説がいらない方は、まとめを見ればすぐできます。
また、今回RandomForestの木の本数の最適な値を探るプログラムと実際の予測データを書いているプログラムの2つプログラムを作成しています。

## 使用環境
- GoogleColaboratory
- Python

# 木の本数を探るプログラム
## 使用ライブラリ
RamdomForestを使用するのと、csvファイルからデータを読むのでここまでは、脳死で書く。
最適な木の本数を知りたいので、プロットするためにmatplotlibを使う。
```Titanic_train.py
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
```
## ファイルを読み込む
ここも脳死
```Titanic_train.py
df = pd.read_csv('train.csv')
```
## データの前処理
|カラム名  |値の概要 |
|---|---|
|生存  |数字(この値を予測する)  |
|チケットのクラス  |数字  |
|性別  |male, female  |
|兄弟・配偶者の数  |数字  |
|親・子供の数  |数字  |
|チケットの番号  |数字と文字  |
|運賃  |数字  |
|乗船キャビンの場所　 |数字と文字  |
|乗船場所  |Q, C, S  |

- 20世紀初期ということで、性別は関係ありそう...
- チケットのグレードも関係ありそう...
- 運賃も関係あるか？
と今回は、相関関係を調べず感覚で行いました。(´∀｀=)
それで、0.77751なら良くね!?と強気で記事を書いています。
ということで、性別を数字に変換する必要がある。
```Titanic_train.py
df['Sex'] = df['Sex'].apply(lambda x: 0.0 if x == "male" else 1.0)
```
## 正規化
次に値の大きさに差がありすぎるので正規化が必要そう
```Titanic_train.py
scaler = MinMaxScaler()
df['Pclass'] = scaler.fit_transform(df[['Pclass']])
df['Age'] = scaler.fit_transform(df[['Age']])
df['Fare'] = scaler.fit_transform(df[['Fare']])
```
Nanの部分が何個か見られるので、中央値を代入しておく
```Titanic_train.py
df.fillna(df.median(), inplace=True)
```
# 学習データと予測データを定義
書いていませんでしたが、実は色々な学習データで試してこれが最もよく学習できた結果でした。
```Titanic_train.py
y = df.Survived
features = ['Pclass','Age', 'Sex', 'Fare']
X = df[features]
```
正答率を評価したいので、テストデータと学習データに分けておく。
```Titanic_train.py
train_x, test_x, train_y, test_y = train_test_split(X, y, random_state=1)
```
学習データの件数と予測データの件数を宣言
```Titanic_train.py
input_data = 4
input_data = [input_data]
output_data = [1]
```
今回、深さ低数値のして木の本数を変数にして、最適なものを見つけたいので、
```Titanic_train.py
max_depth = # ここを変化させる
random_state = 1
max_accuracy = 0
best_n_estimators = 0
accuracies = []
```
では、実際に学習と結果をプロット
最後の行で最も良い予測を行った木の本数とその値を出力しています。
```Titanic_train.py
for n_estimators in range(1, 501, 5):
    model = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth, random_state=random_state)
    model.fit(train_x, train_y)
    y_pred = model.predict(test_x)
    accuracy = accuracy_score(test_y, y_pred)
    accuracies.append(accuracy)
    if accuracy > max_accuracy:
        max_accuracy = accuracy
        best_n_estimators = n_estimators

plt.plot(range(1, 501, 5), accuracies, marker='o', linestyle='-')
plt.xlabel('Number of Trees')
plt.ylabel('Accuracy')
plt.title('Accuracy vs. Number of Trees')
plt.grid(True)
plt.show()
print("Max Accuracy:", max_accuracy)
print("Best Number of Trees:", best_n_estimators)
```
この結果、`n_estimators=40, max_depth=8`のとき最も良い結果が得られてるので、
これを使用して予測データcsvファイルを作成
# 最適解を使用して提出用csvファイルを作成
最初の方はほとんど同じなので変更箇所から書きます。
モデルの定義は、今回上で最適解が得られているので、
## モデルの定義
```Titanic_expect.py
model = RandomForestClassifier(n_estimators=40, max_depth=8, random_state=1)
model.fit(x_train, y_train)
```
## テストデータの入ったcsvファイルの読み込み
```Titanic_expect.py
test_data = pd.read_csv('test.csv')
```
## データの前処理
前回と変わりません。
```Titanic_expect.py
test_data['Sex'] = test_data['Sex'].apply(lambda x: 0.0 if x == "male" else 1.0)
scaler = MinMaxScaler()
test_data['Pclass'] = scaler.fit_transform(test_data[['Pclass']])
test_data['Age'] = scaler.fit_transform(test_data[['Age']])
test_data['Fare'] = scaler.fit_transform(test_data[['Fare']])
test_data.fillna(test_data.median(), inplace=True)
```
## 予測データの定義
```Titanic_expect.py
X_test = test_data[['Pclass','Age', 'Sex', 'Fare']]
```
## 予測
```Titanic_expect.py
predictions = model.predict(X_test)
```
## 結果をcsvファイルとして書き出し
```Titanic_expect.py
test_data['Survived'] = predictions
output_df = test_data[['PassengerId', 'Survived']]
output_df.to_csv('predictions2.csv', index=False)
```
これで、スコア0.77751を獲得できました。
# まとめ
## 良い結果が得られる木の本数を探るプログラム
```Titanic_train.py
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt

df = pd.read_csv('train.csv')
df['Sex'] = df['Sex'].apply(lambda x: 0.0 if x == "male" else 1.0)
scaler = MinMaxScaler()
df['Pclass'] = scaler.fit_transform(df[['Pclass']])
df['Age'] = scaler.fit_transform(df[['Age']])
df['Fare'] = scaler.fit_transform(df[['Fare']])
df.fillna(df.median(), inplace=True)

y = df.Survived
features = ['Pclass','Age', 'Sex', 'Fare']
X = df[features]

train_x, test_x, train_y, test_y = train_test_split(X, y, random_state=1)

input_data = 4
input_data = [input_data]
output_data = [1]

max_depth = # ここを変化させる
random_state = 1
max_accuracy = 0
best_n_estimators = 0
accuracies = []

for n_estimators in range(1, 501, 5):
    model = RandomForestClassifier(n_estimators=n_estimators, max_depth=max_depth, random_state=random_state)
    model.fit(train_x, train_y)
    y_pred = model.predict(test_x)
    accuracy = accuracy_score(test_y, y_pred)
    accuracies.append(accuracy)
    if accuracy > max_accuracy:
        max_accuracy = accuracy
        best_n_estimators = n_estimators

plt.plot(range(1, 501, 5), accuracies, marker='o', linestyle='-')
plt.xlabel('Number of Trees')
plt.ylabel('Accuracy')
plt.title('Accuracy vs. Number of Trees')
plt.grid(True)
plt.show()
print("Max Accuracy:", max_accuracy)
print("Best Number of Trees:", best_n_estimators)
```
## 最適解を使用して予測データを作る
```Titanic_expect.py
import pandas as pd
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt

df = pd.read_csv('train.csv')
df['Sex'] = df['Sex'].apply(lambda x: 0.0 if x == "male" else 1.0)

scaler = MinMaxScaler()
df['Pclass'] = scaler.fit_transform(df[['Pclass']])
df['Age'] = scaler.fit_transform(df[['Age']])
df['Fare'] = scaler.fit_transform(df[['Fare']])
df.fillna(df.median(), inplace=True)

y_train = df.Survived
features = ['Pclass','Age', 'Sex', 'Fare']
x_train = df[features]

model = RandomForestClassifier(n_estimators=40, max_depth=8, random_state=1)
model.fit(x_train, y_train)

test_data = pd.read_csv('test.csv')

test_data['Sex'] = test_data['Sex'].apply(lambda x: 0.0 if x == "male" else 1.0)
scaler = MinMaxScaler()
test_data['Pclass'] = scaler.fit_transform(test_data[['Pclass']])
test_data['Age'] = scaler.fit_transform(test_data[['Age']])
test_data['Fare'] = scaler.fit_transform(test_data[['Fare']])
test_data.fillna(test_data.median(), inplace=True)

X_test = test_data[['Pclass','Age', 'Sex', 'Fare']]

predictions = model.predict(X_test)

test_data['Survived'] = predictions
output_df = test_data[['PassengerId', 'Survived']]
output_df.to_csv('predictions2.csv', index=False)
```
今まで、自身で用意したデータセットでの学習は行ったことがありましたが、生データを使用しての学習は初めてでした。そのため、欠損値などを落としての学習では予測時にはうまくいかず、試行錯誤を繰り返しました。この経験はとても有用だとAIエンジニアを目指すものとして感じ記事を書きました。