Veja no TensorFlow.org | Executar no Google Colab | Ver fonte no GitHub | Baixar caderno |
Visão geral
Este passo a passo completo treina um modelo de regressão logística usando a API tf.estimator
. O modelo é frequentemente usado como base para outros algoritmos mais complexos.
Configurar
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
Carregar o conjunto de dados do Titanic
Você usará o conjunto de dados do Titanic com o objetivo (bastante mórbido) de prever a sobrevivência dos passageiros, dadas características como sexo, idade, 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')
Explorar os dados
O conjunto de dados contém os seguintes recursos
dftrain.head()
dftrain.describe()
Existem 627 e 264 exemplos nos conjuntos de treinamento e avaliação, respectivamente.
dftrain.shape[0], dfeval.shape[0]
(627, 264)
A maioria dos passageiros tem entre 20 e 30 anos.
dftrain.age.hist(bins=20)
<AxesSubplot:>
Há aproximadamente o dobro de passageiros do sexo masculino do que do sexo feminino a bordo.
dftrain.sex.value_counts().plot(kind='barh')
<AxesSubplot:>
A maioria dos passageiros estava na "terceira" classe.
dftrain['class'].value_counts().plot(kind='barh')
<AxesSubplot:>
As fêmeas têm uma chance muito maior de sobreviver em relação aos machos. Este é claramente um recurso preditivo para o modelo.
pd.concat([dftrain, y_train], axis=1).groupby('sex').survived.mean().plot(kind='barh').set_xlabel('% survive')
Text(0.5, 0, '% survive')
Engenharia de recursos para o modelo
Os estimadores usam um sistema chamado colunas de recursos para descrever como o modelo deve interpretar cada um dos recursos brutos de entrada. Um estimador espera um vetor de entradas numéricas e as colunas de recursos descrevem como o modelo deve converter cada recurso.
Selecionar e criar o conjunto certo de colunas de recursos é fundamental para aprender um modelo eficaz. Uma coluna de recurso pode ser uma das entradas brutas no dict
de recursos original (uma coluna de recurso base ) ou qualquer nova coluna criada usando transformações definidas em uma ou várias colunas de base (colunas de recurso derivadas ).
O estimador linear usa recursos numéricos e categóricos. As colunas de recursos funcionam com todos os estimadores do TensorFlow e sua finalidade é definir os recursos usados para modelagem. Além disso, eles fornecem alguns recursos de engenharia de recursos, como codificação one-hot, normalização e bucketização.
Colunas de recursos básicos
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))
A input_function
especifica como os dados são convertidos em um tf.data.Dataset
que alimenta o pipeline de entrada em um modo de streaming. tf.data.Dataset
pode receber várias fontes, como um dataframe, um arquivo formatado em csv e muito mais.
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)
Você pode inspecionar o conjunto de dados:
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]
Você também pode inspecionar o resultado de uma coluna de feição específica usando a camada 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
aceita apenas tensores densos, para inspecionar uma coluna categórica você precisa primeiro transformá-la em uma coluna 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)
Depois de adicionar todos os recursos básicos ao modelo, vamos treinar o modelo. Treinar um modelo é apenas um único comando usando a 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}
Colunas de recursos derivados
Agora você atingiu uma precisão de 75%. Usar cada coluna de recurso base separadamente pode não ser suficiente para explicar os dados. Por exemplo, a correlação entre a idade e o rótulo pode ser diferente para diferentes sexos. Portanto, se você aprender apenas um único peso de modelo para gender="Male"
e gender="Female"
, não capturará todas as combinações de idade e gênero (por exemplo, distinguir entre gender="Male"
AND age="30"
AND gender="Male"
E age="40"
).
Para aprender as diferenças entre diferentes combinações de recursos, você pode adicionar colunas de recursos cruzados ao modelo (você também pode agrupar a coluna de idade antes da coluna cruzada):
age_x_gender = tf.feature_column.crossed_column(['age', 'sex'], hash_bucket_size=100)
Depois de adicionar o recurso de combinação ao modelo, vamos treinar o modelo novamente:
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}
Ele agora atinge uma precisão de 77,6%, que é um pouco melhor do que apenas treinado em recursos básicos. Você pode tentar usar mais recursos e transformações para ver se pode fazer melhor!
Agora você pode usar o modelo de trem para fazer previsões sobre um passageiro do conjunto de avaliação. Os modelos do TensorFlow são otimizados para fazer previsões em um lote ou coleção de exemplos de uma só vez. Anteriormente, o eval_input_fn
era definido usando todo o conjunto de avaliação.
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'>
Finalmente, observe a característica operacional do receptor (ROC) dos resultados, o que nos dará uma ideia melhor da compensação entre a taxa de verdadeiros positivos e a taxa 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)