Construya un modelo lineal con Estimadores

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar libreta

Descripción general

Este tutorial completo entrena un modelo de regresión logística mediante la API tf.estimator . El modelo se utiliza a menudo como base para otros algoritmos más complejos.

Configuración

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

Cargue el conjunto de datos titánico

Utilizará el conjunto de datos del Titanic con el objetivo (bastante morboso) de predecir la supervivencia de los pasajeros, dadas características como el sexo, la edad, la clase, 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')

Explora los datos

El conjunto de datos contiene las siguientes características

dftrain.head()
dftrain.describe()

Hay 627 y 264 ejemplos en los conjuntos de entrenamiento y evaluación, respectivamente.

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

La mayoría de los pasajeros tienen entre 20 y 30 años.

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

png

Hay aproximadamente el doble de pasajeros masculinos que de mujeres a bordo.

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

png

La mayoría de los pasajeros estaban en la "tercera" clase.

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

png

Las hembras tienen muchas más posibilidades de sobrevivir que los machos. Esta es claramente una característica predictiva del modelo.

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

png

Ingeniería de funciones para el modelo

Los estimadores usan un sistema llamado columnas de características para describir cómo el modelo debe interpretar cada una de las características de entrada sin procesar. Un estimador espera un vector de entradas numéricas, y las columnas de funciones describen cómo el modelo debe convertir cada función.

Seleccionar y crear el conjunto correcto de columnas de características es clave para aprender un modelo efectivo. Una columna de funciones puede ser una de las entradas sin procesar en el dict de funciones original (una columna de funciones base ) o cualquier columna nueva creada mediante transformaciones definidas en una o varias columnas base (columnas de funciones derivadas ).

El estimador lineal utiliza características tanto numéricas como categóricas. Las columnas de características funcionan con todos los estimadores de TensorFlow y su propósito es definir las características utilizadas para el modelado. Además, brindan algunas capacidades de ingeniería de características, como codificación en caliente, normalización y segmentación.

Columnas de características 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))

La input_function especifica cómo se convierten los datos en un tf.data.Dataset que alimenta la canalización de entrada en forma de transmisión. tf.data.Dataset puede admitir múltiples fuentes, como un marco de datos, un archivo con formato csv y más.

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)

Puede inspeccionar el conjunto de datos:

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'Third' b'Third' b'Third' b'First' b'Second' b'First'
 b'First' b'Third']

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

También puede inspeccionar el resultado de una columna de características específica utilizando la capa tf.keras.layers.DenseFeatures :

age_column = feature_columns[7]
tf.keras.layers.DenseFeatures([age_column])(feature_batch).numpy()
array([[35.],
       [14.],
       [28.],
       [19.],
       [28.],
       [35.],
       [60.],
       [63.],
       [45.],
       [21.]], dtype=float32)

DenseFeatures solo acepta tensores densos, para inspeccionar una columna categórica, primero debe transformarla en una columna indicadora:

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

Después de agregar todas las funciones base al modelo, entrenemos el modelo. Entrenar un modelo es solo un comando único usando la API tf.estimator :

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.7537879, 'accuracy_baseline': 0.625, 'auc': 0.8060607, 'auc_precision_recall': 0.7480768, 'average_loss': 0.5639972, 'label/mean': 0.375, 'loss': 0.5542658, 'precision': 0.7741935, 'prediction/mean': 0.25232768, 'recall': 0.4848485, 'global_step': 200}

Columnas de funciones derivadas

Ahora alcanzaste una precisión del 75%. El uso de cada columna de características base por separado puede no ser suficiente para explicar los datos. Por ejemplo, la correlación entre la edad y la etiqueta puede ser diferente para diferentes géneros. Por lo tanto, si solo aprende un peso de modelo único para gender="Male" y gender="Female" , no capturará todas las combinaciones de edad y género (por ejemplo, distinguir entre gender="Male" AND age="30" AND gender="Male" Y age="40" ).

Para conocer las diferencias entre las diferentes combinaciones de características, puede agregar columnas de características cruzadas al modelo (también puede clasificar la columna de edad antes de la columna cruzada):

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

Después de agregar la función de combinación al modelo, entrenemos el modelo nuevamente:

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.7462121, 'accuracy_baseline': 0.625, 'auc': 0.845577, 'auc_precision_recall': 0.7873878, 'average_loss': 0.47313985, 'label/mean': 0.375, 'loss': 0.46722567, 'precision': 0.6509434, 'prediction/mean': 0.41550797, 'recall': 0.6969697, 'global_step': 200}

Ahora logra una precisión del 77,6 %, que es ligeramente mejor que solo entrenado en funciones básicas. ¡Puede intentar usar más funciones y transformaciones para ver si puede hacerlo mejor!

Ahora puede usar el modelo de tren para hacer predicciones sobre un pasajero del conjunto de evaluación. Los modelos de TensorFlow están optimizados para hacer predicciones en un lote o colección de ejemplos a la vez. Anteriormente, eval_input_fn se definió utilizando el conjunto de evaluación completo.

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/tmpe5vngw46/model.ckpt-200
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
<AxesSubplot:title={'center':'predicted probabilities'}, ylabel='Frequency'>

png

Finalmente, observe la característica operativa del receptor (ROC) de los resultados, que nos dará una mejor idea de la compensación entre la tasa de verdaderos positivos y la tasa de falsos positivos.

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