Terminamos la lección anterior constatando que la mayoría de los sistemas que NovaMarket va a construir son subsimbólicos: aprenden de datos. Esta lección se dedica a esa materia prima. Marta lleva semanas diciéndolo en cada reunión: "antes de hablar de modelos, hablemos de qué datos tenemos y en qué estado están". Tiene razón, y en esta lección veremos por qué. Explicaremos por qué los datos son el combustible de la IA, qué tipos de datos existen y cómo se organizan, cuál es el ciclo de vida del dato en una organización, cómo se mide su calidad y qué problemas concretos esconden los ficheros de NovaMarket, de dónde vienen los sesgos que después se convierten en decisiones injustas, qué obligaciones conceptuales impone la protección de datos personales y por qué la calidad importa más que la cantidad. Cerraremos con un programa en Python que lee un pedidos.csv de ejemplo y produce un pequeño informe de calidad, exactamente el tipo de comprobación que debería preceder a cualquier proyecto de IA.

Contenido

  1. Por qué los datos son el combustible de la IA
  2. Tipos de datos
  3. Datos etiquetados y no etiquetados
  4. El ciclo de vida del dato: recogida, almacenamiento, calidad, gobernanza
  5. Dimensiones de la calidad de los datos, con los problemas reales de NovaMarket
  6. Sesgo en los datos: el origen de la injusticia algorítmica
  7. Datos personales y RGPD: minimización, anonimización y seudonimización
  8. Cantidad frente a calidad; datos sintéticos
  9. Ejemplo en Python: un informe de calidad de pedidos.csv

  1. Por qué los datos son el combustible de la IA

Recuerda el esquema de 01-02: en la programación tradicional, datos + programa → resultados; en el aprendizaje automático, datos + resultados → modelo, y después el modelo produce resultados para datos nuevos. El modelo no contiene más conocimiento que el que había en los datos con los que se construyó. De ahí se derivan tres consecuencias que conviene grabarse:

  • Sin datos no hay modelo. El recomendador de 01-03 no podía recomendar nada para el televisor hasta que hubo pedidos con televisores (el "arranque en frío").
  • Con datos malos hay modelos malos. La expresión clásica es garbage in, garbage out: si el 50 % de la columna "causa" de incidencias.csv está vacía, ningún algoritmo va a diagnosticar bien las incidencias.
  • El modelo hereda todo lo que hay en los datos, incluidos los errores, las lagunas y los sesgos. Si históricamente NovaMarket revisó más los pedidos de ciertos códigos postales, un modelo entrenado con ese historial aprenderá a sospechar de esos códigos postales (lo desarrollaremos en la sección 6 y en 02-04).

Por eso, en un proyecto real de IA, entre el 60 % y el 80 % del esfuerzo se dedica a obtener, entender, limpiar y preparar datos, no a entrenar modelos. Es lo primero que Marta quiso que Diego entendiera: el "coste de la IA" es en gran parte el coste de poner en orden los datos, y ese coste se amortiza en todos los proyectos posteriores.

  1. Tipos de datos

Los datos se clasifican de varias maneras complementarias. Conocerlas ayuda a saber qué técnica se puede aplicar y qué preparación necesitarán.

2.1 Por su estructura

Tipo Qué es Ejemplos en NovaMarket Cómo se trabaja
Estructurados Tablas con filas y columnas de tipo fijo pedidos.csv, clientes.csv, productos.csv, la base de datos de stock Consultas SQL, hojas de cálculo, ML clásico directamente
Semiestructurados Tienen etiquetas o jerarquía, pero no un esquema rígido Respuestas JSON de la API de la mensajería, ficheros de log del servidor web, correos con cabeceras Hay que extraer campos antes de analizarlos
No estructurados Sin organización predefinida Texto libre de resenas.csv, transcripciones del chat de atención al cliente, fotos de productos devueltos, audios de llamadas Requieren PLN, visión por computador o extracción previa

La mayoría del volumen de datos de una empresa es no estructurado, y la mayoría del valor histórico se ha extraído de los estructurados. El deep learning (módulo 5) cambió eso al hacer explotable el texto y la imagen.

2.2 Por la naturaleza del valor

Tipo Descripción Ejemplos Observación
Numéricos Cantidades con las que tiene sentido operar Importe del pedido, peso del paquete, unidades vendidas Pueden ser continuos (importe) o discretos (unidades)
Categóricos Etiquetas de un conjunto finito Ciudad, categoría de producto, estado del pedido, causa de la incidencia Sin orden (nominal: ciudad) o con orden (ordinal: talla S/M/L, satisfacción 1-5)
Texto Cadenas de lenguaje natural Reseñas, mensajes del chat, descripciones de producto No estructurado; requiere PLN
Imagen / audio / vídeo Señales percibidas Fotos de productos, fotos de daños en devoluciones, llamadas No estructurado; requiere visión o procesamiento de señal
Series temporales Valores numéricos ordenados en el tiempo Ventas diarias por producto, tráfico web por hora, tiempos de entrega El orden importa; base de la previsión de demanda
Fechas e identificadores Marcas de tiempo, claves fecha, id_pedido, id_cliente Ni numéricos ni categóricos "de verdad": sirven para relacionar y ordenar

Un mismo fichero mezcla varios: pedidos.csv tiene identificadores, una fecha, un importe numérico, una ciudad categórica y una columna devuelto categórica binaria. Saber qué es cada columna es el primer paso de cualquier análisis, y es sorprendente cuántos problemas vienen de tratar un identificador como número (sumar códigos postales) o un número como texto (ordenar importes alfabéticamente: "1000" antes que "200").

  1. Datos etiquetados y no etiquetados

Una distinción decisiva para el aprendizaje automático:

  • Datos etiquetados: cada ejemplo lleva asociada la respuesta correcta que queremos que el modelo aprenda a producir. En pedidos.csv, la columna devuelto es la etiqueta si queremos predecir devoluciones. En resenas.csv, una columna "sentimiento" (positivo/negativo) puesta por una persona sería la etiqueta.
  • Datos no etiquetados: solo tenemos los ejemplos, sin respuesta. Miles de reseñas sin clasificar, el historial de navegación sin saber qué acabó comprando el cliente.

Con datos etiquetados se puede hacer aprendizaje supervisado (aprender la relación entre las características y la etiqueta); con datos no etiquetados, aprendizaje no supervisado (descubrir estructura: grupos de clientes parecidos, productos que se compran juntos). Ambos se desarrollan en 04-02; aquí basta con saber que las etiquetas son caras (a menudo hay que ponerlas a mano) y valiosas, y que su calidad condiciona todo.

Un ejemplo de lo cara y delicada que es la etiqueta: incidencias.csv tiene unos 400 registros y la mitad de la columna causa vacía. Esa columna es la etiqueta que el caso de uso 9 (diagnóstico de incidencias) necesitaría aprender. Con 200 ejemplos etiquetados de forma desigual (los operadores rellenaban la causa cuando tenían tiempo, es decir, más en los días tranquilos y menos en los picos), el sistema aprendería de una muestra sesgada. Diego propuso una solución no técnica pero correcta: hacer obligatoria la causa en el formulario a partir de ahora y organizar una sesión para etiquetar retrospectivamente las 200 que faltan.

  1. El ciclo de vida del dato: recogida, almacenamiento, calidad, gobernanza

Los datos no aparecen listos para usar; atraviesan un ciclo, y cada etapa puede introducir o corregir problemas:

flowchart LR
    R[Recogida<br/>formularios, sensores,<br/>logs, APIs, compras] --> A[Almacenamiento<br/>bases de datos, ficheros,<br/>almacén de datos]
    A --> C[Calidad<br/>validación, limpieza,<br/>deduplicación]
    C --> U[Uso<br/>análisis, modelos,<br/>decisiones]
    U --> G[Gobernanza<br/>propiedad, acceso,<br/>retención, cumplimiento]
    G -.-> R
  • Recogida: cómo entran los datos. Cada canal tiene sus vicios: el formulario web de devoluciones permite dejar campos vacíos; el terminal del almacén guarda el peso en gramos y la web en kilos; la mensajería externa envía las fechas en formato DD/MM/AAAA mientras el sistema interno usa AAAA-MM-DD. La regla de oro es validar en origen: es mucho más barato obligar a rellenar la causa de la incidencia en el momento que reconstruirla meses después.
  • Almacenamiento: dónde y cómo se guardan. Bases de datos transaccionales (las que soportan la tienda), almacenes de datos para análisis, ficheros planos como los CSV con los que trabajamos en el curso. Aquí importan la trazabilidad (¿de dónde viene cada dato?, ¿cuándo se cargó?) y el esquema (qué significa cada columna, en qué unidades).
  • Calidad: comprobar y corregir (sección 5). Idealmente es un proceso continuo, no un arreglo puntual antes de cada proyecto.
  • Uso: análisis, informes, entrenamiento de modelos, decisiones. Es lo que justifica todo lo anterior.
  • Gobernanza: el conjunto de normas y responsabilidades sobre los datos: quién es propietario de cada conjunto de datos (Marta propuso que cada área lo sea de los suyos: operaciones de incidencias.csv, marketing de resenas.csv), quién puede acceder a qué, cuánto tiempo se conservan, cómo se documentan (un diccionario de datos con la definición de cada columna) y cómo se cumple la legislación (sección 7). La gobernanza cierra el ciclo porque sus normas mejoran la siguiente recogida.

Sin gobernanza, cada proyecto de IA vuelve a descubrir los mismos problemas. Con ella, el segundo proyecto de NovaMarket (previsión de demanda) reutiliza los datos limpios del primero (recomendación).

  1. Dimensiones de la calidad de los datos, con los problemas reales de NovaMarket

"Datos de calidad" no es un juicio vago: se descompone en dimensiones medibles. Las cinco más usadas, con los problemas que Marta encontró al abrir los CSV de NovaMarket por primera vez:

Dimensión Pregunta Problema real encontrado en NovaMarket Consecuencia si no se corrige Posible corrección
Completitud ¿Faltan valores? La mitad de la columna causa de incidencias.csv está vacía; algunos pedidos sin codigo_postal El diagnóstico de incidencias no puede aprender; los modelos que usan código postal descartan filas Hacer el campo obligatorio; etiquetar retrospectivamente; para el resto, decidir si imputar o descartar (04-03)
Exactitud ¿Los valores son correctos? Precios de productos.csv en céntimos en una parte del catálogo (importada de un proveedor) y en euros en el resto: un cable a "1299" Un modelo de previsión aprende que un cable vale más que un portátil; las medias se disparan Unificar la unidad; detectar valores fuera de rango con reglas
Consistencia ¿Los mismos hechos se representan igual en todas partes? Fechas mezcladas: 2026-03-02, 02/03/2026, 03-03-2026; ciudad como "Zaragoza", "zaragoza", "ZARAGOZA " Ordenar por fecha falla; "Zaragoza" y "zaragoza" cuentan como ciudades distintas Normalizar formatos y mayúsculas al cargar; validar en origen
Actualidad ¿Los datos reflejan el estado presente? Direcciones de clientes que no se actualizan; stock del almacén de Getafe con retraso de horas Rutas mal planificadas; asignación de pedidos a almacenes sin stock Definir la frecuencia de actualización aceptable por dato; marcar la fecha de última modificación
Unicidad ¿Hay duplicados? Clientes duplicados en clientes.csv (mismo correo con mayúsculas distintas o con un espacio final; misma persona con dos correos); un mismo pedido cargado dos veces El recomendador ve dos clientes donde hay uno; se cuentan ventas de más Definir la clave de unicidad; deduplicar con normalización; evitar la doble carga

Dos comentarios importantes:

  • La calidad se mide, no se supone. Marta hizo lo que haremos en la sección 9: contar vacíos, duplicados y formatos por columna y ponerle números. Descubrir que un 58 % de las filas de una muestra tenía algún problema fue lo que convenció a Diego de dedicar tiempo a la limpieza antes que a los modelos.
  • La calidad depende del uso. Un código postal vacío es irrelevante para clasificar reseñas y grave para planificar rutas. No existe "el" nivel de calidad: existe el suficiente para cada caso de uso.

Cómo se limpian estos problemas para preparar un modelo (imputación de valores, codificación de categorías, escalado, tratamiento de atípicos) es el contenido de 04-03; aquí nos quedamos en detectarlos y medirlos.

  1. Sesgo en los datos: el origen de la injusticia algorítmica

Un sesgo en los datos es una desviación sistemática entre lo que los datos representan y la realidad que deberían representar. No es un problema de "datos sucios" (los datos pueden estar limpísimos y sesgados) sino de qué se recogió, de quién y cómo se etiquetó. Como el modelo hereda lo que hay en los datos, el sesgo se convierte en decisiones sistemáticamente desviadas, y cuando esas decisiones afectan a personas, en injusticia algorítmica. Los tres orígenes principales:

Tipo de sesgo Qué ocurre Ejemplo en NovaMarket Efecto en el modelo
De muestreo La muestra no representa a la población: unos grupos están sobrerrepresentados y otros casi ausentes Las reseñas las escriben sobre todo clientes muy satisfechos o muy enfadados; los clientes de ciudades sin reparto propio apenas aparecen en incidencias.csv porque sus incidencias las gestiona la mensajería El clasificador de reseñas no reconoce opiniones templadas; el diagnóstico de incidencias no sabe nada de las ciudades con mensajería
Histórico Los datos reflejan fielmente un pasado que era injusto o distinto Durante años el equipo revisó manualmente más los pedidos de ciertos códigos postales; en el histórico esos códigos tienen más "fraude detectado" simplemente porque se buscó más allí El modelo de riesgo aprende que esos códigos postales son de riesgo, y al revisar más allí encuentra más, reforzando el sesgo (bucle de retroalimentación)
De etiquetado Las etiquetas las ponen personas (o procesos) con criterios inconsistentes o prejuicios La causa de las incidencias la rellenan operadores distintos: unos ponen "error de almacén" donde otros ponen "producto dañado"; los días de pico se etiqueta peor El modelo aprende el criterio de cada operador, no la causa real

Otros sesgos frecuentes: el de supervivencia (solo vemos los datos que "sobrevivieron": analizamos a los clientes que siguen comprando y olvidamos por qué se fueron los que se fueron), el de medición (un sensor o formulario captura peor a un grupo: el formulario de devoluciones en la app es más incómodo que en la web, así que los clientes de móvil rellenan menos) y el de confirmación en el análisis (buscar en los datos lo que ya creíamos, como la regla de 300 € de Diego).

Lo esencial en esta lección: el sesgo entra por los datos y se manifiesta en las decisiones. Cómo evaluar sus consecuencias éticas, cómo medir la disparidad entre grupos y qué hacer al respecto es el contenido de la próxima lección, 02-04.

  1. Datos personales y RGPD: minimización, anonimización y seudonimización

Buena parte de los datos de NovaMarket son datos personales: identifican o permiten identificar a una persona (nombre, correo, dirección, teléfono, historial de compras, incluso una combinación de código postal, fecha de nacimiento y sexo). En la Unión Europea su tratamiento está regulado por el Reglamento General de Protección de Datos (RGPD). Aquí no vamos a estudiar la norma (que se retoma en el marco regulatorio de 02-04) sino los principios que afectan directamente al trabajo con datos para IA:

  • Finalidad y base jurídica: los datos se recogen para un fin concreto y con una base legal (contrato, consentimiento, interés legítimo...). Usar el historial de compras para recomendar productos puede encajar; usarlo para algo no previsto (venderlo, perfilar con fines ajenos) no.
  • Minimización: recoger y usar solo los datos necesarios para el fin. Si para prever la demanda basta con la fecha, el producto, la ciudad y las unidades, no hace falta cargar el nombre y el correo del cliente en el conjunto de entrenamiento. Menos datos personales significa menos riesgo y menos obligaciones.
  • Limitación del plazo de conservación: no guardar datos personales más tiempo del necesario. Esto choca con el instinto de "guardar todo por si sirve para entrenar algo"; hay que definir plazos.
  • Derechos de las personas: acceso, rectificación, supresión ("olvido"), oposición al perfilado y a decisiones automatizadas con efectos significativos. Un modelo entrenado con los datos de un cliente que pide su supresión plantea preguntas prácticas que el proyecto debe prever.
  • Seguridad: proteger los datos frente a accesos indebidos, especialmente cuando se copian a entornos de análisis o se envían a servicios en la nube (recuerda la dicotomía nube/dispositivo de 02-02).

Dos técnicas que reducen el riesgo y que aparecerán constantemente:

Técnica Qué hace Ejemplo ¿Sigue siendo dato personal?
Seudonimización Sustituye los identificadores directos por un código; la correspondencia se guarda aparte y protegida clientes.csv con id_cliente = C1001 en lugar del nombre y correo; la tabla que relaciona C1001 con la persona la custodia otro equipo (se puede revertir con la tabla), pero con menor riesgo; el RGPD lo reconoce como medida de seguridad
Anonimización Elimina o transforma los datos de manera que no sea posible volver a identificar a la persona, ni combinándolos con otros Agregar ventas por ciudad y semana sin ningún identificador; generalizar el código postal a los dos primeros dígitos; eliminar campos únicos No, si la anonimización es real. Pero es difícil de lograr: la combinación de pocos datos "inocentes" puede reidentificar

Marta decidió que los conjuntos de datos que se usen para entrenar modelos en NovaMarket estén siempre, como mínimo, seudonimizados, y que la previsión de demanda trabaje con datos agregados (anónimos).

Aviso importante: todo lo anterior es una descripción conceptual con fines formativos, no asesoramiento jurídico. Cualquier proyecto que trate datos personales debe revisarse con el delegado de protección de datos o un profesional legal, que evaluará la base jurídica, la necesidad de una evaluación de impacto y las medidas concretas.

  1. Cantidad frente a calidad; datos sintéticos

Es habitual oír que "cuantos más datos, mejor". Es cierto a medias:

  • Más datos ayudan cuando son variados y representativos: permiten aprender patrones más finos y reducen el peligro de que el modelo memorice casos concretos (el sobreajuste, tema de 04-06). Los grandes avances del deep learning se apoyaron en conjuntos enormes.
  • Más datos malos no ayudan: multiplicar por diez un conjunto sesgado da un modelo diez veces más seguro de su sesgo. Doscientos ejemplos bien etiquetados de causas de incidencia valen más que dos mil etiquetados de cualquier manera.
  • Los datos deben ser relevantes: para el recomendador de NovaMarket, los pedidos de otra tienda de otro sector aportan poco.

Regla práctica: primero calidad y representatividad; después, cantidad. Y mide siempre si más datos mejoran realmente el resultado.

Los datos sintéticos son datos generados artificialmente (mediante reglas, simulación o modelos generativos) que imitan las propiedades estadísticas de los reales. Se usan para: completar clases poco frecuentes (hay muy pocos fraudes reales de los que aprender), probar sistemas sin exponer datos personales, o simular escenarios que aún no han ocurrido (una campaña de Navidad para un producto nuevo). Tienen un límite evidente: solo contienen lo que quien los generó sabía o supuso; no descubren nada nuevo del mundo, y si se generan a partir de datos sesgados, heredan el sesgo. Son un complemento, no un sustituto.

  1. Ejemplo en Python: un informe de calidad de pedidos.csv

Vamos a hacer lo que hizo Marta el primer día: leer un extracto de pedidos.csv, contar los problemas por dimensión y producir un pequeño informe. Para que el ejemplo sea autocontenido, el CSV está escrito dentro del programa como una cadena de texto; en la práctica lo leerías con open("pedidos.csv"). Solo usamos la biblioteca estándar: csv, io, re y collections.

9.1 Los datos y su lectura

import csv
import io
import re
from collections import Counter

DATOS_PEDIDOS = """id_pedido,id_cliente,fecha,importe,ciudad,codigo_postal,devuelto
48201,C1001,2026-03-02,89.90,Zaragoza,50001,no
48202,C1002,02/03/2026,15990,Madrid,28045,no
48203,C1003,2026-03-02,,Getafe,28901,si
48204,C1001,2026-03-03,45.00,zaragoza,50001,no
48205,C1004,03-03-2026,320.50,Valencia,46001,si
48206,C1005,2026-03-03,12.99,Madrid,,no
48207,C1002,2026-03-04,159.90,Madrid,28045,no
48202,C1002,02/03/2026,15990,Madrid,28045,no
48208,C1006,2026-13-04,75.00,Sevilla,41001,no
48209,,2026-03-04,210.00,Bilbao,48001,
48210,C1007,2026-03-05,58.40,Zaragoza,50002,no
48211,C1008,2026-03-05,1299.00,Getafe,28901,no
"""

def leer_pedidos(texto_csv):
    # io.StringIO convierte la cadena en algo que se lee como un fichero.
    # csv.DictReader devuelve cada fila como un diccionario {columna: valor}.
    lector = csv.DictReader(io.StringIO(texto_csv))
    return list(lector)

pedidos = leer_pedidos(DATOS_PEDIDOS)
print(f"Filas leidas: {len(pedidos)}")
print(pedidos[0])

Salida:

Filas leidas: 12
{'id_pedido': '48201', 'id_cliente': 'C1001', 'fecha': '2026-03-02', 'importe': '89.90', 'ciudad': 'Zaragoza', 'codigo_postal': '50001', 'devuelto': 'no'}

Explicación: csv.DictReader lee la primera línea como cabecera y convierte cada línea siguiente en un diccionario, lo que nos permite acceder a los valores por nombre (fila["importe"]). Observa que todo se lee como texto: '89.90' es una cadena, no un número; convertirlo será responsabilidad nuestra. Si miras los datos con atención ya verás los problemas sembrados: un importe vacío, un id_cliente vacío, un devuelto vacío, un codigo_postal vacío, tres formatos de fecha, una fecha con mes 13, un importe de 15990 que huele a céntimos, "zaragoza" en minúsculas y el pedido 48202 dos veces.

9.2 Completitud: contar vacíos por columna

def informe_completitud(filas):
    columnas = filas[0].keys()
    total = len(filas)
    print(f"{'columna':15s} {'vacios':>7s} {'% vacios':>9s}")
    for col in columnas:
        vacios = sum(1 for f in filas if f[col].strip() == "")
        print(f"{col:15s} {vacios:7d} {100*vacios/total:8.1f}%")

informe_completitud(pedidos)

Salida:

columna          vacios  % vacios
id_pedido             0      0.0%
id_cliente            1      8.3%
fecha                 0      0.0%
importe               1      8.3%
ciudad                0      0.0%
codigo_postal         1      8.3%
devuelto              1      8.3%

Explicación: para cada columna recorremos las filas y contamos las que tienen la celda vacía tras quitar espacios (strip()); un espacio en blanco también es un vacío. La expresión sum(1 for f in filas if ...) es una forma compacta de contar. Con el incidencias.csv real, este informe es el que mostraría "causa: 50,0 %".

9.3 Unicidad: duplicados

def detectar_duplicados(filas, clave):
    # Counter cuenta cuantas veces aparece cada valor de la clave.
    contador = Counter(f[clave] for f in filas)
    return {valor: veces for valor, veces in contador.items() if veces > 1}

print(detectar_duplicados(pedidos, "id_pedido"))     # {'48202': 2}

Explicación: Counter construye un diccionario valor → número de apariciones; nos quedamos con los que aparecen más de una vez. Aquí el duplicado es exacto (la misma fila cargada dos veces), el caso fácil. Los duplicados difíciles son los de clientes.csv: mismo cliente con correo en mayúsculas o con espacio final. Para esos, la clave habría que normalizarla antes de contar: f["email"].strip().lower(). Pruébalo como variante.

9.4 Consistencia: formatos de fecha mezclados

PATRONES_FECHA = {
    "AAAA-MM-DD": re.compile(r"^\d{4}-\d{2}-\d{2}$"),
    "DD/MM/AAAA": re.compile(r"^\d{2}/\d{2}/\d{4}$"),
    "DD-MM-AAAA": re.compile(r"^\d{2}-\d{2}-\d{4}$"),
}

def clasificar_fecha(texto):
    for nombre, patron in PATRONES_FECHA.items():
        if patron.match(texto):
            return nombre
    return "desconocido"

formatos = Counter(clasificar_fecha(f["fecha"]) for f in pedidos)
print(formatos)      # Counter({'AAAA-MM-DD': 9, 'DD/MM/AAAA': 2, 'DD-MM-AAAA': 1})

Explicación: cada patrón es una expresión regular: ^\d{4}-\d{2}-\d{2}$ significa "exactamente cuatro dígitos, guion, dos dígitos, guion, dos dígitos". clasificar_fecha devuelve el nombre del primer patrón que encaja. El Counter final nos dice cuántas fechas hay de cada formato: tres filas no siguen el estándar. Ordenar o comparar esas fechas como texto daría resultados absurdos, y cualquier programa que esperase AAAA-MM-DD fallaría en ellas.

9.5 Exactitud: valores imposibles y unidades sospechosas

def fecha_valida(texto):
    # Solo comprobamos las que ya tienen formato estandar.
    if not PATRONES_FECHA["AAAA-MM-DD"].match(texto):
        return False
    anio, mes, dia = (int(x) for x in texto.split("-"))
    return 1 <= mes <= 12 and 1 <= dia <= 31

imposibles = [f["id_pedido"] for f in pedidos
              if clasificar_fecha(f["fecha"]) == "AAAA-MM-DD" and not fecha_valida(f["fecha"])]
print("Fechas imposibles:", imposibles)         # ['48208']  (mes 13)

def importes_sospechosos(filas, umbral=5000):
    sospechosos = []
    for f in filas:
        if f["importe"].strip() == "":
            continue                             # el vacio ya lo contamos en completitud
        valor = float(f["importe"])
        if valor > umbral:
            sospechosos.append((f["id_pedido"], valor))
    return sospechosos

print("Importes sospechosos:", importes_sospechosos(pedidos))
# [('48202', 15990.0), ('48202', 15990.0)]

Explicación: la exactitud no se puede comprobar del todo sin una fuente de verdad, pero sí podemos detectar valores imposibles (mes 13) y valores fuera del rango razonable (un pedido de 15.990 € en una tienda cuyo ticket medio ronda los 100 € huele a importe en céntimos: 159,90 €). El umbral de 5.000 € es una regla de negocio que fijó Diego. Fíjate en que el importe sospechoso aparece dos veces porque la fila está duplicada: los problemas de calidad se acumulan.

9.6 Consistencia de categorías

def informe_ciudades(filas):
    tal_cual = Counter(f["ciudad"] for f in filas)
    normalizadas = Counter(f["ciudad"].strip().lower() for f in filas)
    print("Ciudades distintas tal cual:", len(tal_cual), sorted(tal_cual))
    print("Ciudades distintas normalizadas:", len(normalizadas))

informe_ciudades(pedidos)

Salida:

Ciudades distintas tal cual: 7 ['Bilbao', 'Getafe', 'Madrid', 'Sevilla', 'Valencia', 'Zaragoza', 'zaragoza']
Ciudades distintas normalizadas: 6

Explicación: contando los valores tal cual hay siete ciudades; normalizando (sin espacios, en minúsculas) hay seis. La diferencia es exactamente el número de inconsistencias. Este truco (comparar el número de valores distintos antes y después de normalizar) sirve para cualquier columna categórica.

9.7 El informe de calidad completo

def informe_calidad(filas):
    total = len(filas)
    print("=== INFORME DE CALIDAD: pedidos.csv ===")
    print(f"Registros: {total}")

    dup = detectar_duplicados(filas, "id_pedido")
    print(f"Unicidad:     {len(dup)} id_pedido repetidos {sorted(dup)}")

    vacios = sum(1 for f in filas for col in f if f[col].strip() == "")
    print(f"Completitud:  {vacios} celdas vacias")

    formatos = Counter(clasificar_fecha(f["fecha"]) for f in filas)
    no_estandar = total - formatos.get("AAAA-MM-DD", 0)
    print(f"Consistencia: {no_estandar} fechas fuera de AAAA-MM-DD")

    imposibles = [f["id_pedido"] for f in filas
                  if clasificar_fecha(f["fecha"]) == "AAAA-MM-DD" and not fecha_valida(f["fecha"])]
    sosp = importes_sospechosos(filas)
    ids_sosp = {s[0] for s in sosp}
    print(f"Exactitud:    {len(imposibles)} fechas imposibles, {len(sosp)} importes sospechosos")

    # Una fila es problematica si tiene al menos un problema de cualquier tipo
    filas_con_problema = 0
    for f in filas:
        problema = (any(f[c].strip() == "" for c in f)
                    or dup.get(f["id_pedido"], 0) > 1
                    or clasificar_fecha(f["fecha"]) != "AAAA-MM-DD"
                    or f["id_pedido"] in imposibles
                    or f["id_pedido"] in ids_sosp)
        if problema:
            filas_con_problema += 1

    porcentaje = 100 * filas_con_problema / total
    print(f"Filas con algun problema: {filas_con_problema} de {total} ({porcentaje:.0f}%)")
    print(f"Puntuacion de calidad: {100 - porcentaje:.0f}/100")

informe_calidad(pedidos)

Salida:

=== INFORME DE CALIDAD: pedidos.csv ===
Registros: 12
Unicidad:     1 id_pedido repetidos ['48202']
Completitud:  4 celdas vacias
Consistencia: 3 fechas fuera de AAAA-MM-DD
Exactitud:    1 fechas imposibles, 2 importes sospechosos
Filas con algun problema: 7 de 12 (58%)
Puntuacion de calidad: 42/100

Explicación: el informe reúne las comprobaciones anteriores y añade una métrica global: el porcentaje de filas con al menos un problema. Un 58 % de filas problemáticas en una muestra pequeña y exagerada; en el fichero real de NovaMarket la cifra fue menor pero suficiente para justificar un proyecto previo de limpieza. La "puntuación de calidad" es una simplificación (todas las dimensiones pesan igual), pero convierte una sensación en un número que se puede seguir en el tiempo: el objetivo de Marta es que suba mes a mes. Como ejercicio mental, piensa qué añadirías para medir la actualidad (necesitarías una columna con la fecha de última actualización) y qué necesitarías para medir la exactitud de verdad (una fuente de referencia con la que comparar).

Errores Comunes y Consejos

  • Empezar por el modelo. El impulso natural es entrenar algo cuanto antes. Empieza siempre por un informe de calidad como el de la sección 9; una hora de comprobaciones ahorra semanas de depurar por qué el modelo "hace cosas raras".
  • Confiar en que un fichero limpio no está sesgado. Calidad y representatividad son cosas distintas. Pregunta siempre quién falta en los datos y por qué.
  • Tratar el vacío como cero, o como una categoría más, sin pensarlo. Un importe vacío no es un importe de 0 €; una causa vacía no es "sin causa". Antes de decidir qué hacer con los vacíos hay que entender por qué faltan (¿es aleatorio o falta más en los días de pico?).
  • Ignorar las unidades. Céntimos frente a euros, gramos frente a kilos, hora local frente a UTC. Documenta las unidades en el diccionario de datos y valida los rangos.
  • Guardar todo "por si acaso". Choca con la minimización y la limitación de conservación del RGPD y aumenta el riesgo. Recoge y conserva lo necesario para un fin definido.
  • Anonimizar quitando solo el nombre. Código postal + fecha de nacimiento + sexo identifican a una gran parte de la población. Si necesitas anonimizar de verdad, agrega o generaliza, y pide revisión experta.
  • Consejo: crea el diccionario de datos desde el primer día (columna, significado, tipo, unidad, valores permitidos, quién es responsable). Es el documento más útil y menos glamuroso de un proyecto de IA.

Ejercicios

Ejercicio 1: Clasificar los datos de NovaMarket

Para cada uno de los cinco ficheros (clientes.csv, pedidos.csv, productos.csv, resenas.csv, incidencias.csv), indica: (a) si es estructurado, semiestructurado o no estructurado (o mixto: qué columnas de cada tipo); (b) qué columna podría ser una etiqueta y para qué caso de uso de la lista de 01-03; (c) si contiene datos personales y qué medida (seudonimización, anonimización, minimización) aplicarías antes de usarlo para entrenar.

Ejercicio 2: Sesgo en el modelo de riesgo de devolución

NovaMarket quiere entrenar un modelo que prediga si un pedido será devuelto, usando el histórico de pedidos.csv de los últimos tres años. Durante ese periodo: (i) las devoluciones de la app móvil se registraban en otro sistema y no están en el fichero; (ii) el equipo de Diego revisaba manualmente y anulaba muchas devoluciones "dudosas" de pedidos de más de 300 € (su antigua regla); (iii) la columna motivo_devolucion la rellenaban los clientes libremente. Identifica qué tipo de sesgo introduce cada circunstancia y qué efecto tendría en el modelo.

Ejercicio 3: Ampliar el informe de calidad

Amplía el programa de la sección 9 con dos comprobaciones: (a) el campo devuelto solo admite los valores si y no (cualquier otro, incluido el vacío, es un problema de consistencia); (b) el codigo_postal, cuando no está vacío, debe tener exactamente 5 dígitos y sus dos primeros dígitos deben ser coherentes con la ciudad para al menos estos casos: Zaragoza → 50, Madrid → 28, Getafe → 28 (problema de exactitud). Añade el recuento de ambos al informe.

Soluciones

Solución 1.

Fichero Estructura Etiqueta posible (caso de uso) Datos personales y medida
clientes.csv Estructurado (nombre, correo, dirección, fecha de alta) Ninguna evidente; podría añadirse "cliente activo/inactivo" para predecir abandono (no está en la lista de 9, pero es habitual) Sí, plenamente: seudonimizar (sustituir nombre y correo por id_cliente); minimizar (¿hace falta la dirección completa para recomendar? probablemente basta la ciudad)
pedidos.csv Estructurado devuelto (caso 3, riesgo de devolución); unidades por producto y fecha son la serie temporal del caso 2 (previsión) Sí, mientras contenga id_cliente vinculable: seudonimizado; para previsión de demanda, agregar por producto/ciudad/día (anonimizado)
productos.csv Estructurado (categoría, precio, peso) con una columna no estructurada (descripción en texto) Ninguna; es información de contexto (características) para casos 1, 2 y 6 No contiene datos personales
resenas.csv Mixto: columnas estructuradas (id_producto, puntuacion, fecha) y texto libre no estructurado puntuacion (1-5) puede servir de etiqueta aproximada de sentimiento para el caso 4; mejor una etiqueta puesta a mano Sí: id_cliente y, potencialmente, el propio texto (la gente escribe su nombre o datos); seudonimizar y revisar el texto
incidencias.csv Mixto: columnas estructuradas (id_pedido, fecha, tipo, causa) y descripción libre causa (caso 9, diagnóstico), con el problema de estar vacía en la mitad de las filas Sí, indirectamente vía id_pedido → cliente; seudonimizar

Solución 2.

  • (i) Devoluciones de la app ausentes: sesgo de muestreo (o de medición). El modelo subestimará las devoluciones de los clientes que compran por móvil; si el canal está correlacionado con la edad o el tipo de producto, el modelo se equivocará sistemáticamente en esos grupos.
  • (ii) Anulaciones manuales de devoluciones dudosas de más de 300 €: sesgo histórico (los datos reflejan una política pasada). El histórico contiene menos devoluciones "consumadas" en pedidos altos de lo que ocurriría sin la intervención de Diego; el modelo puede aprender que los pedidos caros se devuelven poco, justo lo contrario de lo que motivó la regla, y además incorpora el criterio subjetivo de qué era "dudoso". Si el modelo se usa para decidir qué revisar, se crea un bucle de retroalimentación.
  • (iii) Motivo escrito libremente por el cliente: sesgo de etiquetado (y problema de consistencia). "No me gusta", "no era lo que esperaba", "talla" y "calidad mala" pueden ser lo mismo o no; el modelo aprende las palabras que usa cada cliente, no la causa real. Habría que normalizar los motivos a una lista cerrada antes de usarlos como etiqueta.

Solución 3.

def problemas_devuelto(filas):
    return [f["id_pedido"] for f in filas if f["devuelto"].strip() not in ("si", "no")]

PREFIJOS_CP = {"zaragoza": "50", "madrid": "28", "getafe": "28"}

def problemas_codigo_postal(filas):
    malos = []
    for f in filas:
        cp = f["codigo_postal"].strip()
        if cp == "":
            continue                                   # ya contado en completitud
        ciudad = f["ciudad"].strip().lower()
        if not re.fullmatch(r"\d{5}", cp):
            malos.append((f["id_pedido"], cp, "formato"))
        elif ciudad in PREFIJOS_CP and not cp.startswith(PREFIJOS_CP[ciudad]):
            malos.append((f["id_pedido"], cp, "no coincide con " + f["ciudad"]))
    return malos

print("devuelto no valido:", problemas_devuelto(pedidos))         # ['48209']
print("codigo postal:", problemas_codigo_postal(pedidos))         # [] con los datos de ejemplo

Para incorporarlo al informe basta añadir dos líneas dentro de informe_calidad con len(problemas_devuelto(filas)) y len(problemas_codigo_postal(filas)) e incluir esos identificadores en la condición de "fila con problema". Con los datos de ejemplo la comprobación de código postal no encuentra errores; añade una fila 48212,C1009,2026-03-06,20.00,Madrid,50003,no y comprueba que la detecta.

Conclusión

En esta lección hemos tratado los datos como lo que son en la IA moderna: la materia prima de la que el modelo hereda todo, tanto el conocimiento como los errores y los sesgos. Hemos clasificado los datos por estructura (estructurados, semiestructurados, no estructurados), por naturaleza (numéricos, categóricos, texto, imagen, series temporales) y por la presencia de etiquetas, anticipando la distinción entre aprendizaje supervisado y no supervisado. Hemos recorrido el ciclo de vida del dato (recogida, almacenamiento, calidad, uso, gobernanza) y hemos desglosado la calidad en cinco dimensiones medibles (completitud, exactitud, consistencia, actualidad, unicidad) ilustradas con los problemas reales de los CSV de NovaMarket: la mitad de la columna causa vacía, clientes duplicados, fechas en tres formatos y precios en céntimos. Hemos visto que el sesgo entra por los datos (muestreo, histórico, etiquetado) y se convierte en decisiones desviadas, hemos presentado los principios del RGPD que afectan al trabajo con datos (finalidad, minimización, conservación, derechos, seguridad) junto con la seudonimización y la anonimización, y hemos matizado el mito de "más datos siempre es mejor". Por último, hemos escrito un programa que lee un CSV con la biblioteca estándar y produce un informe de calidad: la primera herramienta que debería ejecutarse en cualquier proyecto de IA.

Con los datos ya sobre la mesa, la siguiente lección, Ética y Consideraciones en IA, aborda lo que ocurre cuando esos datos, con sus sesgos, alimentan decisiones que afectan a personas: qué principios éticos deben guiar a NovaMarket, qué problemas concretos (discriminación, privacidad, opacidad, responsabilidad, impacto laboral, desinformación, sostenibilidad) hay que prever, qué exige el marco regulatorio europeo y qué herramientas prácticas (checklist, evaluación de impacto, revisión humana, métricas de equidad) permiten pasar de las buenas intenciones a los hechos. Retomaremos allí el modelo de riesgo de devolución y el código postal para medir, con números, si un modelo trata igual a todos los grupos.

Fundamentos de Inteligencia Artificial (IA)

Módulo 1: Introducción a la Inteligencia Artificial

Módulo 2: Principios Básicos de la IA

Módulo 3: Algoritmos en IA

Módulo 4: Aprendizaje Automático (Machine Learning)

Módulo 5: Redes Neuronales y Deep Learning

Módulo 6: Lógica y Sistemas Expertos

Módulo 7: Herramientas y Lenguajes de Programación en IA

Módulo 8: Proyectos y Casos de Estudio

Módulo 9: Ejercicios y Prácticas

Módulo 10: Recursos Adicionales

© Copyright 2026. Todos los derechos reservados