Datasets: descargar, dividir y guardar
Buenos datos, bien divididos y bien guardados: la mitad del éxito de un modelo.
Qué vas a aprender
- Cargar, recibir en streaming y cachear datasets con la librería
datasetsde 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
- Carga el dataset
gluecon la configuraciónmrpce inspecciona los 5 primeros ejemplos - Recibe en streaming el dataset
c4y cuenta cuántos ejemplos procesas en 10 segundos - Convierte un dataset a Parquet y compara el tamaño del archivo con el CSV
- 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/ |