[Kaggle]いろいろとTitanicしてみる

前回[Kagglerになってみた](https://qiita.com/ryo_naka/items/3d17d327b4ab6b48a78e)が、それだとしっくりこなかったり、ほかのモデルを試してみてなかったりしたので
以下を参考にいろいろと試行錯誤してみた。

[[Kaggle]0から本当に機械学習を理解するために学ぶべきこと～一流のデータサイエンティストを例に～](https://qiita.com/zenonnp/items/9cbb2860505a32059d89)
[[part2]0から本当に機械学習を理解するために学ぶべきこと～一流のデータサイエンティストを例に～](https://qiita.com/zenonnp/items/05c89687ef3ea76f35ac)
[[part3]0から本当に機械学習を理解するために学ぶべきこと～0からscikit-learnを使いこなす～](https://qiita.com/zenonnp/items/92ca776684702b50c110)

といっても、なんとなく思考をトレースしただけなので項目の追加などは特にせずに
今後使いまわしやすそうなコード構成に修正したぐらいだが。
全体的にやらないといけないことの流れはなんとなくわかった気がするので、次回別のデータセットで試してみるのもいいかもしれない。


で、いろいろなモデルをまとめて試してみた結果が以下。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/106639/93102a2a-7cb0-337a-f178-0fa5f9a91c7a.png)
こんな感じになったモデルから一番精度がよさそうなものをピックアップし、生成した予測データをアップロードしてみる。


![image.png](https://qiita-image-store.s3.amazonaws.com/0/106639/1ca783a6-c1e9-d28b-cfab-0933fe74cb33.png)
こんな感じ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/106639/c07f364f-2377-6028-20cb-5b00508091a4.png)

もうちょっと上がるのかと思ったけど、そうでもなかった。
これが訓練データに過剰適合してしまったということなのか？


ちなみに修正後のソースはこんな感じ
何かを修正するとしたら、評価の部分だと思う。
交差検証にしたい。
あとは各モデルのパラメータとかもあるんだろうなと思うし、特徴量についてもある程度はチューニングできるようにしたい。


    # -*- coding: utf-8 -*-
    # ---------------------------------------------------------------------------
    # Python3

    import pprint
    import datetime 

    import pandas as pd
    import numpy as np

    # 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
    from sklearn.linear_model import Perceptron
    from sklearn.linear_model import SGDClassifier
    from sklearn.tree import DecisionTreeClassifier


    csv_train = r'C:\PJ\20180917_kaggle\kaggle_titanic\files\train.csv'
    csv_test = r'C:\PJ\20180917_kaggle\kaggle_titanic\files\test.csv'


    def read_dataset(df):
    
        # サイズ
        print("= size =")
        pprint.pprint(df.shape)

        # 統計量
        print("= describe =")
        pprint.pprint(df.describe())

        # 欠損データ
        print("= 欠損データ =")
        pprint.pprint(kesson_table(df))

        # 先頭データ
        print("= head =")
        pprint.pprint(df.head(10))

    def read_datasets(df_train, df_test):
        print("---> train ---")
        read_dataset(df_train)
        print("---> test ---")
        read_dataset(df_test)
        print("------------------------")

    def kesson_table(df): 
        null_val = df.isnull().sum()
        percent = 100 * df.isnull().sum()/len(df)
        kesson_table = pd.concat([null_val, percent], axis=1)
        kesson_table_ren_columns = kesson_table.rename(
        columns = {0 : '欠損数', 1 : '%'})
        return kesson_table_ren_columns

    def distribution(df, column_name):
        #平均・標準偏差・null数を取得する
        Age_average = df[column_name].mean() #平均値
        Age_std = df[column_name].std()  #標準偏差
        Age_nullcount = df[column_name].isnull().sum() #null値の数＝補完する数

        # 正規分布に従うとし、標準偏差の範囲内でランダムに数字を作る
        rand = np.random.randint(Age_average - Age_std, Age_average + Age_std , size = Age_nullcount)

        #Ageの欠損値
        df[column_name][np.isnan(df[column_name])] = rand
        pass

    def pre_processing(df):
        # 欠損値の補完
        ## 中央値を設定：median()で中央値が取得できる
        df["Age"] = df["Age"].fillna(df["Age"].median())
        # distribution(df, "Age")
        ## 最頻値を設定:pandas.Seriesに対してmode()で最頻値のSeriesが取得できるのでそれの先頭を使用
        df["Embarked"] = df["Embarked"].fillna(df["Embarked"].mode()[0])
        # distribution(df, "Embarked")
        ## 最頻値を設定
        df["Fare"] = df["Fare"].fillna(df["Fare"].mode()[0])
        # distribution(df, "Fare")

        # 文字列→数字化
        df['Sex'] = df['Sex'].map({ 'male':0, 'female':1})
        df['Embarked'] = df['Embarked'].map({ 'S':0, 'C':1, 'Q':1})
        # df['Sex'] = df['Sex'].map({ 'male':1, 'female':0})
        # df['Embarked'] = df['Embarked'].map({ 'S':1, 'C':2, 'Q':0})

    def output_file(prediction, df_test, filename):
        # PassengerIdを取得
        PassengerId = np.array(df_test["PassengerId"]).astype(int)
        # prediction(予測データ）とPassengerIdをデータフレームへ落とし込む
        df_solution_tree = pd.DataFrame(prediction, PassengerId, columns = ["Survived"])
        # csvファイルとして書き出し
        df_solution_tree.to_csv(filename, index_label = ["PassengerId"])
        pass

    def get_data():
        # ファイル読み込み
        df_train = pd.read_csv(csv_train)
        df_test = pd.read_csv(csv_test)

        # データの確認
        # read_datasets(df_train, df_test)

        return df_train, df_test

    def evaluation(model, features, target):
        """
        とりあえず結果を評価してみる
        """
        evaluation_score = round(model.score(features , target) * 100, 2)
        print(" -- evaluation : {}".format(evaluation_score))

        return evaluation_score

    def create_model_DecisionTree(predictor_var, response_var):
        # 決定木の作成とアーギュメントの設定
        max_depth = 10
        min_samples_split = 5
        # model_DecisionTree = tree.DecisionTreeClassifier(max_depth = max_depth, min_samples_split = min_samples_split, random_state = 1)
        model_DecisionTree = DecisionTreeClassifier(max_depth = max_depth, min_samples_split = min_samples_split, random_state = 1)
        model_DecisionTree = model_DecisionTree.fit(predictor_var, response_var)

        return model_DecisionTree

    def create_model_LogisticRegression(predictor_var, response_var):
        # ロジスティック回帰
        model_LogisticRegression = LogisticRegression()
        model_LogisticRegression.fit(predictor_var, response_var)
        # Y_pred = logreg.predict(X_test)
        return model_LogisticRegression

    def create_model_SVM(predictor_var, response_var):
        # Support Vector Machines
        model_SVC = SVC()
        model_SVC.fit(predictor_var, response_var)

        return model_SVC

    def create_model_KNeighbors(predictor_var, response_var):
        # k近傍法(KNN)
        model_KNeighbors = KNeighborsClassifier()
        model_KNeighbors.fit(predictor_var, response_var)

        return model_KNeighbors

    def create_model_GaussianNB(predictor_var, response_var):
        # 単純ベイズ分類器またはナイーブベイズ分類器
        model_GaussianNB = GaussianNB()
        model_GaussianNB.fit(predictor_var, response_var)

        return model_GaussianNB
        
    def create_model_Perceptron(predictor_var, response_var):
        # パーセプトロン
        model_Perceptron = Perceptron()
        model_Perceptron.fit(predictor_var, response_var)

        return model_Perceptron

    def create_model_RandomForest(predictor_var, response_var):
        # Random Forest
        model_RandomForest = RandomForestClassifier(n_estimators=100)
        model_RandomForest.fit(predictor_var, response_var)

        return model_RandomForest

    if __name__ == '__main__':

        print("start")

        # データ取得
        df_train, df_test = get_data()

        # 前処理:pre_processing
        # pd.options.mode.chained_assignment = None
        for df in [df_train, df_test]:
            pre_processing(df)
        # pd.options.mode.chained_assignment = 'warn'

        # 変換後データの確認
        # read_datasets(df_train, df_test)


        # 特徴量の対象とする項目を決定
        lst_params = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]
        # lst_params = ["Pclass", "Sex", "Age", "Fare"]


        # 目的変数の値を取得
        response_var = df_train["Survived"].values

        # 説明変数の値を取得：追加となった項目も含めて予測モデルで使う値を抽出
        predictor_var = df_train[lst_params].values
        # テストからも説明変数の値を取得：実際の予測に使用するデータ
        test_predictor_var = df_test[lst_params].values

        # それぞれの結果格納用のDataFrameを用意する
        model_index = ["model_name","score","model"]
        df_models = pd.DataFrame(index=[], columns=model_index)

        # 確認するモデルリストを作成
        model_list = [  "DecisionTree", 
                        "LogisticRegression",
                        "Support Vector Machines",
                        "k近傍法(KNN)",
                        "Gaussian Naive Bayes",
                        "Perceptron","Random Forest"
                    ]

        for index, name in enumerate(model_list):
            print(index, name)
            model = None
            # print(index)
            if(name == "DecisionTree"):
                # 決定木
                model = create_model_DecisionTree(predictor_var, response_var)
            elif(name == "LogisticRegression"):
                # ロジスティック回帰
                model = create_model_LogisticRegression(predictor_var, response_var)
            elif(name == "Support Vector Machines"):
                # Support Vector Machines
                model = create_model_SVM(predictor_var, response_var)
            elif(name == "k近傍法(KNN)"):
                # k近傍法(KNN)
                model = create_model_KNeighbors(predictor_var, response_var)
            elif(name == "Gaussian Naive Bayes"):
                # 単純ベイズ分類器またはナイーブベイズ分類器(Gaussian Naive Bayes)
                model = create_model_GaussianNB(predictor_var, response_var)
            elif(name == "Perceptron"):
                # パーセプトロン
                model = create_model_Perceptron(predictor_var, response_var)
            elif(name == "Random Forest"):
                model = create_model_RandomForest(predictor_var, response_var)
            else:
                print("Don't Exist Model")
                continue

            evaluation_score = evaluation(model, predictor_var, response_var)
            df_models = df_models.append(pd.Series([name, evaluation_score, model], index=model_index),ignore_index=True)

        # scoreでソート
        df_sorted_models = df_models.sort_values(by='score', ascending=False)
        pprint.pprint(df_sorted_models)

        # 一番精度が高そうなモデルを使って、テストデータに対して予測
        model = df_sorted_models.iloc[0]["model"]
        prediction = model.predict(test_predictor_var)

        # 予測結果をファイルに出力
        output_file(prediction ,df_test , "prediction_{0:%Y%m%d%H%M%S}.csv".format(datetime.datetime.now()))

        print("end")


githubの方も更新しておく。
https://github.com/RyoNakamae/kaggle_titanic
※これ、更新しちゃうと前回の記事の意味がわからなくなるな・・・