Ver en TensorFlow.org | Ejecutar en Google Colab | Ver fuente en GitHub | Descargar libreta |
Este tutorial demuestra cómo clasificar datos estructurados, como datos tabulares, utilizando una versión simplificada del conjunto de datos de PetFinder de una competencia de Kaggle almacenada en un archivo CSV.
Utilizará Keras para definir el modelo y las capas de preprocesamiento de Keras como un puente para mapear desde las columnas en un archivo CSV a las características utilizadas para entrenar el modelo. El objetivo es predecir si una mascota será adoptada.
Este tutorial contiene código completo para:
- Cargando un archivo CSV en un DataFrame usando pandas .
- Creación de una canalización de entrada para procesar por lotes y mezclar las filas mediante
tf.data
. (Visite tf.data: Build TensorFlow input pipelines para obtener más detalles). - Mapeo de columnas en el archivo CSV a funciones utilizadas para entrenar el modelo con las capas de preprocesamiento de Keras.
- Construir, entrenar y evaluar un modelo utilizando los métodos incorporados de Keras.
El miniconjunto de datos de PetFinder.my
Hay varios miles de filas en el archivo de conjunto de datos CSV de PetFinder.my mini, donde cada fila describe una mascota (un perro o un gato) y cada columna describe un atributo, como edad, raza, color, etc.
En el resumen del conjunto de datos a continuación, observe que hay principalmente columnas numéricas y categóricas. En este tutorial, solo tratará con esos dos tipos de funciones, eliminando Description
(una función de texto libre) y AdoptionSpeed
(una función de clasificación) durante el preprocesamiento de datos.
Columna | Descripción de la mascota | tipo de característica | Tipo de datos |
---|---|---|---|
Type | Tipo de animal ( Dog , Cat ) | Categórico | Cuerda |
Age | Envejecer | Numérico | Entero |
Breed1 | raza primaria | Categórico | Cuerda |
Color1 | Color 1 | Categórico | Cuerda |
Color2 | Color 2 | Categórico | Cuerda |
MaturitySize | Tamaño en la madurez | Categórico | Cuerda |
FurLength | Longitud de la piel | Categórico | Cuerda |
Vaccinated | La mascota ha sido vacunada. | Categórico | Cuerda |
Sterilized | La mascota ha sido esterilizada. | Categórico | Cuerda |
Health | Estado de salud | Categórico | Cuerda |
Fee | Tasa de adopción | Numérico | Entero |
Description | Redacción de perfil | Texto | Cuerda |
PhotoAmt | Total de fotos subidas | Numérico | Entero |
AdoptionSpeed | Velocidad categórica de adopción | Clasificación | Entero |
Importar TensorFlow y otras bibliotecas
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras import layers
tf.__version__
'2.8.0-rc1'
Cargue el conjunto de datos y léalo en un DataFrame de pandas
pandas es una biblioteca de Python con muchas utilidades útiles para cargar y trabajar con datos estructurados. Use tf.keras.utils.get_file
para descargar y extraer el archivo CSV con el mini conjunto de datos PetFinder.my y cárguelo en un DataFrame con pandas.read_csv
:
dataset_url = 'http://storage.googleapis.com/download.tensorflow.org/data/petfinder-mini.zip'
csv_file = 'datasets/petfinder-mini/petfinder-mini.csv'
tf.keras.utils.get_file('petfinder_mini.zip', dataset_url,
extract=True, cache_dir='.')
dataframe = pd.read_csv(csv_file)
Downloading data from http://storage.googleapis.com/download.tensorflow.org/data/petfinder-mini.zip 1671168/1668792 [==============================] - 0s 0us/step 1679360/1668792 [==============================] - 0s 0us/step
Inspeccione el conjunto de datos comprobando las primeras cinco filas del DataFrame:
dataframe.head()
Crear una variable objetivo
La tarea original en la competencia Predicción de adopción PetFinder.my de Kaggle era predecir la velocidad a la que se adoptará una mascota (por ejemplo, en la primera semana, el primer mes, los primeros tres meses, etc.).
En este tutorial, simplificarás la tarea transformándola en un problema de clasificación binaria, donde simplemente debes predecir si una mascota fue adoptada o no.
Después de modificar la columna AdoptionSpeed
, 0
indicará que la mascota no fue adoptada y 1
indicará que sí.
# In the original dataset, `'AdoptionSpeed'` of `4` indicates
# a pet was not adopted.
dataframe['target'] = np.where(dataframe['AdoptionSpeed']==4, 0, 1)
# Drop unused features.
dataframe = dataframe.drop(columns=['AdoptionSpeed', 'Description'])
Dividir el DataFrame en conjuntos de entrenamiento, validación y prueba
El conjunto de datos está en un solo marco de datos de pandas. Divídalo en conjuntos de entrenamiento, validación y prueba utilizando, por ejemplo, una proporción de 80:10:10, respectivamente:
train, val, test = np.split(dataframe.sample(frac=1), [int(0.8*len(dataframe)), int(0.9*len(dataframe))])
print(len(train), 'training examples')
print(len(val), 'validation examples')
print(len(test), 'test examples')
9229 training examples 1154 validation examples 1154 test examples
Cree una tubería de entrada usando tf.data
A continuación, cree una función de utilidad que convierta cada DataFrame de conjunto de entrenamiento, validación y prueba en un tf.data.Dataset
, luego mezcle y agrupe los datos.
def df_to_dataset(dataframe, shuffle=True, batch_size=32):
df = dataframe.copy()
labels = df.pop('target')
df = {key: value[:,tf.newaxis] for key, value in dataframe.items()}
ds = tf.data.Dataset.from_tensor_slices((dict(df), labels))
if shuffle:
ds = ds.shuffle(buffer_size=len(dataframe))
ds = ds.batch(batch_size)
ds = ds.prefetch(batch_size)
return ds
Ahora, use la función recién creada ( df_to_dataset
) para verificar el formato de los datos que devuelve la función auxiliar de canalización de entrada invocándola en los datos de entrenamiento, y use un tamaño de lote pequeño para mantener la salida legible:
batch_size = 5
train_ds = df_to_dataset(train, batch_size=batch_size)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:4: FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version. Convert to a numpy array before indexing instead. after removing the cwd from sys.path.
[(train_features, label_batch)] = train_ds.take(1)
print('Every feature:', list(train_features.keys()))
print('A batch of ages:', train_features['Age'])
print('A batch of targets:', label_batch )
Every feature: ['Type', 'Age', 'Breed1', 'Gender', 'Color1', 'Color2', 'MaturitySize', 'FurLength', 'Vaccinated', 'Sterilized', 'Health', 'Fee', 'PhotoAmt', 'target'] A batch of ages: tf.Tensor( [[84] [ 1] [ 5] [ 1] [12]], shape=(5, 1), dtype=int64) A batch of targets: tf.Tensor([1 1 0 1 0], shape=(5,), dtype=int64)
Como demuestra el resultado, el conjunto de entrenamiento devuelve un diccionario de nombres de columna (del DataFrame) que se asignan a valores de columna de filas.
Aplicar las capas de preprocesamiento de Keras
Las capas de preprocesamiento de Keras le permiten crear canalizaciones de procesamiento de entrada nativas de Keras, que se pueden usar como código de preprocesamiento independiente en flujos de trabajo que no son de Keras, combinados directamente con modelos de Keras y exportados como parte de un modelo guardado de Keras.
En este tutorial, utilizará las siguientes cuatro capas de preprocesamiento para demostrar cómo realizar el preprocesamiento, la codificación de datos estructurados y la ingeniería de características:
-
tf.keras.layers.Normalization
: realiza la normalización de características de entrada. -
tf.keras.layers.CategoryEncoding
: convierte características categóricas enteras en representaciones densas one-hot, multi-hot o tf-idf . -
tf.keras.layers.StringLookup
: convierte los valores categóricos de cadena en índices enteros. -
tf.keras.layers.IntegerLookup
: convierte valores categóricos enteros en índices enteros.
Puede obtener más información sobre las capas disponibles en la guía Trabajar con capas de preprocesamiento .
- Para las características numéricas del mini conjunto de datos PetFinder.my, utilizará una capa
tf.keras.layers.Normalization
para estandarizar la distribución de los datos. - Para las características categóricas , como los
Type
de mascotas (cadenas deDog
yCat
), las transformará en tensores codificados en caliente contf.keras.layers.CategoryEncoding
.
Columnas numéricas
Para cada característica numérica en el mini conjunto de datos PetFinder.my, utilizará una capa tf.keras.layers.Normalization
para estandarizar la distribución de los datos.
Defina una nueva función de utilidad que devuelva una capa que aplique la normalización por características a las características numéricas utilizando esa capa de preprocesamiento de Keras:
def get_normalization_layer(name, dataset):
# Create a Normalization layer for the feature.
normalizer = layers.Normalization(axis=None)
# Prepare a Dataset that only yields the feature.
feature_ds = dataset.map(lambda x, y: x[name])
# Learn the statistics of the data.
normalizer.adapt(feature_ds)
return normalizer
A continuación, pruebe la nueva función llamándola en el total de funciones de fotos de mascotas cargadas para normalizar 'PhotoAmt'
:
photo_count_col = train_features['PhotoAmt']
layer = get_normalization_layer('PhotoAmt', train_ds)
layer(photo_count_col)
<tf.Tensor: shape=(5, 1), dtype=float32, numpy= array([[-0.8272058 ], [-0.19125296], [ 1.3986291 ], [-0.19125296], [-0.50922936]], dtype=float32)>
Columnas categóricas
Type
de mascotas en el conjunto de datos se representan como cadenas ( Dog
y Cat
) que deben codificarse en caliente antes de ingresar al modelo. La función de Age
Defina otra nueva función de utilidad que devuelva una capa que asigne valores de un vocabulario a índices enteros y codifique en caliente las características mediante el tf.keras.layers.StringLookup
, tf.keras.layers.IntegerLookup
y tf.keras.CategoryEncoding
capas:
def get_category_encoding_layer(name, dataset, dtype, max_tokens=None):
# Create a layer that turns strings into integer indices.
if dtype == 'string':
index = layers.StringLookup(max_tokens=max_tokens)
# Otherwise, create a layer that turns integer values into integer indices.
else:
index = layers.IntegerLookup(max_tokens=max_tokens)
# Prepare a `tf.data.Dataset` that only yields the feature.
feature_ds = dataset.map(lambda x, y: x[name])
# Learn the set of possible values and assign them a fixed integer index.
index.adapt(feature_ds)
# Encode the integer indices.
encoder = layers.CategoryEncoding(num_tokens=index.vocabulary_size())
# Apply multi-hot encoding to the indices. The lambda function captures the
# layer, so you can use them, or include them in the Keras Functional model later.
return lambda feature: encoder(index(feature))
Pruebe la función get_category_encoding_layer
llamándola a las funciones de 'Type'
de mascotas para convertirlas en tensores codificados multi-calientes:
test_type_col = train_features['Type']
test_type_layer = get_category_encoding_layer(name='Type',
dataset=train_ds,
dtype='string')
test_type_layer(test_type_col)
<tf.Tensor: shape=(5, 3), dtype=float32, numpy= array([[0., 1., 0.], [0., 1., 0.], [0., 1., 0.], [0., 1., 0.], [0., 1., 0.]], dtype=float32)>
Repita el proceso en las características 'Age'
de la mascota:
test_age_col = train_features['Age']
test_age_layer = get_category_encoding_layer(name='Age',
dataset=train_ds,
dtype='int64',
max_tokens=5)
test_age_layer(test_age_col)
<tf.Tensor: shape=(5, 5), dtype=float32, numpy= array([[1., 0., 0., 0., 0.], [0., 0., 0., 1., 0.], [1., 0., 0., 0., 0.], [0., 0., 0., 1., 0.], [1., 0., 0., 0., 0.]], dtype=float32)>
Preprocesar las funciones seleccionadas para entrenar el modelo
Ha aprendido a utilizar varios tipos de capas de preprocesamiento de Keras. A continuación, usted:
- Aplique las funciones de utilidad de preprocesamiento definidas anteriormente en 13 características numéricas y categóricas del mini conjunto de datos PetFinder.my.
- Agregue todas las entradas de funciones a una lista.
Como se mencionó al principio, para entrenar el modelo, utilizará el mini conjunto de datos de PetFinder.my numérico ( 'PhotoAmt'
, 'Fee'
) y categórico ( 'Age'
, 'Type'
, 'Color1'
, 'Color2'
, 'Gender'
, 'MaturitySize'
'FurLength'
, 'Longitud del pelaje' , 'Vaccinated'
, 'Sterilized'
, 'Health'
, 'Breed1'
).
Anteriormente, usó un tamaño de lote pequeño para demostrar la canalización de entrada. Ahora vamos a crear una nueva tubería de entrada con un tamaño de lote más grande de 256:
batch_size = 256
train_ds = df_to_dataset(train, batch_size=batch_size)
val_ds = df_to_dataset(val, shuffle=False, batch_size=batch_size)
test_ds = df_to_dataset(test, shuffle=False, batch_size=batch_size)
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/ipykernel_launcher.py:4: FutureWarning: Support for multi-dimensional indexing (e.g. `obj[:, None]`) is deprecated and will be removed in a future version. Convert to a numpy array before indexing instead. after removing the cwd from sys.path.
Normalice las características numéricas (la cantidad de fotos de mascotas y la tarifa de adopción) y agréguelas a una lista de entradas llamada encoded_features
:
all_inputs = []
encoded_features = []
# Numerical features.
for header in ['PhotoAmt', 'Fee']:
numeric_col = tf.keras.Input(shape=(1,), name=header)
normalization_layer = get_normalization_layer(header, train_ds)
encoded_numeric_col = normalization_layer(numeric_col)
all_inputs.append(numeric_col)
encoded_features.append(encoded_numeric_col)
Convierta los valores categóricos enteros del conjunto de datos (la edad de la mascota) en índices enteros, realice una codificación múltiple y agregue las entradas de características resultantes a encoded_features
:
age_col = tf.keras.Input(shape=(1,), name='Age', dtype='int64')
encoding_layer = get_category_encoding_layer(name='Age',
dataset=train_ds,
dtype='int64',
max_tokens=5)
encoded_age_col = encoding_layer(age_col)
all_inputs.append(age_col)
encoded_features.append(encoded_age_col)
Repita el mismo paso para los valores categóricos de cadena:
categorical_cols = ['Type', 'Color1', 'Color2', 'Gender', 'MaturitySize',
'FurLength', 'Vaccinated', 'Sterilized', 'Health', 'Breed1']
for header in categorical_cols:
categorical_col = tf.keras.Input(shape=(1,), name=header, dtype='string')
encoding_layer = get_category_encoding_layer(name=header,
dataset=train_ds,
dtype='string',
max_tokens=5)
encoded_categorical_col = encoding_layer(categorical_col)
all_inputs.append(categorical_col)
encoded_features.append(encoded_categorical_col)
Crear, compilar y entrenar el modelo.
El siguiente paso es crear un modelo utilizando la API funcional de Keras . Para la primera capa de su modelo, fusione la lista de entradas de características ( encoded_features
) en un vector a través de la concatenación con tf.keras.layers.concatenate
.
all_features = tf.keras.layers.concatenate(encoded_features)
x = tf.keras.layers.Dense(32, activation="relu")(all_features)
x = tf.keras.layers.Dropout(0.5)(x)
output = tf.keras.layers.Dense(1)(x)
model = tf.keras.Model(all_inputs, output)
Configure el modelo con Keras Model.compile
:
model.compile(optimizer='adam',
loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
metrics=["accuracy"])
Visualicemos el gráfico de conectividad:
# Use `rankdir='LR'` to make the graph horizontal.
tf.keras.utils.plot_model(model, show_shapes=True, rankdir="LR")
A continuación, entrene y pruebe el modelo:
model.fit(train_ds, epochs=10, validation_data=val_ds)
Epoch 1/10 /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/keras/engine/functional.py:559: UserWarning: Input dict contained keys ['target'] which did not match any model input. They will be ignored by the model. inputs = self._flatten_to_reference_inputs(inputs) 37/37 [==============================] - 2s 19ms/step - loss: 0.6524 - accuracy: 0.5034 - val_loss: 0.5887 - val_accuracy: 0.6941 Epoch 2/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5906 - accuracy: 0.6648 - val_loss: 0.5627 - val_accuracy: 0.7218 Epoch 3/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5697 - accuracy: 0.6924 - val_loss: 0.5463 - val_accuracy: 0.7504 Epoch 4/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5558 - accuracy: 0.6978 - val_loss: 0.5346 - val_accuracy: 0.7504 Epoch 5/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5502 - accuracy: 0.7105 - val_loss: 0.5272 - val_accuracy: 0.7487 Epoch 6/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5415 - accuracy: 0.7123 - val_loss: 0.5210 - val_accuracy: 0.7608 Epoch 7/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5354 - accuracy: 0.7171 - val_loss: 0.5152 - val_accuracy: 0.7435 Epoch 8/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5301 - accuracy: 0.7214 - val_loss: 0.5113 - val_accuracy: 0.7513 Epoch 9/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5286 - accuracy: 0.7189 - val_loss: 0.5087 - val_accuracy: 0.7574 Epoch 10/10 37/37 [==============================] - 0s 8ms/step - loss: 0.5252 - accuracy: 0.7260 - val_loss: 0.5058 - val_accuracy: 0.7539 <keras.callbacks.History at 0x7f5f9fa91c50>
loss, accuracy = model.evaluate(test_ds)
print("Accuracy", accuracy)
5/5 [==============================] - 0s 6ms/step - loss: 0.5012 - accuracy: 0.7626 Accuracy 0.762565016746521
Realizar inferencia
El modelo que ha desarrollado ahora puede clasificar una fila de un archivo CSV directamente después de haber incluido las capas de preprocesamiento dentro del propio modelo.
Ahora puede guardar y volver a cargar el modelo de Keras con Model.save
y Model.load_model
antes de realizar la inferencia en nuevos datos:
model.save('my_pet_classifier')
reloaded_model = tf.keras.models.load_model('my_pet_classifier')
2022-01-26 06:20:08.013613: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them. WARNING:absl:Function `_wrapped_model` contains input name(s) PhotoAmt, Fee, Age, Type, Color1, Color2, Gender, MaturitySize, FurLength, Vaccinated, Sterilized, Health, Breed1 with unsupported characters which will be renamed to photoamt, fee, age, type, color1, color2, gender, maturitysize, furlength, vaccinated, sterilized, health, breed1 in the SavedModel. INFO:tensorflow:Assets written to: my_pet_classifier/assets INFO:tensorflow:Assets written to: my_pet_classifier/assets
Para obtener una predicción para una nueva muestra, simplemente puede llamar al método Keras Model.predict
. Solo hay dos cosas que debes hacer:
- Envuelva los escalares en una lista para tener una dimensión de lote (los
Model
solo procesan lotes de datos, no muestras individuales). - Llame a
tf.convert_to_tensor
en cada función.
sample = {
'Type': 'Cat',
'Age': 3,
'Breed1': 'Tabby',
'Gender': 'Male',
'Color1': 'Black',
'Color2': 'White',
'MaturitySize': 'Small',
'FurLength': 'Short',
'Vaccinated': 'No',
'Sterilized': 'No',
'Health': 'Healthy',
'Fee': 100,
'PhotoAmt': 2,
}
input_dict = {name: tf.convert_to_tensor([value]) for name, value in sample.items()}
predictions = reloaded_model.predict(input_dict)
prob = tf.nn.sigmoid(predictions[0])
print(
"This particular pet had a %.1f percent probability "
"of getting adopted." % (100 * prob)
)
This particular pet had a 77.7 percent probability of getting adopted.
Próximos pasos
Para obtener más información sobre la clasificación de datos estructurados, intente trabajar con otros conjuntos de datos. Para mejorar la precisión durante el entrenamiento y la prueba de sus modelos, piense detenidamente qué características incluir en su modelo y cómo deben representarse.
A continuación se presentan algunas sugerencias para conjuntos de datos:
- Conjuntos de datos de TensorFlow: MovieLens : un conjunto de clasificaciones de películas de un servicio de recomendación de películas.
- Conjuntos de datos de TensorFlow: calidad del vino : dos conjuntos de datos relacionados con las variantes rojas y blancas del vino portugués "Vinho Verde". También puede encontrar el conjunto de datos de calidad del vino tinto en Kaggle .
- Kaggle: conjunto de datos arXiv : un corpus de 1,7 millones de artículos académicos de arXiv, que abarcan física, informática, matemáticas, estadística, ingeniería eléctrica, biología cuantitativa y economía.