0
0

前回タイタニックの欠損値を大真面目に埋めたり削除しましたけど、

今度はタイタニックの名前データも特徴量にしてみました。
参考↓

コード

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

訓練データの読み込み

df_train = pd.read_csv("train.csv")
df_train

image.png

名前の特徴量化

名前ではなく敬称を特徴量にしてみます。

df_train["Name"] = df_train["Name"].map(lambda x:x.split(",")[1].split(".")[0])
df_train

image.png

不必要な特徴量を削除

df_train = df_train.drop(["Cabin", "Ticket"], axis=1)
df_train

image.png

欠損値の補完

Embarked

sns.histplot(df_train["Embarked"])
plt.show()

image.png
Sで補完します。

df_train["Embarked"] = df_train["Embarked"].fillna("S")
df_train.isnull().sum()
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Fare             0
Embarked         0
dtype: int64

ダミー変数化

質的変数が全て補完できたのでダミー変数化します。

df_train = pd.get_dummies(df_train)
df_train

image.png

端のほうが見切れるくらい変数が増えました。

インデックスを作る

PassengerIdをインデックスにする

df_train.index = df_train["PassengerId"]
df_train = df_train.drop("PassengerId", axis=1)

年齢の補完

年齢は量が多いので確率的な推論ではなくちゃんと機械学習による分析にします。

x_train = df_train.dropna().drop("Age", axis=1)
x_test = df_train[df_train["Age"].isnull()].drop("Age", axis=1)
y_train = df_train.dropna()["Age"]

from sklearn.ensemble import GradientBoostingRegressor

model = GradientBoostingRegressor()
model.fit(x_train, y_train)
y_pred = model.predict(x_test)

pred = pd.DataFrame(y_pred)
pred.columns = ["Age"]
pred.index = x_test.index
train = pd.concat([x_train, y_train], axis=1)
test = pd.concat([x_test, pred], axis=1)
df_train = pd.concat([train, test])
df_train

Ageが補完されました。

df_train.isnull().sum()
Survived              0
Pclass                0
SibSp                 0
Parch                 0
Fare                  0
Name_ Capt            0
Name_ Col             0
Name_ Don             0
Name_ Dr              0
Name_ Jonkheer        0
Name_ Lady            0
Name_ Major           0
Name_ Master          0
Name_ Miss            0
Name_ Mlle            0
Name_ Mme             0
Name_ Mr              0
Name_ Mrs             0
Name_ Ms              0
Name_ Rev             0
Name_ Sir             0
Name_ the Countess    0
Sex_female            0
Sex_male              0
Embarked_C            0
Embarked_Q            0
Embarked_S            0
Age                   0
dtype: int64

訓練データの欠損値が全て補完されました。

テストデータの読み込み

df_test = pd.read_csv("test.csv")
df_test

image.png

使わない変数の削除

df_test.index = df_test["PassengerId"]
df_test = df_test.drop(["PassengerId", "Ticket", "Cabin"], axis=1)

名前の特徴量化

df_test["Name"] = df_test["Name"].map(lambda x:x.split(",")[1].split(".")[0])
df_test

image.png

Fareの補完

plt.hist(df_test["Fare"], bins=40)
(array([175.,  90.,  58.,  15.,  21.,  14.,  10.,   3.,   2.,   0.,   6.,
          3.,   2.,   0.,   0.,   0.,   5.,   4.,   0.,   1.,   7.,   0.,
          0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
          0.,   0.,   0.,   0.,   0.,   0.,   1.]),
 array([  0.     ,  12.80823,  25.61646,  38.42469,  51.23292,  64.04115,
         76.84938,  89.65761, 102.46584, 115.27407, 128.0823 , 140.89053,
        153.69876, 166.50699, 179.31522, 192.12345, 204.93168, 217.73991,
        230.54814, 243.35637, 256.1646 , 268.97283, 281.78106, 294.58929,
        307.39752, 320.20575, 333.01398, 345.82221, 358.63044, 371.43867,
        384.2469 , 397.05513, 409.86336, 422.67159, 435.47982, 448.28805,
        461.09628, 473.90451, 486.71274, 499.52097, 512.3292 ]),
 <BarContainer object of 40 artists>)

image.png

外れ値が大きいので平均値ではなく中央値で補完します(ちなみに某資格試験では平均値の重要性について全体の値を反映していることについて言及していました)。

df_test["Fare"] = df_test["Fare"].fillna(df_test["Fare"].median())

ダミー変数化

df_test = pd.get_dummies(df_test)
df_test

image.png

よく見ると訓練データと変数の個数が異なることがわかります。
そしてその要因が名前(敬称)です。

Ageの補完

訓練データと同様に機械学習で補完します。

x_train = df_test.dropna().drop("Age", axis=1)
x_test = df_test[df_test["Age"].isnull()].drop("Age", axis=1)
y_train = df_test.dropna()["Age"]

model = GradientBoostingRegressor()
model.fit(x_train, y_train)
y_pred = model.predict(x_test)

pred = pd.DataFrame(y_pred)
pred.index = x_test.index
pred.columns = ["Age"]
test = pd.concat([x_test, pred], axis=1)
train = pd.concat([x_train, y_train], axis=1)
df_test = pd.concat([train, test])
df_test

image.png

変数を合わせる

機械学習で予測するうえでPandasでは変数全部そろえる必要があります。

変数の確認

訓練データ

df_train.columns
Index(['Survived', 'Pclass', 'SibSp', 'Parch', 'Fare', 'Name_ Capt',
       'Name_ Col', 'Name_ Don', 'Name_ Dr', 'Name_ Jonkheer', 'Name_ Lady',
       'Name_ Major', 'Name_ Master', 'Name_ Miss', 'Name_ Mlle', 'Name_ Mme',
       'Name_ Mr', 'Name_ Mrs', 'Name_ Ms', 'Name_ Rev', 'Name_ Sir',
       'Name_ the Countess', 'Sex_female', 'Sex_male', 'Embarked_C',
       'Embarked_Q', 'Embarked_S', 'Age'],
      dtype='object')

テストデータ

df_test.columns
Index(['Pclass', 'SibSp', 'Parch', 'Fare', 'Name_ Col', 'Name_ Dona',
       'Name_ Dr', 'Name_ Master', 'Name_ Miss', 'Name_ Mr', 'Name_ Mrs',
       'Name_ Ms', 'Name_ Rev', 'Sex_female', 'Sex_male', 'Embarked_C',
       'Embarked_Q', 'Embarked_S', 'Age'],
      dtype='object')

足りない変数を確認する

for col in df_train.columns:
    if col not in df_test.columns:
        print("'"+ col +"',")
'Survived',
'Name_ Capt',
'Name_ Don',
'Name_ Jonkheer',
'Name_ Lady',
'Name_ Major',
'Name_ Mlle',
'Name_ Mme',
'Name_ Sir',
'Name_ the Countess',

結合関数を作る

そこに無いということはダミー変数では必ずFalseになるはずなのでそのような値をとる変数を疑似的に作ります。

def concat(df, columns):
    for col in columns:
        tmp = []
        for i in range(len(df["Age"])):
            tmp.append(False)
        Capt = pd.DataFrame(tmp)
        Capt.index = df.index
        Capt.columns = [col]
        df = pd.concat([df, Capt], axis=1)
    return df

この関数に足りない変数を確認するスクリプトで作った出力結果を利用して関数に入れます。

df_test = concat(df_test, ['Name_ Capt',
                            'Name_ Don',
                            'Name_ Jonkheer',
                            'Name_ Lady',
                            'Name_ Major',
                            'Name_ Mlle',
                            'Name_ Mme',
                            'Name_ Sir',
                            'Name_ the Countess'])
df_test

image.png

変数が増えました。

訓練データ

for col in df_test.columns:
    if col not in df_train.columns:
        print("'"+ col +"'")
'Name_ Dona'

一つだけでした

結合

df_train = concat(df_train, ['Name_ Dona'])
df_train.columns
Index(['Survived', 'Pclass', 'SibSp', 'Parch', 'Fare', 'Name_ Capt',
       'Name_ Col', 'Name_ Don', 'Name_ Dr', 'Name_ Jonkheer', 'Name_ Lady',
       'Name_ Major', 'Name_ Master', 'Name_ Miss', 'Name_ Mlle', 'Name_ Mme',
       'Name_ Mr', 'Name_ Mrs', 'Name_ Ms', 'Name_ Rev', 'Name_ Sir',
       'Name_ the Countess', 'Sex_female', 'Sex_male', 'Embarked_C',
       'Embarked_Q', 'Embarked_S', 'Age', 'Name_ Dona'],
      dtype='object')

変数の順番を揃える

念のため変数の順番を揃えます。

df_train = df_train.sort_index(axis=1)
df_test = df_test.sort_index(axis=1)

生存の予測

x = df_train.drop("Survived", axis=1)
y = df_train["Survived"]
x_test = df_test

from sklearn.model_selection import train_test_split as tts
from sklearn.ensemble import RandomForestClassifier as RFC
from lightgbm import LGBMClassifier as LGBMC

models = []
for i in range(200):
    x_train, x_val, y_train, y_val = tts(x, y, random_state=i, test_size=0.2, stratify=y)
    model1 = RFC()
    model1.fit(x_train, y_train)
    models.append([model1, model1.score(x_val, y_val)])
    model2 = LGBMC()
    model2.fit(x_train, y_train)
    models.append([model2, model2.score(x_val, y_val)])
models = sorted(models, key=lambda x:x[1], reverse=True)

from scipy.stats import mode
y_pred1 = models[0][0].predict(x_test)
y_pred2 = models[1][0].predict(x_test)
y_pred3 = models[2][0].predict(x_test)
y_pred = []
for i in range(len(y_pred1)):
    y_pred.append(mode([y_pred1[i], y_pred2[i], y_pred3[i]])[0])

400個予測モデルを作って上位3個のモデルで予測を行います。
image.png

これは期待できるかな・・・

pred = pd.DataFrame(y_pred)
pred.columns = ["Survived"]
pred.index = x_test.index
pred.sort_index().to_csv("submit_allval.csv")

データフレーム化して提出データを作りました。

精度は74.641%でした。前回より悪いやん・・・

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0