El preprocesado de datos constituye una fase crítica en cualquier proyecto de aprendizaje automático. Antes de que un modelo pueda aprender patrones útiles, los datos deben ser transformados a un formato adecuado, limpiados de inconsistencias y preparados para maximizar la eficacia del entrenamiento. TensorFlow proporciona un conjunto completo de herramientas que facilitan estas tareas, permitiendo construir pipelines de datos eficientes y optimizados.
API tf.data: la base del preprocesado en TensorFlow
La API tf.data
es el núcleo del ecosistema de preprocesado en TensorFlow, diseñada para construir pipelines de datos eficientes, flexibles y con alto rendimiento. Esta API permite cargar datos desde diferentes fuentes, transformarlos y entregarlos al modelo en lotes, todo dentro del grafo de computación de TensorFlow, lo que optimiza el rendimiento y evita cuellos de botella.
import tensorflow as tf
import numpy as np
## Crear un dataset simple desde un tensor
datos = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
dataset = tf.data.Dataset.from_tensor_slices(datos)
## Aplicar transformaciones
dataset = dataset.map(lambda x: x * 2) # Multiplicar cada elemento por 2
dataset = dataset.batch(3) # Agrupar en lotes de 3 elementos
## Iterar sobre el dataset
for lote in dataset:
print(lote.numpy())
La creación de un dataset puede realizarse desde diversas fuentes como tensores, archivos TFRecord, archivos de texto o generadores de Python. Una vez creado, podemos aplicar una serie de transformaciones encadenadas para preparar los datos según nuestras necesidades.
Carga de diferentes tipos de datos
Datos tabulares y numéricos
Los datos tabulares pueden cargarse desde diferentes formatos como CSV, Excel o bases de datos. TensorFlow facilita la carga directa de archivos CSV:
csv_dataset = tf.data.experimental.make_csv_dataset(
file_pattern="datos.csv",
batch_size=32,
column_names=["caracteristica1", "caracteristica2", "etiqueta"],
label_name="etiqueta",
num_epochs=1
)
for features_batch, labels_batch in csv_dataset:
print(f"Características: {features_batch}")
print(f"Etiquetas: {labels_batch}")
break # Solo mostramos el primer lote
Para conjuntos de datos más complejos o que requieren un preprocesado específico, podemos utilizar bibliotecas como pandas para la carga inicial y luego convertirlos a objetos tf.data.Dataset
:
import pandas as pd
## Cargar datos con pandas
df = pd.read_csv("datos.csv")
## Separar características y etiquetas
features = df.drop("etiqueta", axis=1).values
labels = df["etiqueta"].values
## Crear dataset de TensorFlow
dataset = tf.data.Dataset.from_tensor_slices((features, labels))
Imágenes
El preprocesado de imágenes es crucial en tareas de visión por computador. TensorFlow proporciona funciones específicas para cargar y transformar imágenes:
def cargar_imagen(ruta_archivo):
# Leer el archivo
img_raw = tf.io.read_file(ruta_archivo)
# Decodificar la imagen
img = tf.io.decode_image(img_raw, channels=3, expand_animations=False)
# Redimensionar
img = tf.image.resize(img, [224, 224])
# Normalizar valores a [0, 1]
img = tf.cast(img, tf.float32) / 255.0
return img
## Crear una lista de rutas de archivos
rutas_imagenes = tf.data.Dataset.list_files("imagenes/*.jpg")
## Aplicar la función de carga a cada ruta
dataset_imagenes = rutas_imagenes.map(cargar_imagen, num_parallel_calls=tf.data.AUTOTUNE)
La API tf.image
ofrece numerosas funciones para transformar imágenes, incluyendo operaciones de redimensionado, recorte, rotación, ajuste de brillo y contraste, y muchas más. Estas operaciones pueden integrarse perfectamente en el pipeline de datos.
Datos de texto
El procesamiento de texto requiere transformar palabras o caracteres en representaciones numéricas que los modelos puedan entender. TensorFlow proporciona herramientas específicas para esta tarea:
## Lista de frases de ejemplo
frases = ["Hola mundo", "Aprendizaje automático", "TensorFlow es genial"]
dataset_texto = tf.data.Dataset.from_tensor_slices(frases)
## Crear un tokenizador y ajustarlo a los datos
tokenizador = tf.keras.preprocessing.text.Tokenizer()
tokenizador.fit_on_texts(frases)
## Convertir texto a secuencias de índices
def tokenizar(texto):
secuencias = tokenizador.texts_to_sequences([texto.numpy().decode('utf-8')])
return tf.constant(secuencias[0])
## Aplicar la tokenización a cada elemento
dataset_texto = dataset_texto.map(
lambda texto: tf.py_function(func=tokenizar, inp=[texto], Tout=tf.int32)
)
Para manejar secuencias de diferentes longitudes, necesitamos aplicar padding para que todas tengan la misma dimensión:
def aplicar_padding(secuencia):
return tf.pad(
secuencia,
[[0, 50 - tf.shape(secuencia)[0]]],
"CONSTANT",
constant_values=0
)[:50] # Truncar si es más larga que 50
dataset_texto = dataset_texto.map(aplicar_padding)
Limpieza y transformación de datos
Manejo de valores faltantes
Los valores faltantes son un problema común en conjuntos de datos reales. Para manejarlos, podemos utilizar diversas técnicas como:
def manejar_valores_faltantes(features):
# Reemplazar NaN con un valor predeterminado
features = {k: tf.where(tf.math.is_nan(v), tf.zeros_like(v), v)
for k, v in features.items()}
# O imputar con la media (calculada previamente)
medias = {"caracteristica1": 3.5, "caracteristica2": 2.7}
features = {k: tf.where(tf.math.is_nan(v), tf.constant(medias[k], dtype=v.dtype), v)
for k, v in features.items()}
return features
dataset = dataset.map(lambda x, y: (manejar_valores_faltantes(x), y))
Normalización y estandarización
La normalización de datos es esencial para muchos algoritmos de aprendizaje automático, ya que ayuda a que el proceso de entrenamiento sea más estable y eficiente:
def normalizar_min_max(x):
# Normalización a [0, 1]
min_val = tf.reduce_min(x)
max_val = tf.reduce_max(x)
return (x - min_val) / (max_val - min_val)
def estandarizar(x):
# Estandarización (media 0, desviación estándar 1)
media = tf.reduce_mean(x)
desv_std = tf.math.reduce_std(x)
return (x - media) / desv_std
## Aplicar normalización a cada característica
dataset = dataset.map(
lambda x: {k: normalizar_min_max(v) for k, v in x.items()}
)
En la práctica, es recomendable calcular las estadísticas (mínimo, máximo, media, desviación estándar) sobre el conjunto de entrenamiento y aplicar las mismas transformaciones al conjunto de validación y prueba:
## Calcular estadísticas sobre el conjunto de entrenamiento
estadisticas = {}
for batch in dataset_entrenamiento:
for key, tensor in batch.items():
if key not in estadisticas:
estadisticas[key] = {"min": float('inf'), "max": float('-inf'),
"sum": 0, "count": 0, "sum_squared": 0}
estadisticas[key]["min"] = min(estadisticas[key]["min"], tf.reduce_min(tensor))
estadisticas[key]["max"] = max(estadisticas[key]["max"], tf.reduce_max(tensor))
estadisticas[key]["sum"] += tf.reduce_sum(tensor)
estadisticas[key]["count"] += tf.size(tensor)
estadisticas[key]["sum_squared"] += tf.reduce_sum(tf.square(tensor))
## Calcular media y desviación estándar
for key in estadisticas:
estadisticas[key]["mean"] = estadisticas[key]["sum"] / estadisticas[key]["count"]
varianza = (estadisticas[key]["sum_squared"] / estadisticas[key]["count"]) - tf.square(estadisticas[key]["mean"])
estadisticas[key]["std"] = tf.sqrt(varianza)
## Función de normalización usando las estadísticas calculadas
def normalizar_con_estadisticas(features):
return {k: (v - estadisticas[k]["mean"]) / estadisticas[k]["std"]
for k, v in features.items()}
## Aplicar a los conjuntos de datos
dataset_entrenamiento = dataset_entrenamiento.map(normalizar_con_estadisticas)
dataset_validacion = dataset_validacion.map(normalizar_con_estadisticas)
Codificación de variables categóricas
Las variables categóricas deben transformarse en representaciones numéricas. TensorFlow ofrece diversas opciones para esta codificación:
## One-hot encoding
def one_hot_encoding(valor, num_categorias):
return tf.one_hot(valor, depth=num_categorias)
## Ejemplo para una variable categórica con 5 posibles valores
dataset = dataset.map(
lambda x, y: ({**x, "categoria_one_hot": one_hot_encoding(x["categoria"], 5)}, y)
)
## Embedding para categorías con alta cardinalidad
embedding_layer = tf.keras.layers.Embedding(input_dim=1000, output_dim=16)
def aplicar_embedding(x):
categoria_embedding = embedding_layer(x["categoria"])
return {**x, "categoria_embedding": categoria_embedding}
dataset = dataset.map(aplicar_embedding)
Partición de datos
La división adecuada del conjunto de datos en entrenamiento, validación y prueba es fundamental para evaluar correctamente el rendimiento del modelo:
def particionar_dataset(dataset, proporciones):
"""
Particiona un dataset en múltiples subconjuntos según las proporciones dadas.
Args:
dataset: Dataset a particionar
proporciones: Lista de proporciones para cada partición (debe sumar 1)
Returns:
Lista de datasets particionados
"""
assert sum(proporciones) == 1.0, "Las proporciones deben sumar 1"
# Obtener el tamaño total del dataset
dataset = dataset.cache()
tamanio = 0
for _ in dataset:
tamanio += 1
# Crear índices aleatorios
indices = tf.range(tamanio)
indices = tf.random.shuffle(indices)
# Calcular los puntos de corte
puntos_corte = [0]
for i in range(len(proporciones) - 1):
puntos_cort
Lecciones de este módulo
Explora todas las lecciones disponibles en Preprocesados y preparación
Explora más sobre TensorFlow
Descubre más recursos de TensorFlow

Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, TensorFlow es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.