[PYTHON] Concours de prédiction de données en 3 étapes (titanesque)

Après avoir lu les articles de Kaggle, j'ai personnellement pensé que l'analyse des données pouvait être résumée en trois étapes.

Étape 1: Ingénierie des fonctionnalités Étape 2: Sélection de l'apprenant et ajustement des hyper paramètres Étape 3: Ensemble

Après avoir terminé les trois étapes ci-dessus, le modèle sera décidé, alors appliquez les données de test (données pour soumettre des prévisions) au modèle pour faire des prédictions et les soumettre. (Jusque-là, ne soumettez pas et n'évaluez pas les performances par la valeur de validation croisée.) Étant donné que la validation croisée est effectuée au moins une fois en une étape, la validation croisée sera effectuée au moins trois fois au total.

Étape 1: Ingénierie des fonctionnalités

Considérez les fonctionnalités qui peuvent être utilisées dans EDA (Exploratory Data Analysis), etc., et créez de nouvelles fonctionnalités si nécessaire. Pensez également aux fuites de données. Il effectue également un prétraitement tel que le traitement des valeurs manquantes. Finalement, l'apprenant est configuré et RFE (élimination des fonctionnalités récursives) est utilisé pour supprimer les fonctionnalités inutiles. À ce stade, la validation croisée est utilisée pour l'évaluation. Vous pouvez également voir l'importance de la quantité de caractéristiques avec l'apprenant de type d'arbre de décision. Pour les données complexes telles que les images et le texte, envisagez d'extraire des fonctionnalités à l'aide d'un réseau neuronal.

Étape 2: Sélection de l'apprenant et ajustement des hyper paramètres

C'est une bonne idée d'essayer tout ce que vous pouvez imaginer en tant qu'apprenant. (Parce que ça peut être un ensemble plus tard.) Le réglage des hyper paramètres peut également être une recherche de grille, une recherche aléatoire et plus récemment une optimisation bayésienne avec optuna. Cela crée un état où chaque apprenant peut obtenir le score le plus élevé. Supprimer les apprenants dont les résultats d'évaluation des performances sont trop faibles.

Étape 3: Ensemble

Il résume les résultats de chaque apprenant. S'il n'y a qu'un seul apprenant, il ne peut pas être ensemble, de sorte que l'apprenant est le modèle final. Vous pouvez simplement voter ou dire, ou vous pouvez empiler des mélangeurs et les empiler. Lors de l'empilement, il est également nécessaire d'ajuster les hyper paramètres de l'apprenant qui devient le mixeur. De plus, le résultat de l'évaluation peut être meilleur sans ensemble, auquel cas il s'agit de se demander lequel sera le modèle final. (Il peut être préférable de soumettre les deux.)

À propos de la validation croisée

La validation croisée est souvent utilisée comme méthode d'évaluation des performances du modèle. C'est fait avec K-Fold, mais en gros, il vaut mieux avoir un grand nombre de K. (Cependant, cela prend du temps s'il y a beaucoup de K.) De plus, le KFold stratifié et l'extraction aléatoire sont effectués afin d'éviter tout déséquilibre des données. L'évaluation des performances porte non seulement sur le score moyen de chaque pli, mais aussi sur l'écart type.

Exemple d'implémentation en compétition titanesque

Articles référencés https://www.kaggle.com/ldfreeman3/a-data-science-framework-to-achieve-99-accuracy http://maruo51.com/2019/04/07/titanic-3/ https://yolo-kiyoshi.com/2020/01/22/post-1588/

Ingénierie de la quantité de fonctionnalités

EDA est omis. Une forêt aléatoire a été utilisée pour RFE.

import pandas as pd 
import numpy as np

data_train = pd.read_csv('./input/train.csv')
data_test  = pd.read_csv('./input/test.csv')
data_train_raw = data_train.copy(deep = True) #Faire une copie des données originales
data_test_raw = data_test.copy(deep = True) #Faire une copie des données originales
data_cleaner = [data_train, data_test]#La combinaison sous forme de liste est pratique car vous pouvez également utiliser la source de copie ensemble.
#À propos, la jointure dans le bloc de données est des données_all = pd.concat([data_train, data_test], sort=False)Peut être fait avec

#Supprimer les inutilisés
drop_column = ['PassengerId','Cabin', 'Ticket','Name']
data_train.drop(drop_column, axis=1, inplace = True)
#Remplacement de valeur manquante
for dataset in data_cleaner:    
    dataset['Age'].fillna(dataset['Age'].median(), inplace = True)
    dataset['Embarked'].fillna(dataset['Embarked'].mode()[0], inplace = True)
    dataset['Fare'].fillna(dataset['Fare'].median(), inplace = True)
#Créer de nouvelles fonctionnalités
for dataset in data_cleaner:    
    dataset['FamilySize'] = dataset ['SibSp'] + dataset['Parch'] + 1
    dataset['IsAlone'] = 1
    dataset['IsAlone'].loc[dataset['FamilySize'] > 1] = 0 
#Encodage des étiquettes
from sklearn.preprocessing import LabelEncoder
label = LabelEncoder()
for dataset in data_cleaner:    
    dataset['Sex_Code'] = label.fit_transform(dataset['Sex'])
    dataset['Embarked_Code'] = label.fit_transform(dataset['Embarked'])
drop_column = ['Sex','Embarked']
data_train.drop(drop_column, axis=1, inplace = True)
# x,Obtenez l'étiquette de y
lavel_y = "Survived"
lavel_x = data_train.columns.values[1:]

#RFE dans Random Forest(Élimination des fonctionnalités récursives)
from sklearn.model_selection import StratifiedKFold
from sklearn.feature_selection import RFECV
from sklearn.ensemble import RandomForestClassifier
NFOLD = 20 #Nombre de plis fractionnés CV
kf = StratifiedKFold(n_splits=NFOLD, shuffle=True, random_state=0)
rfe = RFECV(RandomForestClassifier(random_state = 0), scoring = 'accuracy', cv = kf)
rfe.fit(data_train[lavel_x], data_train[lavel_y])
f_importances = pd.DataFrame({"features":lavel_x,"select":rfe.get_support()})
print(f_importances) #Affichage des résultats RFE
#Confirmer les données de quantité de fonction à utiliser
X_train = rfe.transform(data_train[lavel_x])
X_test = rfe.transform(data_test[lavel_x])
Y_train = data_train[lavel_y]

Sélection de l'apprenant et ajustement des hyper paramètres

En utilisant Random Forest, XGBoost et LightGBM comme apprenants, nous avons effectué des recherches d'hyperparamètres sur Optuna.

from sklearn.model_selection import cross_validate
from xgboost import XGBClassifier
from lightgbm import LGBMClassifier
import optuna

#Forêt aléatoire
def objective(trial):
    param_grid_rfc = {
        "max_depth": trial.suggest_int("max_depth", 5, 15),
        "min_samples_leaf": trial.suggest_int("min_samples_leaf", 1, 5),
        'min_samples_split': trial.suggest_int("min_samples_split", 7, 15),
        "criterion": trial.suggest_categorical("criterion", ["gini", "entropy"]),
        'max_features': trial.suggest_int("max_features", 3, 10),
        "random_state": 0
    }
    model = RandomForestClassifier(**param_grid_rfc)
    scores = cross_validate(model, X=X_train, y=Y_train, cv=kf)
    return scores['test_score'].mean()
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=100)
print(study.best_params)
print(study.best_value)
rfc_best_param = study.best_params

# XGBoost
def objective(trial):   
    param_grid_xgb = {
        'min_child_weight': trial.suggest_int("min_child_weight", 1, 5),
        'gamma': trial.suggest_discrete_uniform("gamma", 0.1, 1.0, 0.1),
        'subsample': trial.suggest_discrete_uniform("subsample", 0.5, 1.0, 0.1),
        'colsample_bytree': trial.suggest_discrete_uniform("colsample_bytree", 0.5, 1.0, 0.1),
        'max_depth': trial.suggest_int("max_depth", 3, 10),
        "random_state": 0
    }
    model = XGBClassifier(**param_grid_xgb)
    scores = cross_validate(model, X=X_train, y=Y_train, cv=kf)
    return scores['test_score'].mean()
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=100)
print(study.best_params)
print(study.best_value)
xgb_best_param = study.best_params

# LightGBM
def objective(trial):
    param_grid_lgb = {
        'num_leaves': trial.suggest_int("num_leaves", 3, 10),
        'learning_rate': trial.suggest_loguniform("learning_rate", 1e-8, 1.0),
        'max_depth': trial.suggest_int("max_depth", 3, 10),
        "random_state": 0
    }
    model = LGBMClassifier(**param_grid_lgb)
    scores = cross_validate(model, X=X_train, y=Y_train, cv=kf)
    return scores['test_score'].mean()
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=100)
print(study.best_params)
print(study.best_value)
lgb_best_param = study.best_params

ensemble

Assemblé par vote à la majorité.

from sklearn.ensemble import VotingClassifier
estimators = [
    ('rfc', RandomForestClassifier(**rfc_best_param)),
    ('xgb', XGBClassifier(**xgb_best_param)),
    ('lgb', LGBMClassifier(**lgb_best_param)),
]
voting = VotingClassifier(estimators)
scores = cross_validate(voting, X=X_train, y=Y_train, cv=kf)
print(scores["test_score"].mean())
print(scores["test_score"].std())

Puisque le résultat de l'ensemble semble être le meilleur, je le prédis avec ce modèle et fais un dossier de soumission.

voting.fit(X_train, Y_train)
data_test['Survived'] = voting.predict(X_test)
submit = data_test[['PassengerId','Survived']]
submit.to_csv("./submit.csv", index=False)

finalement

La valeur de validation croisée était d'environ 0,85, ce qui semblait plutôt bon, mais pas si bon avec PLB. Il y a beaucoup de choses que vous pouvez concevoir, comme comment créer des fonctionnalités, la sélection des apprenants dans RFE, le nombre de KFolds, la sélection des apprenants, la sélection de la plage d'hyperparamètres, la sélection de la méthode d'ensemble, etc. Je pense qu'ils peuvent l'améliorer encore plus.

Recommended Posts

Concours de prédiction de données en 3 étapes (titanesque)
Analyse des données Titanic 2
Analyse des données Titanic 1
Analyse des données Titanic 3
Arrêtez de penser à une utilisation dans les concours d'analyse de données
Concours de science des données OPT
Gérer les données ambiantes en Python
Manipuler des données en Python-essayez avec Pandas_plyr
Afficher les données UTM-30LX en Python
Écrire des données au format HDF
Prédiction de probabilité de données déséquilibrées