[PYTHON] Prédiction de survie Titanic à l'aide de l'outil de gestion du flux de travail d'apprentissage automatique Kedro

introduction

Dans cet article, nous utiliserons une bibliothèque appelée Kedro pour créer un flux de travail de prédiction de survie Titanic.

Récemment, de nombreux types d'outils de gestion de flux de travail d'apprentissage automatique et d'outils d'aide à la construction sont apparus. Même si tu l'as entendu

Etc.

Comparons les performances de ces outils à travers un projet de prédiction commun! C'est le début de la rédaction de cet article.

En tant que projet commun, j'ai choisi Titanic Survival Prediction, qui est un chemin que tout le monde devrait emprunter lors du démarrage de l'analyse des données.

Alors, essayez d'abord depuis Kedro.

Voici pourquoi j'ai choisi Kedro:

«Il était populaire sur Twitter pendant un certain temps car il était facile à utiliser.

À propos de Kedro

kedro est un outil de gestion de flux de travail d'apprentissage automatique pour Python développé par la société d'analyse de données de McKinsey QuantumBlack.

Comme indiqué ci-dessous, c'est un outil utile pour gérer les expériences au stade PoC, mais d'un autre côté, il a des fonctions faibles pour la production.

Utilisation

Développement expérimental fluide de modèles d'apprentissage automatique

Ce que tu peux faire

--Création de répertoires et de modèles de code Python --Exécution en ligne de commande de la construction d'un modèle de traitement de données basé sur le pipeline décrit selon le format --Gestion des résultats de sortie et des objets de données intermédiaires

mérite

--Unifier la structure du répertoire et le format du code --Gestion facile des données et des objets intermédiaires --Facile à lire et à enregistrer automatiquement simplement en écrivant dans catalog.yml --Facile à spécifier les paramètres sur une base de texte --Si vous l'écrivez dans parameters.yml, vous pouvez facilement le lire avec une chaîne.

Je ne sais pas ce que je peux faire

--Rechargement des modèles et prétraitement des objets ―― Que dois-je faire si je veux faire des inférences sur de nouvelles données? ――En particulier, est-il possible de spécifier la version?

Choses impossibles

--Comparaison de la précision entre différents modèles --Il semble être complémentaire de MLflow

Exemple pratique de prédiction de survie du Titanic

Ci-dessous, je voudrais vous présenter comment utiliser Kedro, en utilisant Titanic, qui est familier dans l'analyse de données, à titre d'exemple.

Fondamentalement, il est créé en se référant au Tutoriel officiel. Le code a été téléchargé sur GitHub.

Flux de construction de flux de travail de base

  1. Créez un projet
  1. Préparation des données --Mettez les données brutes dans le répertoire data / 01_raw / et éditez catalog.yml.
  1. Construction d'un pipeline
  1. Exécution et stockage des données intermédiaires --De la ligne de commande kedro run --Si vous le définissez dans catalog.yml, il enregistrera le fichier intermédiaire.

Création de projet

Lorsque vous exécutez kedro new à partir de la ligne de commande, vous serez invité à entrer le nom du projet, le nom du référentiel et le nom du package comme indiqué ci-dessous.

$ kedro new

Project Name:
=============
Please enter a human readable name for your new project.
Spaces and punctuation are allowed.
 [New Kedro Project]: Titanic with Kedro
Repository Name:
================
Please enter a directory name for your new project repository.
Alphanumeric characters, hyphens and underscores are allowed.
Lowercase is recommended.
 [titanic-with-kedro]: titanic-with-kedro
Python Package Name:
====================
Please enter a valid Python package name for your project package.
Alphanumeric characters and underscores are allowed.
Lowercase is recommended. Package name must start with a letter or underscore.
 [titanic_with_kedro]: titanic_with_kedro
Generate Example Pipeline:
==========================
Do you want to generate an example pipeline in your project?
Good for first-time users. (default=N)
 [y/N]: N

Un répertoire de projet sera créé avec le nom que vous avez entré dans Nom du référentiel. En regardant à l'intérieur, cela ressemble à ce qui suit.

titanic-with-kedro
├── README.md
├── conf
│   ├── README.md
│   ├── base
│   │   ├── catalog.yml
│   │   ├── credentials.yml
│   │   ├── logging.yml
│   │   └── parameters.yml
│   └── local
├── data
│   ├── 01_raw
│   ├── 02_intermediate
│   ├── 03_primary
│   ├── 04_features
│   ├── 05_model_input
│   ├── 06_models
│   ├── 07_model_output
│   └── 08_reporting
├── docs
│   └── source
│       ├── conf.py
│       └── index.rst
├── errors.log
├── info.log
├── kedro_cli.py
├── logs
├── notebooks
├── references
├── results
├── setup.cfg
└── src
    ├── requirements.txt
    ├── setup.py
    ├── tests
    │   ├── __init__.py
    │   └── test_run.py
    └── titanic_with_kedro
        ├── __init__.py
        ├── nodes
        │   └── __init__.py
        ├── pipeline.py
        ├── pipelines
        │   └── __init__.py
        └── run.py

Le 'Nom du package Python' qui est demandé en cours de route est utilisé comme nom du répertoire qui place le code du pipeline généré sous src (cette fois titanic_with_kedro).

Enfin, il vous sera demandé «Voulez-vous générer un exemple de pipeline dans votre projet?», Mais si vous appuyez sur y ici, le code du didacticiel sera généré sous forme d'ensemble. Puisqu'il est inutile à partir de la deuxième fois, appuyez sur Entrée sans saisir N.

Préparation des données

Cette fois, je vais récupérer les données de kaggle en utilisant l'API et les mettre dans data / 01_raw /. L'inscription à kaggle et l'acquisition du jeton d'authentification sont requises séparément.

$ cd data/01_raw/
$ kaggle competitions download -c titanic
$ unzip titanic.zip

En plus de cela, modifiez le catalogue de données comme suit.

conf/base/catalog.yml


train:
    type: CSVLocalDataSet
    filepath: data/01_raw/train.csv

test:
    type: CSVLocalDataSet
    filepath: data/01_raw/test.csv

Les noms de données «train» et «test» sont également utilisés lors de la lecture des données. Avec type:, vous pouvez sélectionner le format de lecture des données préparé par kedro à l'avance. [^ 2]

[^ 2]: vous pouvez également appliquer une fonction de chargement de données personnalisée.

Essayons de voir si les données peuvent être lues.

Exécutez la commande kedro suivante pour lancer le notebook Jupyter (ou IPython). Le notebook démarre avec le catalogue pour lire les données importées à l'avance [^ 3].

$ kedro jupyter notebook
df_train = catalog.load("train")
df_train.head()

[^ 3]: Par défaut, il peut ne pas être possible de s'exécuter en raison d'une erreur de chargement du module. Dans ce cas, ouvrez src / <nom-projet> / pipeline.py et supprimez l'importation de module pour le didacticiel.

Construction d'un pipeline

Définition du nœud et du pipeline

Décrivez le pipeline de prétraitement des données selon le format kedro.

src/titanic_with_kedro/pipelines/data_engineering/pipeline.py


from kedro.pipeline import node, Pipeline
from titanic_with_kedro.nodes import preprocess


def create_pipeline(**kwargs):
    return Pipeline(
        [
            node(
                func=preprocess.preprocess,
                inputs="train",
                outputs="train_prep",
                name="preprocess",
            ),
        ],
        tags=['de_tag'],
    )

L'unité de traitement "node" est stockée dans la classe "Pipeline" fournie par kedro.

Pour la fonction node,

--func: fonction qui décrit le processus --inputs: nom des données d'entrée --outputs: nom des données de sortie --name: nom du nœud

Est spécifié.

Le traitement effectué par node est spécifié en passant un objet fonction à l'argument func.

Dans cet exemple, la fonction preprocess () est utilisée comme un nœud pour compléter les valeurs manquantes et effectuer le codage des étiquettes.

A ce moment, les données spécifiées par l'argument ʻinputs sont utilisées pour l'entrée de la fonction preprocess () `. Dans l'exemple ci-dessus, «train» est spécifié, mais cela pointe vers les données de «train» définies dans le catalogue de données ci-dessus «conf / base / catalog.yml» et le format de données décrit dans le catalogue. Il lira le fichier et l'entrera en fonction du chemin.

L'objet de sortie reçoit alors l'étiquette spécifiée par ʻoutputs`. Lorsque vous utilisez cet objet dans un traitement ultérieur, vous pouvez le spécifier avec cette étiquette et l'appeler.

La fonction de prétraitement spécifiée dans node cette fois est la suivante. Contrairement au pipeline, il n'est pas nécessaire d'utiliser une méthode de description spéciale.

(La fonction _label_encoding () est une fonction auxiliaire)

src/titanic_with_kedro/nodes/preprocess.py


import pandas as pd
from sklearn import preprocessing


def _label_encoding(df: pd.DataFrame) -> (pd.DataFrame, dict):
    
    df_le = df.copy()
    # Getting Dummies from all categorical vars
    list_columns_object = df_le.columns[df_le.dtypes == 'object']
    
    dict_encoders = {}
    for column in list_columns_object:    
        le = preprocessing.LabelEncoder()
        mask_nan = df_le[column].isnull()
        df_le[column] = le.fit_transform(df_le[column].fillna('NaN'))
        
        df_le.loc[mask_nan, column] *= -1  # transform minus for missing records
        dict_encoders[column] = le
    
    return df_le, dict_encoders


def preprocess(df: pd.DataFrame) -> pd.DataFrame:
    
    df_prep = df.copy()
    
    drop_cols = ['Name', 'Ticket', 'PassengerId']
    df_prep = df_prep.drop(drop_cols, axis=1)
    
    df_prep['Age'] = df_prep['Age'].fillna(df_prep['Age'].mean())

    # Filling missing Embarked values with most common value
    df_prep['Embarked'] = df_prep['Embarked'].fillna(df_prep['Embarked'].mode()[0])

    df_prep['Pclass'] = df_prep['Pclass'].astype(str)

    # Take the frist alphabet from Cabin
    df_prep['Cabin'] = df_prep['Cabin'].str[0]

    # Label Encoding for str columns
    df_prep, _ = _label_encoding(df_prep)
    
    return df_prep

Intégration de plusieurs pipelines

Vous pouvez également combiner plusieurs pipelines créés.

Cette fois j'ai défini la construction du modèle dans un autre pipelinesrc / titanic_with_kedro / pipelines / data_science / pipeline.py.

Pour combiner cela avec le prétraitement précédent, procédez comme suit:

src/titanic_with_kedro/pipeline.py


from typing import Dict

from kedro.pipeline import Pipeline
from titanic_with_kedro.pipelines.data_engineering import pipeline as de
from titanic_with_kedro.pipelines.data_science import pipeline as ds


def create_pipelines(**kwargs) -> Dict[str, Pipeline]:
    """Create the project's pipeline.

    Args:
        kwargs: Ignore any additional arguments added in the future.

    Returns:
        A mapping from a pipeline name to a ``Pipeline`` object.

    """

    de_pipeline = de.create_pipeline()
    ds_pipeline = ds.create_pipeline()

    return {
        "de": de_pipeline,
        "ds": ds_pipeline,
        "__default__": de_pipeline + ds_pipeline,
    }

Le pipeline de création de modèles est défini comme suit.

src/titanic_with_kedro/pipelines/data_science/pipeline.py


from kedro.pipeline import node, Pipeline
from titanic_with_kedro.nodes import modeling


def create_pipeline(**kwargs):
    return Pipeline(
        [
            node(
                func=modeling.split_data,
                inputs=["train_prep", "parameters"],
                outputs=["X_train", "X_test", "y_train", "y_test"],
            ),
            node(func=modeling.train_model,
                 inputs=["X_train", "y_train"],
                 outputs="clf"),
            node(
                func=modeling.evaluate_model,
                inputs=["clf", "X_test", "y_test"],
                outputs=None,
            ),
        ],
        tags=["ds_tag"],
    )

De cette façon, vous pouvez placer plusieurs nœuds dans un pipeline.

Exécution et stockage des données intermédiaires

Après avoir défini le pipeline, émettez une commande d'exécution à partir de la racine du projet.

$ kedro run

En faisant cela, src / <nom_projet> / pipeline.py sera appelé et le processus sera exécuté.

À ce stade, si vous souhaitez enregistrer les données intermédiaires après le prétraitement et le modèle créé (forêt aléatoire cette fois), ajoutez ce qui suit au catalogue de données.

conf/base/catalog.yml


train_prep:
    type: CSVLocalDataSet
    filepath: data/02_intermediate/train_prep.csv

clf:
    type: PickleLocalDataSet
    filepath: data/06_models/classifier.pickle
    versioned: true

train_prep et clf font référence aux données prétraitées et au modèle entraîné, respectivement, mais lors de la définition du pipeline, le nom spécifié dans l'argument ʻoutputs de la fonction node` est reconnu tel quel, et il est défini sur le chemin de format spécifié. Cela le sauvera.

De plus, si vous définissez versionné sur true, il sera enregistré dans un répertoire différent à chaque exécution [^ 4].

[^ 4]: Dans ce cas, une nouvelle heure est créée sous data / 06_models / classifier.pickle / au moment de l'exécution, et data / 06_models / classifier.pickle / 2020-02-22T06.26.54.486Z Il sera enregistré sous / classifier.pickle.

Autres fonctions utiles

Les fonctions de base sont comme ci-dessus, mais il y a aussi les fonctions suivantes.

Créer un nœud directement à partir du notebook Jupyter

Lors de la création d'un code d'exécution, je pense qu'il y a beaucoup de gens qui l'écrivent en l'exécutant un par un avec le notebook Jupyter sans l'écrire dans un fichier .py depuis le début.

Dans ce cas, il est difficile de réécrire le code en .py plus tard, mais si vous utilisez le cli de kedro, seule la partie spécifiée du code sera crachée vers .py.

Pour ce faire, lancez d'abord Jupyter à partir du cli de kedro.

$ kedro jupyter notebook

Ensuite, ajoutez la balise node uniquement aux cellules que vous souhaitez écrire dans .py. Pour le balisage, sélectionnez Affichage> Barre d'outils Cellule> Balises dans le menu en haut de l'écran. Étant donné que la fenêtre de saisie des balises est affichée en haut de chaque cellule, saisissez node pour l'ajouter.

スクリーンショット 2020-02-23 19.31.18.png スクリーンショット 2020-02-23 19.33.06.png

Ensuite, si vous exécutez ce qui suit à partir de la ligne de commande, seule la partie balisée sera extraite et src / <nom du projet> / nœuds / <nom du notebook> .py sera généré.

kedro jupyter convert notebooks/<notebook name>.ipynb


Référence
https://kedro.readthedocs.io/en/latest/04_user_guide/11_ipython.html

Gestion des paramètres

Vous pouvez également lire les paramètres spécifiés dans le fichier externe lors de la définition du pipeline.

En regardant à nouveau les paramètres de construction du modèle ci-dessus, il y a un endroit où «paramètres» est spécifié dans les entrées.

src/titanic_with_kedro/pipelines/data_science/pipeline.py


#réduction

def create_pipeline(**kwargs):
    return Pipeline(
        [
            node(
                func=modeling.split_data,
                inputs=["train_prep", "parameters"],
                outputs=["X_train", "X_test", "y_train", "y_test"],

#réduction

Ce qui précède est la partie à diviser en données d'entraînement et données de test.

"" parameters "" fait référence au fichier "parameters.yml" dans le répertoire "conf / base".

conf/base/parameters.yml


test_size: 0.2
random_state: 17

Ce faisant, vous pouvez le passer automatiquement en tant qu'objet de type dictionnaire à l'argument de la fonction de nœud et y faire référence comme indiqué ci-dessous.

#réduction

def split_data(data: pd.DataFrame, parameters: Dict) -> List:
    """Splits data into training and test sets.

        Args:
            data: Source data.
            parameters: Parameters defined in parameters.yml.

        Returns:
            A list containing split data.

    """
    target_col = 'Survived'
    X = data.drop(target_col, axis=1).values
    y = data[target_col].values

    X_train, X_test, y_train, y_test = train_test_split(
        X, y, test_size=parameters["test_size"], random_state=parameters["random_state"]
    )

    return [X_train, X_test, y_train, y_test]

#réduction

Résumé

Comme mentionné ci-dessus, après avoir expliqué comment utiliser Kedro, j'ai essayé de faire une prédiction Titanic.

Défi: sauvegarde et versioning des objets de prétraitement

Le flux prévu ci-dessus est défectueux.

Si vous êtes habitué à l'analyse de données, vous l'avez peut-être remarqué.

Cela peut être mentionné.

Surtout pour le premier, il existe un risque de fuite car les informations de données de test sont mélangées aux données d'apprentissage lors de la saisie des valeurs manquantes et du codage des étiquettes.

Les deux problèmes peuvent être résolus en écrivant la partie de prétraitement dans une classe et en consolidant l'instance avec pickle afin qu'elle puisse être lue et utilisée plus tard.

La solution n'est pas si difficile, et on s'attend à ce qu'elle puisse être réalisée en ajoutant un objet de prétraitement à la sortie du nœud, en éditant catalog.yml et en l'enregistrant au moment de l'exécution.

Cependant, il existe un problème de gestion des versions.

Si la pièce de prétraitement et le modèle sont enregistrés avec la gestion des versions, comment les objets de prétraitement de la version correspondant à chaque modèle doivent-ils être liés?

Par exemple, supposons que vous souhaitiez réécrire la pièce de prétraitement pour créer un modèle et faire ultérieurement des inférences avec l'ancien modèle. À ce stade, si le nouveau code de prétraitement n'est pas compatible avec l'ancien modèle, l'objet de prétraitement doit également être remplacé par celui utilisé lors de la création de l'ancien modèle.

Pour ce faire sans effort, un certain marquage ou une attribution d'ID d'exécution est nécessaire, mais il n'est pas confirmé si Kedro peut le faire. [^ 5]

[^ 5]: Dans MLflow et Metaflow, il est possible de lire le modèle et les objets intermédiaires en spécifiant l'ID d'exécution. Si bien combiné avec ceux-ci, il peut être possible ...

D'autres pensées

De plus, il y a quelques points sur lesquels j'ai pensé "J'aurais aimé avoir cette fonction ..." quand j'ai touché Kedro.

il y a.

Le premier peut être altéré.

Ce dernier est probablement hors du champ d'application de Kedro, il semble donc que nous devions l'utiliser en combinaison avec d'autres outils. Plus précisément, MLflow de Databricks semble être juste. En fait, un article écrit par le développeur Kedro Quantum Black discute également de la combinaison avec MLflow. Il existe également une bibliothèque appelée PipelineX qui combine les deux.

Lien de référence

Recommended Posts

Prédiction de survie Titanic à l'aide de l'outil de gestion du flux de travail d'apprentissage automatique Kedro
[Apprentissage automatique] Prédiction FX à l'aide de l'arbre de décision
J'ai essayé d'utiliser Tensorboard, un outil de visualisation pour l'apprentissage automatique
Développement d'applications à l'aide d'Azure Machine Learning
Créez un modèle de prédiction de survie pour les passagers du Kaggle Titanic sans utiliser Python
Prédiction des survivants à l'aide du réseau neuronal titanesque de Kaggle [80,8%]
Prévision du cours des actions à l'aide de l'apprentissage automatique (scikit-learn)
[Apprentissage automatique] Classification des sujets LDA à l'aide de scikit-learn
Prédiction de survivant utilisant le boost de xg titanesque de Kaggle [80,1%]
[Apprentissage automatique] Apprentissage supervisé utilisant l'estimation de la densité du noyau
Prévision du cours des actions à l'aide de l'apprentissage automatique (édition de retour)
[Apprentissage automatique] Analyse de régression à l'aide de scicit learn
Jusqu'au lancement d'un site de triple prédiction de course de bateaux utilisant l'apprentissage automatique et Flask
J'ai essayé d'implémenter diverses méthodes d'apprentissage automatique (modèle de prédiction) en utilisant scicit-learn