Datasets: descargar, dividir y guardar

Buenos datos, bien divididos y bien guardados: la mitad del éxito de un modelo.

Duración: ~45 minutosHerramientas: PythonAntes, conviene haber hecho: «Tu puesto de trabajo de IA, desde cero»

Qué vas a aprender

  • Cargar, recibir en streaming y cachear datasets con la librería datasets de Hugging Face
  • Convertir entre CSV, JSON, Parquet y Arrow, y explicar las ventajas de cada formato
  • Crear divisiones reproducibles de entrenamiento, validación y test con semillas fijas
  • Gestionar archivos grandes de modelos y datos con .gitignore, Git LFS o DVC

Por qué importa

Todo proyecto de IA empieza por los datos. Tienes que encontrar datasets, descargarlos, convertirlos entre formatos, dividirlos para entrenar y evaluar, y versionarlos para que los experimentos sean reproducibles. Hacerlo a mano cada vez es lento y propenso a errores. Necesitas un flujo de trabajo repetible.

La idea clave

graph TD
    A["Hugging Face Hub"] --> B["librería datasets"]
    B --> C["Cargar / Streaming"]
    C --> D["Caché local<br/>~/.cache/huggingface/"]
    B --> E["Conversión de formato<br/>CSV, JSON, Parquet, Arrow"]
    E --> F["Divisiones<br/>train / val / test"]
    F --> G["Tu pipeline de entrenamiento"]

La librería datasets de Hugging Face es la forma estándar de cargar datos en IA. Se encarga de la descarga, la caché, la conversión de formatos y el streaming sin que tengas que hacer nada.

Paso a paso

Paso 1: instala la librería datasets

pip install datasets huggingface_hub

Paso 2: carga un dataset

from datasets import load_dataset

dataset = load_dataset("stanfordnlp/imdb")
print(dataset)
print(dataset["train"][0])

Esto descarga el dataset de reseñas de películas de IMDB. Tras la primera descarga, se carga desde la caché en ~/.cache/huggingface/datasets/.

¿Datos en español? En el Hugging Face Hub puedes filtrar por idioma (Languages › Spanish). Para tus proyectos de portfolio, un dataset en español es un buen elemento diferenciador.

Paso 3: datasets enormes en streaming

Algunos datasets no caben en tu disco. El streaming los carga fila a fila sin descargarlos enteros.

dataset = load_dataset("wikimedia/wikipedia", "20231101.en", split="train", streaming=True)

for i, example in enumerate(dataset):
    print(example["title"])
    if i >= 4:
        break

Con streaming obtienes un IterableDataset: procesas las filas a medida que llegan y el uso de memoria se mantiene constante, sea cual sea el tamaño del dataset.

Paso 4: formatos de datos

La librería datasets usa Apache Arrow por debajo. Puedes convertir a otros formatos según lo que necesite tu pipeline.

dataset = load_dataset("stanfordnlp/imdb", split="train")

dataset.to_csv("imdb_train.csv")
dataset.to_json("imdb_train.json")
dataset.to_parquet("imdb_train.parquet")

Comparativa de formatos:

Formato Tamaño Velocidad de lectura Ideal para
CSV Grande Lenta Legible por humanos, hojas de cálculo
JSON Grande Lenta APIs, datos anidados
Parquet Pequeño Rápida Analítica, consultas por columnas
Arrow Pequeño La más rápida Procesamiento en memoria (lo que usa datasets internamente)

En IA, Parquet es el mejor formato de almacenamiento y Arrow es con lo que trabajas en memoria. CSV y JSON son para intercambiar datos.

¿Por qué Parquet es tan eficiente? Porque guarda los datos por columnas: todos los valores de una columna van juntos, se comprimen muy bien (se parecen entre sí) y, si solo necesitas dos columnas de cincuenta, solo lees esas dos.

Compruébalo tú mismo aquí, en el navegador. Este ejemplo genera 2.000 reseñas inventadas, las guarda en CSV, JSON y JSONL (una línea JSON por ejemplo, muy usado para entrenar LLMs) y compara lo que ocupan, sin comprimir y comprimidas. Cambia n o añade columnas y vuelve a ejecutarlo:

import csv, gzip, io, json, random

random.seed(42)
palabras = ["genial", "aburrida", "emocionante", "lenta", "divertida", "previsible", "brillante"]
n = 2000
filas = [{"id": i,
          "texto": " ".join(random.choices(palabras, k=12)),
          "etiqueta": random.choice(["positiva", "negativa"])} for i in range(n)]

def a_csv(filas):
    buf = io.StringIO()
    escritor = csv.DictWriter(buf, fieldnames=filas[0].keys())
    escritor.writeheader()
    escritor.writerows(filas)
    return buf.getvalue()

formatos = {
    "CSV": a_csv(filas),
    "JSON": json.dumps(filas, ensure_ascii=False, indent=2),
    "JSONL": "\n".join(json.dumps(f, ensure_ascii=False) for f in filas),
}

print(f"{'Formato':<8}{'Tamaño':>12}{'Comprimido':>14}")
for nombre, texto in formatos.items():
    datos = texto.encode()
    print(f"{nombre:<8}{len(datos) / 1024:>10.1f} KB{len(gzip.compress(datos)) / 1024:>12.1f} KB")

Fíjate en cuánto ocupa JSON con sangría (repite los nombres de las columnas en cada fila) y en cuánto se reduce todo al comprimir: los datos repetitivos se comprimen muy bien. Parquet aprovecha justo eso, columna a columna.

Paso 5: divisiones de los datos

Todo proyecto de ML necesita tres divisiones:

  • Entrenamiento (train): de aquí aprende el modelo (normalmente el 80 %)
  • Validación (validation): con ella compruebas el progreso durante el entrenamiento y ajustas hiperparámetros (normalmente el 10 %)
  • Test: la evaluación final, cuando ya has terminado de entrenar (normalmente el 10 %)

Algunos datasets vienen ya divididos. Cuando no, divídelos tú:

dataset = load_dataset("stanfordnlp/imdb", split="train")

split = dataset.train_test_split(test_size=0.2, seed=42)
train_val = split["train"].train_test_split(test_size=0.125, seed=42)

train_ds = train_val["train"]
val_ds = train_val["test"]
test_ds = split["test"]

print(f"Train: {len(train_ds)}, Val: {len(val_ds)}, Test: {len(test_ds)}")

Fija siempre una semilla: la misma semilla produce la misma división cada vez. Compruébalo aquí con Python puro (sin descargar nada): ejecuta el bloque varias veces y verás que con la misma semilla salen siempre los mismos ejemplos en test. Cambia semilla y verás que cambian:

import random

def dividir(ejemplos, prop_val=0.1, prop_test=0.1, semilla=42):
    ejemplos = list(ejemplos)
    random.Random(semilla).shuffle(ejemplos)   # barajar SIEMPRE antes de dividir
    n_test = int(len(ejemplos) * prop_test)
    n_val = int(len(ejemplos) * prop_val)
    return ejemplos[n_test + n_val:], ejemplos[n_test:n_test + n_val], ejemplos[:n_test]

datos = list(range(1000))   # imagina que cada número es un ejemplo
semilla = 42
train, val, test = dividir(datos, semilla=semilla)

print(f"Train: {len(train)}, Val: {len(val)}, Test: {len(test)}")
print("Primeros ejemplos de test:", test[:8])
print("¿Algún ejemplo repetido entre train y test?", bool(set(train) & set(test)))

La regla de oro del conjunto de test: no lo mires hasta el final. Si ajustas tu modelo según los resultados en test, deja de ser una evaluación honesta y tus métricas serán optimistas.

Paso 6: descarga y caché de modelos

Los modelos son archivos grandes. La librería huggingface_hub gestiona su descarga y caché.

from huggingface_hub import hf_hub_download, snapshot_download

model_path = hf_hub_download(
    repo_id="sentence-transformers/all-MiniLM-L6-v2",
    filename="config.json"
)
print(f"En caché en: {model_path}")

model_dir = snapshot_download("sentence-transformers/all-MiniLM-L6-v2")
print(f"Modelo completo en: {model_dir}")

Los modelos se guardan en ~/.cache/huggingface/hub/. Una vez descargados, en las siguientes ejecuciones se cargan al instante.

Paso 7: archivos grandes

Los pesos de modelos y los datasets grandes no deben ir a git. Tres opciones:

Opción A: .gitignore (la más sencilla)

*.bin
*.safetensors
*.pt
*.onnx
data/*.parquet
data/*.csv
models/

Opción B: Git LFS (archivos grandes dentro de git)

git lfs install
git lfs track "*.bin"
git lfs track "*.safetensors"
git add .gitattributes

Git LFS guarda punteros en tu repositorio y los archivos reales en un servidor aparte. GitHub incluye una cuota gratuita limitada.

Opción C: DVC (control de versiones de datos)

pip install dvc
dvc init
dvc add data/training_set.parquet
git add data/training_set.parquet.dvc data/.gitignore
git commit -m "Versiona los datos de entrenamiento con DVC"

DVC crea pequeños archivos .dvc que apuntan a tus datos. Los datos en sí viven en S3, GCS u otro almacenamiento remoto.

Enfoque Complejidad Ideal para
.gitignore Baja Proyectos personales, datos descargados que puedes volver a obtener
Git LFS Media Equipos que comparten pesos de modelos mediante git
DVC Alta Experimentos reproducibles, datasets grandes, equipos

Para este curso basta con .gitignore. Usa DVC cuando necesites reproducir experimentos exactos en distintas máquinas.

Paso 8: dónde guardar los datos

El almacenamiento local funciona para datasets de menos de ~10 GB. La caché de Hugging Face lo gestiona sola.

El almacenamiento en la nube es para todo lo más grande o compartido entre máquinas:

import os

local_path = os.path.expanduser("~/.cache/huggingface/datasets/")

# s3_path = "s3://mi-bucket/datasets/"
# gcs_path = "gs://mi-bucket/datasets/"

DVC se integra directamente con S3 y GCS:

dvc remote add -d myremote s3://mi-bucket/dvc-store
dvc push

Para este curso, el almacenamiento local es suficiente. La nube cobra importancia cuando hagas fine-tuning en máquinas remotas con GPU.

Extra: datos personales y RGPD

Si trabajas con datos de personas (nombres, emails, conversaciones, historiales…) en Europa, aplica el RGPD: necesitas una base legal para tratarlos, debes usar solo los datos necesarios (minimización) y protegerlos. Antes de entrenar o evaluar con datos reales, anonimízalos o seudonimízalos siempre que puedas. Lo verás en profundidad en el módulo 32 (Ética, equidad y regulación) y en el extra sobre el AI Act.

Datasets que usarás en el curso

Dataset Lecciones Tamaño Qué enseña
IMDB Tokenización, clasificación 84 MB Lo básico de clasificar texto
WikiText Modelado de lenguaje 181 MB Predicción del siguiente token
SQuAD Sistemas de pregunta-respuesta 35 MB Responder preguntas extrayendo fragmentos
Common Crawl (subconjunto) Embeddings Variable Procesar texto a gran escala
MNIST Visión básica 21 MB Fundamentos de clasificación de imágenes
COCO (subconjunto) Multimodal Variable Pares imagen-texto

No necesitas descargarlos todos ahora. Cada lección indica lo que necesita.

En la práctica

Descarga utilidades_datos.py desde «Archivos de la lección» y ejecútalo (con tu entorno activado y uv pip install datasets hecho) para comprobar que todo funciona:

python utilidades_datos.py

Descarga un dataset pequeño de reseñas, lo divide, lo guarda en varios formatos e imprime un resumen. Después puedes importar sus funciones en tus proyectos: from utilidades_datos import cargar, dividir.

Tu caja de herramientas

Te llevas utilidades_datos.py, una utilidad reutilizable para cargar, dividir y guardar datos.

Y un prompt para que un asistente de IA te ayude a encontrar el dataset adecuado para cada tarea. Cópialo, pégalo y describe tu proyecto:

Eres un experto en datasets para IA. Ayúdame a elegir y cargar los datos para mi proyecto.

1. Antes de recomendar nada, pregúntame lo que te falte saber: la tarea (clasificación, generación,
   pregunta-respuesta, visión…), el idioma, cuántos ejemplos necesito, la licencia que puedo usar
   (¿uso comercial?) y mis recursos (RAM, disco, GPU).
2. Recomiéndame de 2 a 4 datasets en una tabla con: nombre exacto en Hugging Face, tamaño,
   licencia, idioma y por qué encaja.
3. Dame el código para cargarlo con la librería `datasets`, incluida la división
   train/validación/test con semilla fija si no viene dividido.
4. Ten en cuenta los casos especiales:
   - Si es muy grande, usa streaming=True.
   - Si necesito datos en español y hay pocos, propón alternativas (multilingües, traducción, datos sintéticos).
   - Si hay datos personales, avísame de las implicaciones del RGPD.
   - Si las clases están desequilibradas, dime cómo detectarlo y tratarlo.

Mi proyecto:

Retos para tu ordenador

  1. Carga el dataset glue con la configuración mrpc e inspecciona los 5 primeros ejemplos
  2. Recibe en streaming el dataset c4 y cuenta cuántos ejemplos procesas en 10 segundos
  3. Convierte un dataset a Parquet y compara el tamaño del archivo con el CSV
  4. Crea una división 70/15/15 con semilla fija y comprueba los tamaños

Glosario de la lección

Término Como se suele decir Qué es exactamente
División (split) «Los datos de entrenamiento» Un subconjunto con nombre (train/val/test) que se usa en una fase distinta del ciclo de vida del modelo
Streaming «Cargarlo poco a poco» Procesar los datos fila a fila desde una fuente remota sin descargar el dataset completo
Parquet «Un CSV comprimido» Un formato de archivo por columnas, optimizado para consultas analíticas y para ocupar poco
Arrow «Un dataframe rápido» Un formato en memoria por columnas que usa la librería datasets para leer sin copias
Git LFS «Git para archivos grandes» Una extensión que guarda los archivos grandes fuera del repositorio y deja punteros en él
DVC «Git para datos» Un sistema de control de versiones para datasets y modelos que se integra con almacenamiento en la nube
Caché «Ya está descargado» Una copia local de los datos ya obtenidos; por defecto en ~/.cache/huggingface/

🧪 Practica esta lección

En el curso, esta lección incluye ejercicios interactivos con corrección automática y ejemplos de Python que ejecutas en tu navegador, sin instalar nada. Es gratis.

Practicar gratis en el curso →

📥 Archivos de la lección