[PYTHON] Prédiction de survivant utilisant le boost de xg titanesque de Kaggle [80,1%]

introduction

La dernière fois, j'ai regardé les données de train du Titanic pour voir quelles fonctionnalités sont liées au taux de survie. Dernière fois: Analyse des données avant la génération de fonctionnalités titanesques de Kaggle (J'espère que vous pouvez également lire cet article)

Sur la base du résultat, cette fois **, nous allons créer une base de données pour compléter les valeurs manquantes et ajouter les fonctionnalités nécessaires au modèle de prédiction **.

Cette fois-ci, comme modèle de prédiction, nous utiliserons "** GBDT (gradient boosting tree) xg boost **", qui est souvent utilisé dans les compétitions kaggle, donc nous rendrons les données adaptées.

1. Acquisition des données et confirmation des valeurs manquantes

import pandas as pd
import numpy as np

train = pd.read_csv('/kaggle/input/titanic/train.csv')
test = pd.read_csv('/kaggle/input/titanic/test.csv')
#Combinez les données de train et les données de test en un seul
data = pd.concat([train,test]).reset_index(drop=True)
#Vérifiez le nombre de lignes contenant des valeurs manquantes
train.isnull().sum()
test.isnull().sum()

Le numéro de chaque valeur manquante est le suivant.

données de train données de test
PassengerId 0 0
Survived 0
Pclass 0 0
Name 0 0
Sex 0 0
Age 177 86
SibSp 0 0
Parch 0 0
Ticket 0 0
Fare 0 1
Cabin 687 327
Embarked 2 0

2. Compléter les valeurs manquantes et créer des fonctionnalités

2.1 Complément tarifaire et classification

La ligne manquante avait une ** Pclass de 3 ** et ** Embarked était S **. スクリーンショット 2020-10-01 12.01.00.png Par conséquent, il est complété par la valeur médiane parmi ceux qui remplissent ces deux conditions. Après cela, le classement est effectué en tenant compte de la différence de taux de survie en fonction de la valeur du tarif et de la classe P.

#Achèvement de la valeur manquante
data['Fare'] = data['Fare'].fillna(data.query('Pclass==3 & Embarked=="S"')['Fare'].median())
#Classifié'Fare_bin'Mettre en
data['Fare_bin'] = 0
data.loc[(data['Fare']>=10) & (data['Fare']<50), 'Fare_bin'] = 1
data.loc[(data['Fare']>=50) & (data['Fare']<100), 'Fare_bin'] = 2
data.loc[(data['Fare']>=100), 'Fare_bin'] = 3

2.2 Différence de vie et de mort entre les groupes Création de la «survie de la famille»

Titanic [0.82] - [0.83] Création de la quantité de fonctionnalités "Family_survival" introduite dans ce code. Je vais.

** La famille et les amis sont plus susceptibles d'agir ensemble à bord **, on peut donc dire que le fait qu'ils aient survécu ou non ** a tendance à avoir le même résultat au sein du groupe **.

Par conséquent, le regroupement est effectué par le prénom et le nom et le numéro de ticket, et la valeur est déterminée par le fait que les membres du groupe sont en vie ou non.

#Obtenez le nom de famille du nom'Last_name'Mettre en
data['Last_name'] = data['Name'].apply(lambda x: x.split(",")[0])


data['Family_survival'] = 0.5 #Valeur par défaut
#Last_Regroupement par nom et tarif
for grp, grp_df in data.groupby(['Last_name', 'Fare']):
                               
    if (len(grp_df) != 1):
        #(Même nom)Et(Le tarif est le même)Quand il y a deux personnes ou plus
        for index, row in grp_df.iterrows():
            smax = grp_df.drop(index)['Survived'].max()
            smin = grp_df.drop(index)['Survived'].min()
            passID = row['PassengerId']
            
            if (smax == 1.0):
                data.loc[data['PassengerId'] == passID, 'Family_survival'] = 1
            elif (smin == 0.0):
                data.loc[data['PassengerId'] == passID, 'Family_survival'] = 0
            #À propos des membres autres que vous dans le groupe
            #Même une personne est en vie → 1
            #Aucun survivant(Y compris NaN) → 0
            #Tout NaN → 0.5

#Regroupement par numéro de billet
for grp, grp_df in data.groupby('Ticket'):
    if (len(grp_df) != 1):
        #Lorsqu'il y a deux personnes ou plus avec le même numéro de billet
        #S'il y a même un survivant dans le groupe'Family_survival'À 1
        for ind, row in grp_df.iterrows():
            if (row['Family_survival'] == 0) | (row['Family_survival']== 0.5):
                smax = grp_df.drop(ind)['Survived'].max()
                smin = grp_df.drop(ind)['Survived'].min()
                passID = row['PassengerId']
                if (smax == 1.0):
                    data.loc[data['PassengerId'] == passID, 'Family_survival'] = 1
                elif (smin == 0.0):
                    data.loc[data['PassengerId'] == passID, 'Family_survival'] = 0

2.3 Création et classification de la quantité de caractéristiques 'Taille_famille' représentant le nombre de membres de la famille

En utilisant les valeurs de SibSp et Parch, nous allons créer une quantité caractéristique «Taille de la famille» qui indique le nombre de familles à bord du Titanic, et les classer en fonction de leur taux de survie.

#Family_Création de taille
data['Family_size'] = data['SibSp']+data['Parch']+1
#1, 2~4, 5~Divisez en trois
data['Family_size_bin'] = 0
data.loc[(data['Family_size']>=2) & (data['Family_size']<=4),'Family_size_bin'] = 1
data.loc[(data['Family_size']>=5) & (data['Family_size']<=7),'Family_size_bin'] = 2
data.loc[(data['Family_size']>=8),'Family_size_bin'] = 3

2.4 Création du titre du titre 'Titre'

Obtenez des titres tels que «Monsieur», «Miss» dans la colonne Nom. Incorporez quelques titres («Mme», «Mlle», etc.) dans des titres qui ont la même signification.

#Obtenez le titre du nom'Title'Mettre en
data['Title'] = data['Name'].map(lambda x: x.split(', ')[1].split('. ')[0])
#Intégrez quelques titres
data['Title'].replace(['Capt', 'Col', 'Major', 'Dr', 'Rev'], 'Officer', inplace=True)
data['Title'].replace(['Don', 'Sir',  'the Countess', 'Lady', 'Dona'], 'Royalty', inplace=True)
data['Title'].replace(['Mme', 'Ms'], 'Mrs', inplace=True)
data['Title'].replace(['Mlle'], 'Miss', inplace=True)
data['Title'].replace(['Jonkheer'], 'Master', inplace=True)

2.5 Étiquetage du numéro de billet

Certains numéros de billets sont uniquement des chiffres et certains incluent des chiffres et des lettres. Après avoir séparé les deux, nous étiquetons chaque type de numéro de billet.

#Divisez en billets avec des chiffres uniquement et des billets avec des chiffres et des alphabets
#Obtenez un billet à numéro uniquement
num_ticket = data[data['Ticket'].str.match('[0-9]+')].copy()
num_ticket_index = num_ticket.index.values.tolist()
#Billets avec uniquement des numéros supprimés des données d'origine et le reste contient des alphabets
num_alpha_ticket = data.drop(num_ticket_index).copy()

#Classification des billets avec numéros seulement
#Le numéro du ticket étant une chaîne de caractères, il est converti en valeur numérique
num_ticket['Ticket'] = num_ticket['Ticket'].apply(lambda x:int(x))

num_ticket['Ticket_bin'] = 0
num_ticket.loc[(num_ticket['Ticket']>=100000) & (num_ticket['Ticket']<200000),
               'Ticket_bin'] = 1
num_ticket.loc[(num_ticket['Ticket']>=200000) & (num_ticket['Ticket']<300000),
               'Ticket_bin'] = 2
num_ticket.loc[(num_ticket['Ticket']>=300000),'Ticket_bin'] = 3

#Classification des billets avec numéros et alphabets
num_alpha_ticket['Ticket_bin'] = 4
num_alpha_ticket.loc[num_alpha_ticket['Ticket'].str.match('A.+'),'Ticket_bin'] = 5
num_alpha_ticket.loc[num_alpha_ticket['Ticket'].str.match('C.+'),'Ticket_bin'] = 6
num_alpha_ticket.loc[num_alpha_ticket['Ticket'].str.match('C\.*A\.*.+'),'Ticket_bin'] = 7
num_alpha_ticket.loc[num_alpha_ticket['Ticket'].str.match('F\.C.+'),'Ticket_bin'] = 8
num_alpha_ticket.loc[num_alpha_ticket['Ticket'].str.match('PC.+'),'Ticket_bin'] = 9
num_alpha_ticket.loc[num_alpha_ticket['Ticket'].str.match('S\.+.+'),'Ticket_bin'] = 10
num_alpha_ticket.loc[num_alpha_ticket['Ticket'].str.match('SC.+'),'Ticket_bin'] = 11
num_alpha_ticket.loc[num_alpha_ticket['Ticket'].str.match('SOTON.+'),'Ticket_bin'] = 12 
num_alpha_ticket.loc[num_alpha_ticket['Ticket'].str.match('STON.+'),'Ticket_bin'] = 13
num_alpha_ticket.loc[num_alpha_ticket['Ticket'].str.match('W\.*/C.+'),'Ticket_bin'] = 14

data = pd.concat([num_ticket,num_alpha_ticket]).sort_values('PassengerId')

2.6 Complémentation et classification par âge

Pour la valeur manquante de Age, il existe une méthode de ** médiane ** ou ** de trouver et de compléter l'âge moyen pour chaque titre du nom **, mais quand je l'ai recherché, il manquait ** en utilisant une forêt aléatoire. Il y avait une méthode ** pour prédire l'âge de la pièce où elle se trouve, donc cette fois je vais l'utiliser.

from sklearn.preprocessing import LabelEncoder
from sklearn.ensemble import RandomForestRegressor
#Étiquetage du montant de fonction qui est une chaîne de caractères
le = LabelEncoder()
data['Sex'] = le.fit_transform(data['Sex']) #Puisqu'il est utilisé pour la prédiction du taux de survie, l'étiquetage est accessoire
data['Title'] = le.fit_transform(data['Title'])
#La quantité de fonction utilisée pour prédire l'âge'age_data'Mettre en
age_data = data[['Age','Pclass','Family_size',
                 'Fare_bin','Title']].copy()
#Divisez en lignes où l'âge est manquant et en lignes où l'âge n'est pas manquant
known_age = age_data[age_data['Age'].notnull()].values  
unknown_age = age_data[age_data['Age'].isnull()].values

x = known_age[:, 1:]  
y = known_age[:, 0]
#Apprenez dans une forêt aléatoire
rfr = RandomForestRegressor(random_state=0, n_estimators=100, n_jobs=-1)
rfr.fit(x, y)
#Refléter la valeur prévue dans le bloc de données d'origine
age_predict = rfr.predict(unknown_age[:, 1:])
data.loc[(data['Age'].isnull()), 'Age'] = np.round(age_predict,1)

Vous avez maintenant complété la valeur manquante pour Age. スクリーンショット 2020-10-15 21.37.08.png

Et l'âge sera également classé.

data['Age_bin'] = 0
data.loc[(data['Age']>18) & (data['Age']<=60),'Age_bin'] = 1
data.loc[(data['Age']>60),'Age_bin'] = 2

Enfin, réduisez les fonctionnalités inutiles.

data = data.drop(['PassengerId','Name','Age','SibSp','Parch','Ticket',
                  'Fare','Cabin','Embarked','Last_name','Family_size'], axis=1)

En fin de compte, la trame de données ressemble à ceci.

Survived Pclass Sex Fare_bin Family_survival Family_size_bin Title Ticket_bin Age_bin
0 0.0 3 1 0 0.5 1 2 5 1
1 1.0 1 0 2 0.5 1 3 9 1
2 1.0 3 0 0 0.5 0 1 13 1
3 1.0 1 0 2 0.0 1 3 1 1
4 0.0 3 1 0 0.5 0 2 3 1
... ... ... ... ... ... ... ... ... ...
1304 NaN 3 1 0 0.5 0 2 5 1
1305 NaN 1 0 3 1.0 0 5 9 1
1306 NaN 3 1 0 0.5 0 2 12 1
1307 NaN 3 1 0 0.5 0 2 3 1
1308 NaN 3 1 1 1.0 1 0 0 0

1309 rows × 9 columns

Les données intégrées sont divisées en données de train et données de test, et le traitement des caractéristiques est terminé.

model_train = data[:891]
model_test = data[891:]

X = model_train.drop('Survived', axis=1)
Y = pd.DataFrame(model_train['Survived'])
x_test = model_test.drop('Survived', axis=1)

Prédiction de boost 3 xg

Regardons les performances du modèle en recherchant deux, ** logloss ** et ** exactitude **.

from sklearn.metrics import log_loss
from sklearn.metrics import accuracy_score
from sklearn.model_selection import KFold
import xgboost as xgb
#Définir les paramètres
params = {'objective':'binary:logistic',
          'max_depth':5,
          'eta': 0.1, 
          'min_child_weight':1.0,
          'gamma':0.0,
          'colsample_bytree':0.8,
          'subsample':0.8}

num_round = 1000

logloss = []
accuracy = []

kf = KFold(n_splits=4, shuffle=True, random_state=0)
for train_index, valid_index in kf.split(X):
    x_train, x_valid = X.iloc[train_index], X.iloc[valid_index] 
    y_train, y_valid = Y.iloc[train_index], Y.iloc[valid_index]
    #Convertir le bloc de données en une forme adaptée à l'augmentation de xg
    dtrain = xgb.DMatrix(x_train, label=y_train)
    dvalid = xgb.DMatrix(x_valid, label=y_valid)
    dtest = xgb.DMatrix(x_test)
    #Apprenez avec xgboost
    model = xgb.train(params, dtrain, num_round,evals=[(dtrain,'train'),(dvalid,'eval')],
                      early_stopping_rounds=50)
    
    valid_pred_proba = model.predict(dvalid)
    #Demander la perte de journal
    score = log_loss(y_valid, valid_pred_proba)
    logloss.append(score)
    #Trouvez la précision
    #valid_pred_Puisque proba est une valeur de probabilité, elle est convertie en 0 et 1.
    valid_pred = np.where(valid_pred_proba >0.5,1,0)
    acc = accuracy_score(y_valid, valid_pred)
    accuracy.append(acc)
    
print(f'log_loss:{np.mean(logloss)}')
print(f'accuracy:{np.mean(accuracy)}')

Avec ce code log_loss : 0.39114 accuracy : 0.8338 Le résultat était que.

Maintenant que le modèle est terminé, nous allons créer les données de prévision à soumettre à kaggle.

#Prédire avec prédire
y_pred_proba = model.predict(dtest)
y_pred= np.where(y_pred_proba > 0.5,1,0)
#Créer un bloc de données
submission = pd.DataFrame({'PassengerId':test['PassengerId'], 'Survived':y_pred})
submission.to_csv('titanic_xgboost.csv', index=False)

スクリーンショット 2020-10-15 21.54.44.png Le taux de réponse correcte était de ** 80,1% **, atteignant la limite de 80%.

Résumé

Cette fois, j'ai essayé de soumettre la valeur prévue à kaggle.

Au début, Cabin était également étiqueté et utilisé comme quantité de caractéristiques, mais ** la précision de la prédiction s'est améliorée lorsque Cabin n'était pas utilisé **. Après tout, il semble qu'il y avait trop de valeurs manquantes et ce n'était pas très approprié pour xg boost.

De plus, si vous effectuez des prédictions sans classifier des fonctionnalités telles que le tarif et l'âge, ** les valeurs de perte de log et de précision s'amélioreront **, mais ** le taux de précision des valeurs prévues ne s'améliorera pas **. J'ai senti qu'il serait possible de créer un modèle approprié sans surapprentissage en classant en fonction de la différence de taux de survie plutôt que d'utiliser le montant de la fonctionnalité tel quel.

Si vous avez des opinions ou des suggestions, nous vous serions reconnaissants de bien vouloir faire un commentaire ou une demande de modification.

Sites et livres auxquels j'ai fait référence

Kaggle Tutorial Titanic's Top 2% Know-how pyhaya’s diary Titanic [0.82] - [0.83] [Technologie d'analyse de données qui gagne avec Kaggle](https://www.amazon.co.jp/Kaggle%E3%81%A7%E5%8B%9D%E3%81%A4%E3%83%87%E3% 83% BC% E3% 82% BF% E5% 88% 86% E6% 9E% 90% E3% 81% AE% E6% 8A% 80% E8% A1% 93-% E9% 96% 80% E8% 84 % 87-% E5% A4% A7% E8% BC% 94-ebook / dp / B07YTDBC3Z)

Recommended Posts

Prédiction de survivant utilisant le boost de xg titanesque de Kaggle [80,1%]
Prédiction des survivants à l'aide du réseau neuronal titanesque de Kaggle [80,8%]
[Kaggle] Essayez d'utiliser xg boost
Comment configurer XG Boost à l'aide d'Optuna
Essayez le didacticiel Titanic de Kaggle
Prédiction de survie Titanic à l'aide de l'outil de gestion du flux de travail d'apprentissage automatique Kedro