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
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
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
Completa TensorFlow y certifícate
Únete a nuestra plataforma y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.
Asistente IA
Resuelve dudas al instante
Ejercicios
Practica con proyectos reales
Certificados
Valida tus conocimientos
Más de 25.000 desarrolladores ya se han certificado con CertiDevs