Saltar al contenido

lección 3

Tipos de datos: estructurados, semiestructurados y no estructurados

Los tres reinos de los datos: tablas ordenadas, documentos flexibles y el caos creativo. Aprende a reconocer cada uno.

55 min

No todos los datos nacen iguales. Cuando alguien dice "tenemos muchos datos", la primera pregunta de un ingeniero es: ¿de qué tipo? Porque no es lo mismo una tabla de ventas con columnas fijas que un directorio de archivos PDF o un volcado de mensajes de chat donde cada mensaje tiene campos diferentes. El tipo determina cómo lo almacenas, cómo lo procesas y qué herramientas usas.

Piensa en una librería. Los datos estructurados son el catálogo: cada libro tiene título, autor, ISBN, año y precio — siempre los mismos campos, siempre el mismo formato. Los datos semiestructurados son las reseñas de los clientes: tienen cierta estructura (autor, fecha, puntuación) pero el texto de la reseña varía en longitud y contenido. Los datos no estructurados son las fotos del evento de presentación de un libro: no tienen campos definidos, son binarios, y extraer información de ellas requiere técnicas especiales.

### Datos estructurados: el mundo de las tablas

Los datos estructurados encajan perfectamente en una tabla con filas y columnas. Cada columna tiene un tipo definido (texto, número, fecha) y cada fila sigue exactamente el mismo esquema. Son los datos de toda la vida: la tabla de clientes de una tienda, la de productos de un almacén, la de transacciones de un banco. El 80% de tu trabajo será con datos estructurados.

1# Datos ESTRUCTURADOS: como una hoja de cálculo perfecta
2# Cada registro tiene EXACTAMENTE los mismos campos
3
4clientes = [
5 {"id": 1, "nombre": "Ana López", "edad": 28, "ciudad": "Madrid", "vip": True},
6 {"id": 2, "nombre": "Carlos Ruiz", "edad": 35, "ciudad": "Barcelona", "vip": False},
7 {"id": 3, "nombre": "Laura Sanz", "edad": 42, "ciudad": "Sevilla", "vip": True},
8]
9
10# Todos tienen: id (entero), nombre (texto), edad (entero), ciudad (texto), vip (booleano)
11# No hay sorpresas. Predecible. Fácil de procesar.
12for c in clientes:
13 print(f" {c['id']:3d} | {c['nombre']:15} | {c['edad']:3d} | {c['ciudad']:12} | VIP: {c['vip']}")

Datos estructurados: esquema fijo, tipos consistentes, como una hoja de cálculo

  • Ventaja: predecible. Sabes exactamente qué campos tiene cada registro.
  • Ventaja: eficiente. Las herramientas pueden optimizar porque conocen la estructura.
  • Ventaja: consultable. Puedes hacer preguntas precisas ("clientes VIP de Madrid").
  • Desventaja: rígido. Si mañana necesitas un campo nuevo, hay que modificar el esquema.
  • Desventaja: no todo encaja. ¿Cómo metes una imagen o un PDF en una tabla?

### Datos semiestructurados: flexibilidad con cierto orden

Los datos semiestructurados tienen estructura, pero no rígida. El ejemplo más común es JSON: cada documento tiene campos, pero distintos documentos pueden tener campos diferentes. No necesitas definir el esquema por adelantado. Es el formato de la web moderna: las APIs devuelven JSON, los logs de aplicaciones son JSON, los archivos de configuración son JSON o YAML.

1# Datos SEMIESTRUCTURADOS: estructura flexible
2# Cada evento tiene campos diferentes según el tipo
3
4eventos = [
5 {
6 "tipo": "compra",
7 "usuario": 42,
8 "timestamp": "2026-01-15T10:30:00",
9 "producto": "Teclado mecánico",
10 "importe": 89.90,
11 "metodo_pago": "tarjeta"
12 },
13 {
14 "tipo": "login",
15 "usuario": 42,
16 "timestamp": "2026-01-15T10:28:00",
17 "ip": "192.168.1.100",
18 "dispositivo": "móvil"
19 # No tiene "producto" ni "importe" -- y está bien!
20 },
21 {
22 "tipo": "error",
23 "timestamp": "2026-01-15T10:35:00",
24 "codigo": 500,
25 "mensaje": "Timeout en pasarela de pago",
26 "stack_trace": "File app.py, line 42..."
27 # No tiene "usuario" -- fue un error de sistema
28 }
29]
30
31# Mismo concepto (evento), pero campos diferentes según contexto.
32for e in eventos:
33 print(f" [{e['tipo']:8}] campos: {list(e.keys())}")

Datos semiestructurados: cada documento puede tener campos distintos

La flexibilidad es una bendición y una maldición. Bendición porque puedes evolucionar sin romper nada: si mañana los eventos de compra necesitan un campo "cupon_descuento", lo añades solo a los nuevos — los antiguos siguen funcionando. Maldición porque nunca puedes asumir que un campo existe: siempre tienes que comprobar antes de acceder ("¿tiene este evento el campo importe?"). Eso hace el código más defensivo y complejo.

### Datos no estructurados: el caos creativo

Los datos no estructurados no tienen un esquema definido en absoluto. Son archivos binarios, texto libre, imágenes, audio, vídeo. Para un ordenador, una imagen es simplemente una secuencia de bytes que representan píxeles — no hay "columnas" ni "campos". Extraer información útil de datos no estructurados requiere técnicas especiales (visión artificial, procesamiento de lenguaje natural, etc.) que están fuera del scope de esta skill.

  • Imágenes y fotos: una radiografía, la foto de un producto, un selfie.
  • Audio y vídeo: una llamada de atención al cliente, una videoconferencia grabada.
  • Texto libre: un email, un comentario en redes sociales, un documento Word.
  • PDFs escaneados: facturas, contratos, formularios.
  • Código fuente: los archivos .py que escribes son, para otro sistema, texto libre sin estructura.

El 80% de los datos del mundo son no estructurados. Pero irónicamente, el 80% del trabajo de ingeniería de datos se centra en datos estructurados y semiestructurados, porque son los que más directamente alimentan decisiones de negocio. Los no estructurados suelen pasar por un proceso de "extracción" que los convierte en estructurados antes de ser útiles (ejemplo: un modelo de IA que lee facturas PDF y extrae el importe, la fecha y el proveedor en una tabla).

Los tres reinos de los datos y el porcentaje aproximado de tu trabajo diario

### Cómo convertir semiestructurado en estructurado

Una tarea muy común en ingeniería de datos es tomar datos semiestructurados (como JSON de una API) y "aplanarlos" en una estructura tabular. Es como tomar un documento con viñetas anidadas y convertirlo en una hoja de cálculo plana. No siempre es trivial — especialmente cuando hay arrays o objetos anidados — pero es una habilidad que usarás constantemente.

1# Convertir JSON semiestructurado → tabla estructurada
2import json
3
4# Datos de una API (semiestructurados)
5respuesta_api = [
6 {"id": 1, "nombre": "Ana", "direccion": {"ciudad": "Madrid", "cp": "28001"}},
7 {"id": 2, "nombre": "Pedro", "direccion": {"ciudad": "Barcelona", "cp": "08001"}},
8 {"id": 3, "nombre": "Lucía", "direccion": None}, # Sin dirección!
9]
10
11# Aplanar: extraer campos anidados a nivel plano
12tabla = []
13for registro in respuesta_api:
14 fila = {
15 "id": registro["id"],
16 "nombre": registro["nombre"],
17 "ciudad": registro["direccion"]["ciudad"] if registro["direccion"] else None,
18 "cp": registro["direccion"]["cp"] if registro["direccion"] else None,
19 }
20 tabla.append(fila)
21
22# Ahora es estructurado: todos los registros tienen los mismos campos
23for fila in tabla:
24 print(fila)

Aplanar JSON anidado en una tabla plana: tarea cotidiana del ingeniero de datos

Consejo de senior: cuando aplanes datos semiestructurados, SIEMPRE maneja el caso None/null. Las APIs del mundo real devuelven campos opcionales, objetos nulos y arrays vacíos. Si no lo previenes, tu código explotará a las 3AM del primer lunes de mes.

### Ejemplos reales por industria

  • E-commerce: pedidos (estructurado), catálogo con atributos variables (semi), fotos de producto (no estructurado).
  • Banca: transacciones (estructurado), logs de sesión del usuario (semi), documentos de identidad escaneados (no).
  • Salud: historial clínico tabular (estructurado), notas del médico en texto libre (no), radiografías (no).
  • Redes sociales: tabla de usuarios (estructurado), publicaciones con campos variables (semi), vídeos e imágenes (no).
  • Logística: rutas y entregas (estructurado), eventos GPS con metadatos variables (semi), firmas digitalizadas (no).

Trampa real que he visto en producción: tratar datos semiestructurados como si fueran estructurados. "Asumimos que todos los eventos de la API tienen campo precio" — hasta que un día llega un evento sin ese campo y el pipeline explota. NUNCA asumas que un campo existe en datos semiestructurados. Siempre usa .get() con valor por defecto o comprueba con "if campo in registro".

El warning de arriba habla de .get() y de "campo" in dict. Si los recuerdas de Python, aquí van las dos juntas: .get() te da un valor seguro para operar, y "in" te dice si el campo existe — que no es lo mismo que si vale cero.

1# Dos herramientas para campos que pueden no existir:
2evento = {"tipo": "login", "usuario": 42}
3
4print(evento.get("importe", 0)) # 0 <- valor por defecto si no existe
5print("importe" in evento) # False <- ¿está el campo, sí o no?

.get() para operar seguro, "in" para preguntar si existe

### Resumen práctico

  1. 01.Estructurado = tabla con esquema fijo. Lo más fácil de procesar. CSV, bases de datos.
  2. 02.Semiestructurado = documentos con estructura flexible. JSON, XML, logs. Requiere más cuidado.
  3. 03.No estructurado = sin esquema. Imágenes, vídeo, texto libre. Requiere técnicas especiales.
  4. 04.Tu trabajo principal será con estructurados y semiestructurados.
  5. 05.Convertir semi → estructurado (aplanar JSON) es una tarea diaria del ingeniero de datos.

## ejercicios

[01]

Clasifica datos reales por tipo

Una empresa de delivery tiene varios tipos de datos. Clasifica cada uno. La regla: si el registro tiene campos con nombre (aunque uno sea texto libre), es semiestructurado. Si es un fichero binario o texto suelto, no lo es.

💡 Resultado esperado

  [        estructurado] Tabla de pedidos (id, cliente, restaurante, importe, fecha)
  [     no_estructurado] Foto del plato que sube el restaurante
  [    semiestructurado] JSON del evento de tracking GPS del repartidor
  [     no_estructurado] Grabación de la llamada al servicio al cliente
Cargando editor...
[02]

Aplanar JSON de una API de películas

Aplana cada película a 5 campos planos. Usa el ternario (a if cond else b) que has visto en la teoría. Ojo, son DOS problemas: el director puede ser None y la lista de géneros puede estar VACÍA.

💡 Resultado esperado

{'titulo': 'Matrix', 'anio': 1999, 'director_nombre': 'Lana', 'director_apellido': 'Wachowski', 'genero_principal': 'sci-fi'}
{'titulo': 'Origen', 'anio': 2010, 'director_nombre': 'Christopher', 'director_apellido': 'Nolan', 'genero_principal': 'sci-fi'}
{'titulo': 'Documental X', 'anio': 2023, 'director_nombre': None, 'director_apellido': None, 'genero_principal': None}
Cargando editor...
[03]

Acceso seguro a campos opcionales

Eventos de una app con campos variables. Extrae "importe" de forma segura y cuenta cuántos TIENEN el campo (no cuántos tienen un importe distinto de cero).

💡 Resultado esperado

Total facturado: 200.0€
Eventos con importe: 4
Eventos sin importe: 3
Cargando editor...
[04]

Detective de datos: encuentra los problemas

Un campo puede fallar de tres formas: no estar, ser None o ser un texto vacío. La primera comprobación ya está hecha; añade las otras dos.

💡 Resultado esperado

Correctos: 2
Con problemas: 4
  Registro 1: ["falta 'edad'"]
  Registro 3: ["falta 'nombre'"]
Cargando editor...

Regístrate para guardar tu progreso.

## comentarios

Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.

Inicia sesión para comentar y responder.

cargando comentarios...