La journée communautaire ML est le 9 novembre ! Rejoignez - nous pour les mises à jour de tensorflow, JAX et plus En savoir plus

Construire un modèle linéaire avec les estimateurs

Voir sur TensorFlow.org Exécuter dans Google Colab Voir la source sur GitHub Télécharger le cahier

Aperçu

Cette procédure pas à pas de bout en bout forme un modèle de régression logistique utilisant la tf.estimator API. Le modèle est souvent utilisé comme référence pour d'autres algorithmes plus complexes.

Installer

pip install sklearn
import os
import sys

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import clear_output
from six.moves import urllib

Charger le jeu de données titanesque

Vous utiliserez l'ensemble de données Titanic dans le but (plutôt morbide) de prédire la survie des passagers, compte tenu de caractéristiques telles que le sexe, l'âge, la classe, etc.

import tensorflow.compat.v2.feature_column as fc

import tensorflow as tf
# Load dataset.
dftrain = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/train.csv')
dfeval = pd.read_csv('https://storage.googleapis.com/tf-datasets/titanic/eval.csv')
y_train = dftrain.pop('survived')
y_eval = dfeval.pop('survived')

Explorer les données

L'ensemble de données contient les caractéristiques suivantes

dftrain.head()
dftrain.describe()

Il y a respectivement 627 et 264 exemples dans les ensembles de formation et d'évaluation.

dftrain.shape[0], dfeval.shape[0]
(627, 264)

La majorité des passagers ont entre 20 et 30 ans.

dftrain.age.hist(bins=20)
<AxesSubplot:>

png

Il y a environ deux fois plus de passagers hommes que de femmes à bord.

dftrain.sex.value_counts().plot(kind='barh')
<AxesSubplot:>

png

La majorité des passagers étaient dans la "troisième" classe.

dftrain['class'].value_counts().plot(kind='barh')
<AxesSubplot:>

png

Les femmes ont beaucoup plus de chances de survivre que les hommes. Il s'agit clairement d'une caractéristique prédictive du modèle.

pd.concat([dftrain, y_train], axis=1).groupby('sex').survived.mean().plot(kind='barh').set_xlabel('% survive')
Text(0.5, 0, '% survive')

png

Ingénierie des fonctionnalités pour le modèle

Estimateurs utilisent un système appelé colonnes de fonction pour décrire la façon dont le modèle doit interpréter chacune des caractéristiques d'entrée brutes. Un estimateur attend un vecteur d'entrées numériques et des colonnes de caractéristiques décrivent comment le modèle doit convertir chaque fonction.

La sélection et la création du bon ensemble de colonnes de fonctionnalités sont essentielles pour apprendre un modèle efficace. Une colonne de fonction peut être soit l' une des entrées brutes dans les caractéristiques d' origine dict (une colonne de fonction de base), ou de nouvelles colonnes créées à l' aide des transformations définies sur une ou plusieurs colonnes de base (a colonnes d'entités dérivées).

L'estimateur linéaire utilise à la fois des caractéristiques numériques et catégorielles. Les colonnes de caractéristiques fonctionnent avec tous les estimateurs TensorFlow et leur objectif est de définir les caractéristiques utilisées pour la modélisation. De plus, ils fournissent des fonctionnalités d'ingénierie de fonctionnalités telles que l'encodage à chaud, la normalisation et la compartimentation.

Colonnes d'entités de base

CATEGORICAL_COLUMNS = ['sex', 'n_siblings_spouses', 'parch', 'class', 'deck',
                       'embark_town', 'alone']
NUMERIC_COLUMNS = ['age', 'fare']

feature_columns = []
for feature_name in CATEGORICAL_COLUMNS:
  vocabulary = dftrain[feature_name].unique()
  feature_columns.append(tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary))

for feature_name in NUMERIC_COLUMNS:
  feature_columns.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float32))

Les input_function spécifie comment les données sont converties en un tf.data.Dataset qui alimente le pipeline d'entrée de façon streaming. tf.data.Dataset peut prendre plusieurs sources comme un dataframe, un fichier au format csv, et plus encore.

def make_input_fn(data_df, label_df, num_epochs=10, shuffle=True, batch_size=32):
  def input_function():
    ds = tf.data.Dataset.from_tensor_slices((dict(data_df), label_df))
    if shuffle:
      ds = ds.shuffle(1000)
    ds = ds.batch(batch_size).repeat(num_epochs)
    return ds
  return input_function

train_input_fn = make_input_fn(dftrain, y_train)
eval_input_fn = make_input_fn(dfeval, y_eval, num_epochs=1, shuffle=False)

Vous pouvez inspecter l'ensemble de données :

ds = make_input_fn(dftrain, y_train, batch_size=10)()
for feature_batch, label_batch in ds.take(1):
  print('Some feature keys:', list(feature_batch.keys()))
  print()
  print('A batch of class:', feature_batch['class'].numpy())
  print()
  print('A batch of Labels:', label_batch.numpy())
Some feature keys: ['sex', 'age', 'n_siblings_spouses', 'parch', 'fare', 'class', 'deck', 'embark_town', 'alone']

A batch of class: [b'Third' b'Third' b'Second' b'Third' b'First' b'First' b'Third' b'Third'
 b'Third' b'Third']

A batch of Labels: [0 1 0 1 1 0 0 0 1 1]

Vous pouvez également vérifier le résultat d'une colonne de fonction spécifique en utilisant la tf.keras.layers.DenseFeatures couche:

age_column = feature_columns[7]
tf.keras.layers.DenseFeatures([age_column])(feature_batch).numpy()
array([[ 9.  ],
       [24.  ],
       [23.  ],
       [28.  ],
       [24.  ],
       [40.  ],
       [31.  ],
       [36.  ],
       [28.  ],
       [ 0.75]], dtype=float32)

DenseFeatures accepte que tenseurs denses, pour inspecter une colonne catégorique que vous devez transformer ce à une colonne de premier indicateur:

gender_column = feature_columns[0]
tf.keras.layers.DenseFeatures([tf.feature_column.indicator_column(gender_column)])(feature_batch).numpy()
array([[0., 1.],
       [0., 1.],
       [1., 0.],
       [0., 1.],
       [0., 1.],
       [1., 0.],
       [0., 1.],
       [1., 0.],
       [1., 0.],
       [0., 1.]], dtype=float32)

Après avoir ajouté toutes les fonctionnalités de base au modèle, entraînons le modèle. La formation d' un modèle est juste une seule commande en utilisant l' tf.estimator API:

linear_est = tf.estimator.LinearClassifier(feature_columns=feature_columns)
linear_est.train(train_input_fn)
result = linear_est.evaluate(eval_input_fn)

clear_output()
print(result)
{'accuracy': 0.74242425, 'accuracy_baseline': 0.625, 'auc': 0.83409864, 'auc_precision_recall': 0.79196465, 'average_loss': 0.48227197, 'label/mean': 0.375, 'loss': 0.47621801, 'precision': 0.64761907, 'prediction/mean': 0.4210519, 'recall': 0.68686867, 'global_step': 200}

Colonnes d'entités dérivées

Vous avez maintenant atteint une précision de 75 %. L'utilisation séparée de chaque colonne d'entités de base peut ne pas suffire à expliquer les données. Par exemple, la corrélation entre l'âge et l'étiquette peut être différente selon le sexe. Par conséquent, si vous apprenez qu'un seul poids de modèle pour le gender="Male" et gender="Female" , vous ne serez pas saisir toutes les combinaisons âge-sexe (par exemple , distinction entre le gender="Male" et age="30" ET gender="Male" et age="40" ).

Pour connaître les différences entre les différentes combinaisons de caractéristiques, vous pouvez ajouter des colonnes croisées de fonction au modèle (vous pouvez aussi bucketize colonne d'âge avant la colonne croix):

age_x_gender = tf.feature_column.crossed_column(['age', 'sex'], hash_bucket_size=100)

Après avoir ajouté la fonction de combinaison au modèle, entraînons à nouveau le modèle :

derived_feature_columns = [age_x_gender]
linear_est = tf.estimator.LinearClassifier(feature_columns=feature_columns+derived_feature_columns)
linear_est.train(train_input_fn)
result = linear_est.evaluate(eval_input_fn)

clear_output()
print(result)
{'accuracy': 0.7689394, 'accuracy_baseline': 0.625, 'auc': 0.8474442, 'auc_precision_recall': 0.7786934, 'average_loss': 0.4796637, 'label/mean': 0.375, 'loss': 0.47112098, 'precision': 0.73170733, 'prediction/mean': 0.3178967, 'recall': 0.6060606, 'global_step': 200}

Il atteint désormais une précision de 77,6 %, ce qui est légèrement supérieur à la seule formation aux fonctionnalités de base. Vous pouvez essayer d'utiliser plus de fonctionnalités et de transformations pour voir si vous pouvez faire mieux !

Vous pouvez maintenant utiliser le modèle de train pour faire des prédictions sur un passager à partir de l'ensemble d'évaluation. Les modèles TensorFlow sont optimisés pour faire des prédictions sur un lot ou une collection d'exemples à la fois. Plus tôt, le eval_input_fn a été défini à l' aide l'ensemble de l' évaluation.

pred_dicts = list(linear_est.predict(eval_input_fn))
probs = pd.Series([pred['probabilities'][1] for pred in pred_dicts])

probs.plot(kind='hist', bins=20, title='predicted probabilities')
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from /tmp/tmpoq0ukjec/model.ckpt-200
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
<AxesSubplot:title={'center':'predicted probabilities'}, ylabel='Frequency'>

png

Enfin, regardez la caractéristique de fonctionnement du récepteur (ROC) des résultats, ce qui nous donnera une meilleure idée du compromis entre le taux de vrais positifs et le taux de faux positifs.

from sklearn.metrics import roc_curve
from matplotlib import pyplot as plt

fpr, tpr, _ = roc_curve(y_eval, probs)
plt.plot(fpr, tpr)
plt.title('ROC curve')
plt.xlabel('false positive rate')
plt.ylabel('true positive rate')
plt.xlim(0,)
plt.ylim(0,)
(0.0, 1.05)

png