Saltar a contenido

Proyectos — Módulo 01: FUNDAMENTOS

AI Master Academy · Módulo 01-FUNDAMENTOS · Julio 2026 Aquí demuestras (a ti y al mundo) que los fundamentos son tuyos. Dos entregables: uno técnico y uno de consultoría.


Índice

  1. Visión general y entregables
  2. MINI PROYECTO — Analizador de datasets universal
  3. Especificación completa
  4. Arquitectura
  5. Esqueleto de código con TODOs
  6. Código de referencia completo
  7. Criterios de aceptación
  8. Rúbrica de autoevaluación
  9. PROYECTO PROFESIONAL — Informe ejecutivo de viabilidad de IA
  10. Por qué este proyecto
  11. Instrucciones y plantilla completa
  12. Anexo técnico con Pandas
  13. Criterios de calidad
  14. Errores típicos
  15. Ejemplo resuelto: cafetería con delivery
  16. Navegación

Visión general y entregables

Proyecto Tipo Tiempo Entregable
A. Analizador de datasets universal Técnico (CLI Python) 4-6 h analizador.py + informe generado
B. Informe ejecutivo de viabilidad de IA Consultoría (Markdown) 6-10 h informe-viabilidad.md + anexo técnico

Nota

Haz los dos en este orden. El mini proyecto consolida Pandas y NumPy; el proyecto profesional consolida el criterio — la habilidad que de verdad diferencia a un ingeniero de IA de alguien que solo llama APIs.

Advertencia

No entregues nada que no hayas ejecutado de principio a fin. Un informe precioso generado por un script que casca con el segundo CSV que pruebas vale cero en el mundo real.


MINI PROYECTO — Analizador de datasets universal

La misión

En el Lab 4 analizaste UN dataset concreto con código a medida. Un profesional no reescribe ese código cada vez: construye una herramienta. Vas a crear analizador.py, un CLI que recibe la ruta de CUALQUIER CSV y genera un informe Markdown de diagnóstico automático.

# Así se usará tu herramienta:
python analizador.py datos/ventas.csv
# → genera: informe_ventas.md

Es el mismo tipo de utilidad que los equipos de datos llaman "data profiling" (existen versiones industriales como ydata-profiling; tú construirás la tuya para entender qué hacen por dentro).

Especificación completa

Entrada

  • Argumento 1 (obligatorio): ruta a un archivo CSV.
  • Argumento 2 (opcional): ruta del informe de salida. Por defecto: informe_<nombre-del-csv>.md.

Comportamiento requerido

Req Descripción
R1 Si no se pasa argumento, imprime el modo de uso y sale con código 1
R2 Si el archivo no existe o no es CSV legible, muestra error claro (sin traceback crudo) y sale con código 1
R3 El informe incluye dimensiones: nº de filas y columnas
R4 El informe incluye tabla de columnas: nombre, tipo, nº de nulos, % de nulos, nº de valores únicos
R5 El informe incluye nº de filas duplicadas exactas
R6 Para cada columna numérica: mínimo, máximo, media, mediana y desviación estándar
R7 Para cada columna categórica (texto): top 5 valores más frecuentes con su conteo
R8 Sección de advertencias automáticas (ver tabla siguiente)
R9 El informe se escribe en Markdown válido con encoding UTF-8
R10 El script termina imprimiendo la ruta del informe generado

Advertencias automáticas (R8)

Advertencia Regla de detección Por qué importa
Columna con exceso de nulos > 50% de valores nulos Probablemente inutilizable para modelar
Posible columna ID nº valores únicos == nº filas No aporta información predictiva; hay que excluirla
Columna constante 1 solo valor único Cero información; ruido en el dataset
Posible desbalanceo Columna categórica con ≤ 10 categorías donde la mayoritaria supera el 90% En clasificación, un modelo "tonto" acertaría 90% sin aprender nada
Dataset con duplicados ≥ 1 fila duplicada Infla métricas y sesga estadísticas

Consejo profesional

Las advertencias son la parte más valiosa del proyecto. Los números los da cualquier df.describe(); el juicio automático ("cuidado con esta columna, parece un ID") es lo que convierte datos en decisiones. Esa es la mentalidad que este máster quiere instalarte.

Arquitectura

flowchart TD
    A[CLI: python analizador.py ruta.csv] --> B{validar_argumentos}
    B -- ruta inválida --> Z[Mensaje de error claro + exit 1]
    B -- ok --> C[cargar_csv<br/>pd.read_csv con manejo de errores]
    C --> D[analizar_dimensiones]
    C --> E[analizar_columnas<br/>tipos, nulos, únicos]
    C --> F[analizar_numericas<br/>min, max, media, mediana, std]
    C --> G[analizar_categoricas<br/>top 5 valores]
    C --> H[detectar_advertencias<br/>nulos>50%, IDs, constantes,<br/>desbalanceo, duplicados]
    D --> I[generar_informe_markdown]
    E --> I
    F --> I
    G --> I
    H --> I
    I --> J[escribir archivo .md<br/>UTF-8]
    J --> K[print ruta del informe]

Nota

Cada caja del diagrama es UNA función con UNA responsabilidad. Esta separación (validar / cargar / analizar / renderizar / escribir) es el patrón que usarás en todos los proyectos del máster, y hace cada pieza testeable por separado.

Esqueleto de código con TODOs

Parte de este esqueleto. Rellena los TODO en orden; el programa debe ejecutar (aunque incompleto) después de cada TODO resuelto.

# analizador.py — Analizador universal de datasets CSV.
# Uso: python analizador.py <ruta.csv> [ruta_informe.md]

import sys                    # para leer argumentos de línea de comandos
from pathlib import Path      # manejo de rutas moderno y multiplataforma

import pandas as pd


def validar_argumentos(argv):
    """Valida los argumentos del CLI. Devuelve (ruta_csv, ruta_salida)."""
    # TODO 1: si len(argv) < 2, imprimir el modo de uso y sys.exit(1)
    # TODO 2: construir ruta_csv = Path(argv[1])
    # TODO 3: si no ruta_csv.exists(), imprimir error claro y sys.exit(1)
    # TODO 4: ruta_salida = argv[2] si existe; si no, f"informe_{ruta_csv.stem}.md"
    ...


def cargar_csv(ruta_csv):
    """Carga el CSV en un DataFrame con manejo de errores amable."""
    # TODO 5: envolver pd.read_csv en try/except
    #         capturar pd.errors.ParserError y UnicodeDecodeError
    #         → mensaje claro + sys.exit(1)
    ...


def analizar_columnas(df):
    """Devuelve una lista de dicts: nombre, tipo, nulos, %nulos, únicos."""
    # TODO 6: recorrer df.columns y por cada una calcular
    #         dtype, isna().sum(), % sobre len(df), nunique()
    ...


def analizar_numericas(df):
    """Estadísticas de las columnas numéricas."""
    # TODO 7: seleccionar con df.select_dtypes(include="number")
    #         y calcular min, max, mean, median, std por columna
    ...


def analizar_categoricas(df, top=5):
    """Top valores de las columnas de texto."""
    # TODO 8: seleccionar con df.select_dtypes(include="object")
    #         y usar .value_counts().head(top) por columna
    ...


def detectar_advertencias(df):
    """Aplica las 5 reglas de advertencia. Devuelve lista de strings."""
    # TODO 9: implementar las 5 reglas de la tabla de la especificación.
    #         Pista desbalanceo: vc = col.value_counts(normalize=True);
    #         si len(vc) <= 10 y vc.iloc[0] > 0.90 → advertencia.
    ...


def generar_informe(ruta_csv, df, columnas, numericas, categoricas, advertencias):
    """Compone el string Markdown completo del informe."""
    # TODO 10: construir el Markdown con f-strings (tablas incluidas).
    #          Secciones: título, dimensiones, columnas, duplicados,
    #          numéricas, categóricas, advertencias.
    ...


def main():
    ruta_csv, ruta_salida = validar_argumentos(sys.argv)
    df = cargar_csv(ruta_csv)
    # TODO 11: llamar a los analizadores, generar el informe,
    #          escribirlo con encoding="utf-8" e imprimir la ruta final
    ...


if __name__ == "__main__":
    main()

Advertencia

Intenta resolverlo TÚ antes de abrir la solución. El código de referencia está plegado a propósito: úsalo para compararte, no para copiarlo. Si lo copias, el único engañado eres tú (y tu próxima entrevista técnica).

Código de referencia completo

Ver solución de referencia comentada (ábrela solo tras intentarlo)
# analizador.py — Analizador universal de datasets CSV (solución de referencia).
# Uso: python analizador.py <ruta.csv> [ruta_informe.md]

import sys                    # acceso a los argumentos y a exit codes
from pathlib import Path      # rutas multiplataforma orientadas a objetos

import pandas as pd


def validar_argumentos(argv):
    """Valida los argumentos del CLI. Devuelve (ruta_csv, ruta_salida)."""
    # argv[0] es el nombre del script; el primer argumento real es argv[1]
    if len(argv) < 2:
        # Modo de uso: el mensaje más importante de cualquier CLI
        print("Uso: python analizador.py <ruta.csv> [ruta_informe.md]")
        sys.exit(1)                      # código 1 = terminó con error

    ruta_csv = Path(argv[1])             # convertimos el texto en objeto ruta
    if not ruta_csv.exists():
        # Error claro y accionable, sin traceback que asuste al usuario
        print(f"ERROR: no existe el archivo '{ruta_csv}'")
        sys.exit(1)

    # Salida: la indicada, o un nombre derivado del CSV (stem = nombre sin extensión)
    ruta_salida = Path(argv[2]) if len(argv) > 2 else Path(f"informe_{ruta_csv.stem}.md")
    return ruta_csv, ruta_salida


def cargar_csv(ruta_csv):
    """Carga el CSV en un DataFrame con manejo de errores amable."""
    try:
        # read_csv infiere tipos automáticamente; suficiente para perfilar
        return pd.read_csv(ruta_csv)
    except pd.errors.ParserError as e:
        # CSV corrupto o con formato raro (separadores inconsistentes...)
        print(f"ERROR: el archivo no parece un CSV válido: {e}")
        sys.exit(1)
    except UnicodeDecodeError:
        # Encoding no UTF-8: damos la pista de solución más común
        print("ERROR: problema de encoding. Prueba a guardar el CSV como UTF-8.")
        sys.exit(1)


def analizar_columnas(df):
    """Devuelve una lista de dicts: nombre, tipo, nulos, %nulos, únicos."""
    resultado = []
    for col in df.columns:                       # recorremos cada columna
        nulos = int(df[col].isna().sum())        # nº de valores nulos
        resultado.append({
            "nombre": col,                        # nombre de la columna
            "tipo": str(df[col].dtype),           # tipo inferido por pandas
            "nulos": nulos,                       # conteo absoluto de nulos
            "pct_nulos": 100 * nulos / len(df) if len(df) else 0,  # porcentaje
            "unicos": int(df[col].nunique()),     # nº de valores distintos
        })
    return resultado


def analizar_numericas(df):
    """Estadísticas de las columnas numéricas."""
    # select_dtypes filtra solo las columnas de tipo numérico
    num = df.select_dtypes(include="number")
    stats = {}
    for col in num.columns:
        s = num[col]                              # la Serie de esa columna
        stats[col] = {
            "min": s.min(),                       # valor mínimo
            "max": s.max(),                       # valor máximo
            "media": s.mean(),                    # media aritmética
            "mediana": s.median(),                # mediana (robusta a atípicos)
            "std": s.std(),                       # desviación estándar
        }
    return stats


def analizar_categoricas(df, top=5):
    """Top valores de las columnas de texto."""
    # include="object" selecciona las columnas de texto
    cat = df.select_dtypes(include="object")
    tops = {}
    for col in cat.columns:
        # value_counts cuenta frecuencias ordenadas; head(top) toma las mayores
        tops[col] = df[col].value_counts().head(top)
    return tops


def detectar_advertencias(df):
    """Aplica las 5 reglas de advertencia. Devuelve lista de strings."""
    advertencias = []
    n = len(df)                                   # nº total de filas

    # Regla 5: duplicados exactos en el dataset
    dups = int(df.duplicated().sum())
    if dups > 0:
        advertencias.append(f"⚠ Hay {dups} filas duplicadas exactas: revisa el origen de los datos.")

    for col in df.columns:
        pct_nulos = df[col].isna().mean()         # .mean() de booleanos = proporción
        unicos = df[col].nunique()

        # Regla 1: más de la mitad de la columna es nula
        if pct_nulos > 0.5:
            advertencias.append(
                f"⚠ La columna '{col}' tiene {pct_nulos:.0%} de nulos: probablemente inutilizable.")

        # Regla 2: tantos valores únicos como filas → huele a identificador
        if n > 0 and unicos == n:
            advertencias.append(
                f"⚠ La columna '{col}' parece un ID (todos los valores son únicos): exclúyela del análisis.")

        # Regla 3: un solo valor en toda la columna → no aporta nada
        if unicos == 1:
            advertencias.append(
                f"⚠ La columna '{col}' es constante (un único valor): no aporta información.")

        # Regla 4: desbalanceo en categóricas de pocas clases
        if df[col].dtype == "object" and 1 < unicos <= 10:
            vc = df[col].value_counts(normalize=True)   # proporciones por categoría
            if vc.iloc[0] > 0.90:                        # ¿la mayoritaria pasa del 90%?
                advertencias.append(
                    f"⚠ La columna '{col}' está desbalanceada: '{vc.index[0]}' es el {vc.iloc[0]:.0%} de los casos.")

    return advertencias


def generar_informe(ruta_csv, df, columnas, numericas, categoricas, advertencias):
    """Compone el string Markdown completo del informe."""
    partes = []                                    # acumulamos secciones en una lista
    partes.append(f"# Informe de diagnóstico: `{ruta_csv.name}`\n")
    partes.append(f"**Dimensiones:** {df.shape[0]} filas × {df.shape[1]} columnas\n")
    partes.append(f"**Filas duplicadas:** {int(df.duplicated().sum())}\n")

    # --- Tabla de columnas ---
    partes.append("\n## Columnas\n")
    partes.append("| Columna | Tipo | Nulos | % Nulos | Únicos |")
    partes.append("|---------|------|-------|---------|--------|")
    for c in columnas:
        partes.append(
            f"| {c['nombre']} | {c['tipo']} | {c['nulos']} | {c['pct_nulos']:.1f}% | {c['unicos']} |")

    # --- Estadísticas numéricas ---
    if numericas:                                  # solo si hay columnas numéricas
        partes.append("\n## Estadísticas numéricas\n")
        partes.append("| Columna | Mín | Máx | Media | Mediana | Desv. est. |")
        partes.append("|---------|-----|-----|-------|---------|------------|")
        for col, s in numericas.items():
            partes.append(
                f"| {col} | {s['min']:.2f} | {s['max']:.2f} | {s['media']:.2f} "
                f"| {s['mediana']:.2f} | {s['std']:.2f} |")

    # --- Top de categóricas ---
    if categoricas:
        partes.append("\n## Valores más frecuentes (categóricas)\n")
        for col, vc in categoricas.items():
            partes.append(f"\n### {col}\n")
            partes.append("| Valor | Frecuencia |")
            partes.append("|-------|------------|")
            for valor, cuenta in vc.items():       # cada par valor→conteo del top 5
                partes.append(f"| {valor} | {cuenta} |")

    # --- Advertencias ---
    partes.append("\n## Advertencias automáticas\n")
    if advertencias:
        for a in advertencias:
            partes.append(f"- {a}")
    else:
        partes.append("- ✅ Sin advertencias: el dataset pasa las comprobaciones básicas.")

    # Unimos todas las líneas con saltos de línea
    return "\n".join(partes) + "\n"


def main():
    # 1. Validar entrada
    ruta_csv, ruta_salida = validar_argumentos(sys.argv)
    # 2. Cargar datos
    df = cargar_csv(ruta_csv)
    # 3. Analizar (cada función hace UNA cosa)
    columnas = analizar_columnas(df)
    numericas = analizar_numericas(df)
    categoricas = analizar_categoricas(df)
    advertencias = detectar_advertencias(df)
    # 4. Renderizar el informe
    informe = generar_informe(ruta_csv, df, columnas, numericas, categoricas, advertencias)
    # 5. Escribir a disco (UTF-8 para tildes y emojis)
    ruta_salida.write_text(informe, encoding="utf-8")
    # 6. Confirmar al usuario dónde quedó su informe
    print(f"✅ Informe generado: {ruta_salida}")


if __name__ == "__main__":
    main()

Cómo probarlo

Pruébalo como mínimo con tres CSVs distintos:

# 1. El CSV de ventas del Lab 4 (con suciedad conocida)
python analizador.py datos/ventas.csv

# 2. Un CSV que dispare advertencias: créalo con una columna ID,
#    una constante y una con >50% nulos
python analizador.py datos/trampas.csv

# 3. Un CSV cualquiera descargado de internet (datos abiertos de tu ciudad,
#    Kaggle, etc.) — la prueba de fuego de la palabra "universal"
python analizador.py datos/desconocido.csv

Salida esperada en consola:

✅ Informe generado: informe_ventas.md

Criterios de aceptación (checklist)

  • [ ] python analizador.py sin argumentos imprime el modo de uso y sale con código 1 (verifícalo con echo $? o $LASTEXITCODE)
  • [ ] Con una ruta inexistente muestra un error claro SIN traceback
  • [ ] El informe incluye dimensiones, tabla de columnas, duplicados, numéricas y categóricas
  • [ ] Las 5 advertencias automáticas se disparan cuando toca (pruébalo con un CSV trampa)
  • [ ] Con un dataset limpio, la sección de advertencias dice explícitamente que no hay ninguna
  • [ ] Funciona con al menos 3 CSVs diferentes que no compartan columnas
  • [ ] El Markdown generado se renderiza correctamente (ábrelo en VS Code con Ctrl+Shift+V)
  • [ ] Tildes y símbolos se ven bien (encoding UTF-8)
  • [ ] El código está organizado en funciones de una responsabilidad, como la arquitectura
  • [ ] El proyecto está en git con commits descriptivos

Rúbrica de autoevaluación

Dimensión Aprendiz (1) Competente (2) Profesional (3)
Robustez Funciona solo con mi CSV de prueba Maneja archivo inexistente y CSV corrupto Además maneja CSV vacío, sin columnas numéricas, o de 1 columna
Advertencias 1-2 reglas implementadas Las 5 reglas funcionan Las 5 + alguna regla propia justificada
Código Todo en main(), difícil de leer Funciones separadas según la arquitectura Funciones puras, nombres claros, comentarios donde aportan
Informe Texto plano con datos Markdown con tablas correctas Markdown pulido que un no-técnico entiende de un vistazo
Git 1 commit final "subo todo" Commits por funcionalidad Commits atómicos con mensajes en imperativo

Puntuación: 5-7 = repasa los labs y refactoriza · 8-11 = objetivo cumplido · 12-15 = listo para el módulo 02 con nota.

Consejo profesional

Guarda este script. En el módulo 02 (Machine Learning) lo usarás de verdad: perfilar el dataset ANTES de entrenar es el paso 0 de cualquier proyecto de ML, y tú ya tendrás tu propia herramienta.


PROYECTO PROFESIONAL — Informe ejecutivo de viabilidad de IA para una empresa real

Por qué este proyecto

Puede sorprenderte que el proyecto estrella de un módulo técnico sea... un documento. La razón:

Esto es EXACTAMENTE lo que hace un consultor de IA. Antes de escribir una línea de código, alguien tiene que responder: ¿dónde aporta valor la IA en ESTE negocio? ¿Con qué datos? ¿Con qué técnica — reglas, ML clásico, un LLM, RAG, un agente? ¿Qué riesgos hay? Las empresas pagan miles de euros por este análisis, y la mayoría de proyectos de IA que fracasan, fracasan aquí: no en el código, sino en elegir mal el problema o ignorar el estado de los datos.

Este proyecto entrena tres músculos que ningún tutorial de código entrena:

  1. Mapear técnica → problema: el capítulo "cómo aprende una máquina" y el de "ecosistema" te dieron el catálogo; aquí lo aplicas a un negocio real.
  2. Pensar en datos primero: sin datos (suficientes, accesibles, de calidad) no hay IA. Tu Lab 4 y el analizador te enseñaron a mirar datos con lupa; aquí evalúas si los datos de una empresa dan para algo.
  3. Comunicar a no-técnicos: un informe que un gerente entiende y con el que puede decidir. En los módulos 20 (Consultoría de IA) y 22 (Proyecto final) esta pieza será tu carta de presentación — de hecho, este informe es la semilla directa de aquellos entregables.

Nota

Elige una empresa que CONOZCAS de verdad: donde trabajas, el negocio de un familiar, tu gimnasio, la clínica dental de tu barrio. El conocimiento del negocio es el 50% del valor del informe; inventarte una multinacional ficticia produce informes genéricos que no enseñan nada.

Instrucciones paso a paso

  1. Elige la empresa (criterio: puedes describir su operación diaria sin inventar).
  2. Investiga 1-2 horas: ¿qué procesos son repetitivos? ¿dónde se pierde tiempo o dinero? ¿qué datos genera la operación (tickets, reservas, emails, inventario)?
  3. Identifica 3 oportunidades de IA de distinto tipo si es posible (no tres chatbots).
  4. Rellena la plantilla de abajo, sección por sección.
  5. Construye el anexo técnico con Pandas (ver más abajo).
  6. Revisa contra los criterios de calidad y la lista de errores típicos.

Plantilla completa del informe

Copia esta plantilla en informe-viabilidad.md y sustituye las instrucciones en cursiva por tu contenido:

# Informe de viabilidad de IA — [NOMBRE DE LA EMPRESA]

**Autor:** [tu nombre] · **Fecha:** [mes año] · **Versión:** 1.0

## 1. Resumen ejecutivo

*(Escríbelo AL FINAL, aunque vaya primero: 5-8 líneas con la conclusión,
la oportunidad recomendada como quick win y la inversión aproximada de
tiempo/esfuerzo. Un directivo que solo lea esto debe poder decidir.)*

## 2. Contexto de negocio

- **Actividad:** *(qué vende/hace la empresa, a quién)*
- **Tamaño:** *(empleados, locales, volumen aproximado de operaciones)*
- **Procesos clave:** *(los 3-5 procesos que sostienen el negocio)*
- **Dolores actuales:** *(qué consume tiempo, dónde se pierde dinero,
  qué quejas se repiten — sé concreto: "responder 40 WhatsApps/día
  sobre horarios" vale; "mejorar la eficiencia" no vale)*
- **Datos que ya genera la operación:** *(TPV, reservas, emails, Excel
  de inventario, historial de pedidos... aunque estén desordenados)*

## 3. Oportunidades de IA identificadas

### Oportunidad 1: [nombre corto y claro]

| Aspecto | Detalle |
|---------|---------|
| Problema que resuelve | *(el dolor concreto, en lenguaje de negocio)* |
| Tipo de técnica | *(reglas / ML clásico / LLM / RAG / agente — y POR QUÉ esa y no otra)* |
| Datos necesarios | *(qué datos harían falta, cuántos, con qué calidad)* |
| Datos disponibles | *(qué hay HOY realmente, en qué formato, con qué huecos)* |
| Riesgos y limitaciones | *(errores del sistema y su coste, privacidad, sesgo, dependencia de proveedor)* |
| Complejidad estimada | *(Baja / Media / Alta + justificación en 1-2 líneas)* |
| Valor esperado | *(horas ahorradas, ventas incrementadas, errores evitados — con números aunque sean estimaciones)* |

### Oportunidad 2: [nombre]

*(misma tabla)*

### Oportunidad 3: [nombre]

*(misma tabla)*

## 4. Quick win recomendado

*(¿Cuál de las tres empezarías y por qué: mejor ratio valor/complejidad?
Qué se podría tener funcionando en 4-6 semanas. Qué NO incluye esta
primera versión — acotar es de profesionales.)*

## 5. Roadmap de adopción

```mermaid
gantt
    title Roadmap de adopción de IA — [EMPRESA]
    dateFormat  YYYY-MM
    section Fase 1: Fundamentos
    Digitalizar y ordenar datos       :2026-08, 2M
    Quick win (Oportunidad X)         :2026-09, 2M
    section Fase 2: Expansión
    Medir resultados del quick win    :2026-11, 1M
    Oportunidad Y                     :2026-12, 3M
    section Fase 3: Madurez
    Oportunidad Z                     :2027-03, 3M

(Ajusta fases y fechas a tu caso; la fase 1 casi siempre incluye ordenar los datos ANTES de cualquier IA.)

6. Riesgos transversales y consideraciones éticas

(Privacidad de datos de clientes (RGPD), qué pasa si el sistema se equivoca, dependencia de un proveedor, aceptación por parte del equipo.)

7. Anexo técnico: análisis de datos de apoyo

(Resumen de tu análisis en Pandas: qué datos usaste — públicos o sintéticos —, 2-3 hallazgos con números, y cómo apoyan el caso de negocio. Enlaza el script y el informe generado.)

## El anexo técnico: análisis en Pandas

El informe no puede ser solo opinión: debe apoyarse en al menos **un análisis de datos real**, hecho por ti con Pandas. Dos vías válidas:

| Vía | Cuándo usarla | Ejemplo |
|-----|----------------|---------|
| **Dato público** | Existe un dataset abierto relevante para el sector | Datos de turismo de tu ciudad para un hotel; datos abiertos de tráfico para una empresa de reparto |
| **Dato sintético** | No hay dato público razonable | Generas 3-6 meses de ventas sintéticas plausibles (como en el Lab 3) y demuestras QUÉ se podría aprender de los datos reales si la empresa los recogiera |

Requisitos mínimos del anexo:

- Un script `anexo_analisis.py` reproducible (con semilla fija si hay datos sintéticos).
- Al menos: una limpieza documentada, un `groupby` con métrica de negocio y una tendencia temporal.
- 2-3 conclusiones numéricas conectadas EXPLÍCITAMENTE con alguna oportunidad del informe ("los martes la demanda cae un 40% → la oportunidad 2 de predicción de demanda permitiría ajustar personal").
- Pasa tu propio `analizador.py` (Mini Proyecto) al dataset y adjunta el informe de diagnóstico. Los dos proyectos del módulo se encajan aquí.

## Criterios de calidad

| Criterio | Se cumple cuando... |
|----------|---------------------|
| Especificidad | Cada oportunidad menciona procesos, datos y cifras de ESA empresa (borra el nombre de la empresa: si el informe sigue teniendo sentido para cualquier otra, es demasiado genérico) |
| Técnica justificada | Cada oportunidad explica por qué ESA técnica y no una más simple ("bastan reglas porque los casos son 5 y enumerables" es una justificación excelente) |
| Honestidad sobre datos | El informe distingue datos que EXISTEN de datos que habría que empezar a recoger |
| Riesgos reales | Al menos un riesgo por oportunidad que NO sea genérico ("la IA puede fallar" no vale; "un precio mal calculado se publica a 3.000 clientes" sí) |
| Legibilidad ejecutiva | Una persona sin formación técnica entiende el resumen y puede decidir |
| Anexo conectado | Las conclusiones del análisis se citan en el cuerpo del informe, no viven aisladas |

## Errores típicos (y cómo evitarlos)

!!! warning "Advertencia"
    Estos errores aparecen en el 80% de los primeros informes. Revísalos ANTES de entregar.

| Error típico | Cómo se ve | Antídoto |
|---------------|------------|----------|
| **Prometer IA donde bastan reglas** | "Un modelo de ML para aplicar el descuento del 10% a mayores de 65" | Pregúntate: ¿puedo escribir la lógica en un if? Entonces son reglas. La IA se gana su complejidad solo cuando las reglas no escalan |
| **Ignorar la calidad de los datos** | "Entrenaremos con el histórico de ventas" (que vive en 14 Excels incompatibles con años de huecos) | Sección de datos disponibles con honestidad brutal; casi siempre la fase 1 del roadmap es ordenar datos |
| **Tres chatbots** | Las 3 oportunidades son variantes de "un chatbot que..." | Fuerza diversidad: al menos una oportunidad de predicción/análisis y una de automatización de proceso |
| **Cifras de humo** | "Aumentará las ventas un 30%" sin origen | Toda cifra lleva su origen: dato del anexo, benchmark citado o estimación marcada como tal |
| **Roadmap fantasía** | "Mes 1: implantar agente autónomo de compras" | El quick win va primero, y es humilde; la madurez llega en fases |
| **Olvidar el coste del error** | Se propone IA generativa cara al público sin plan para respuestas incorrectas | Por cada oportunidad: ¿qué pasa cuando falle? ¿quién revisa? |
| **Informe para impresionar, no para decidir** | 20 páginas de historia de la IA | Todo lo que no ayude a decidir, fuera. 6-10 páginas es el objetivo |

## Ejemplo resuelto (ABREVIADO): cafetería "La Taza Feliz"

*Versión comprimida para calibrar el nivel esperado. Tu informe debe desarrollar cada sección 3-4 veces más.*

### Contexto (resumen)

Cafetería de barrio en Valencia con delivery propio y por plataformas. 6 empleados, ~180 pedidos/día (60% local, 40% delivery). Datos disponibles: TPV con 2 años de tickets (exportable a CSV), historial de pedidos de las plataformas de delivery, y un Excel de compras a proveedores. Dolores: (1) tiran ~8% de la bollería cada día o se quedan cortos los findes, (2) el teléfono se satura con preguntas repetidas en hora punta, (3) las promociones se deciden "a ojo".

### Las 3 oportunidades (resumen)

| # | Oportunidad | Técnica | Por qué esa técnica | Complejidad |
|---|-------------|---------|---------------------|-------------|
| 1 | Predicción de demanda diaria de bollería | **ML clásico** (regresión con día de semana, festivos, clima) | Es un problema numérico con histórico de 2 años en el TPV; no hace falta ningún LLM | Media |
| 2 | Respuesta automática de preguntas frecuentes (horarios, alérgenos, estado del pedido) | **Reglas + RAG ligero** sobre la carta y FAQs | El 80% son 10 preguntas: reglas. El resto ("¿el brownie lleva trazas de nuez?") lo cubre RAG sobre la carta; un LLM sin anclar inventaría alérgenos → riesgo inaceptable | Baja-Media |
| 3 | Promociones personalizadas por segmento de cliente | **ML clásico** (segmentación por frecuencia y ticket sobre datos del TPV) | Antes de "IA que redacta ofertas" hay que SABER a quién ofertar; primero segmentación, la generación de textos puede venir después | Media |

### Quick win recomendado

**Oportunidad 2 (FAQs), versión solo-reglas, en 4 semanas:** un autorespondedor de WhatsApp con las 10 preguntas top identificadas en el histórico. Sin ML, sin coste de API, riesgo casi nulo, y libera ~1 hora/día de personal en hora punta. La versión RAG llega en fase 2, cuando la carta esté digitalizada y estructurada.

### Fragmento del roadmap

```mermaid
gantt
    title Roadmap IA — La Taza Feliz
    dateFormat YYYY-MM
    section Fase 1
    Exportar y ordenar datos del TPV :2026-08, 1M
    Quick win FAQs con reglas :2026-08, 1M
    section Fase 2
    Predicción de demanda de bollería :2026-10, 2M
    FAQs v2 con RAG sobre la carta :2026-11, 2M
    section Fase 3
    Segmentación y promociones :2027-01, 2M

Fragmento del anexo técnico

Con un CSV sintético de 6 meses de ventas de bollería (generado con semilla fija, patrón semanal + ruido, como en el Lab 3):

  • El desperdicio simulado con la política actual ("producir siempre 60 unidades") es del 9,1% entre semana, y los sábados faltan de media 14 unidades (ventas perdidas).
  • Una regla trivial aprendida de los datos ("producir la media móvil de los últimos 4 mismos-días-de-semana") ya reduce el desperdicio simulado al 3,8% — lo que sugiere que un modelo de regresión con clima y festivos (Oportunidad 1) tiene margen real.
  • Conexión con el negocio: a ~1,20 € de coste por pieza, el ahorro estimado ronda los 190 €/mes — modesto pero positivo, y el mismo modelo aplica al resto de frescos.

Consejo profesional

Fíjate en el patrón del ejemplo: en la oportunidad 2 el consultor rebajó la solución (de "LLM conversacional" a "reglas primero, RAG después"). Recomendar MENOS tecnología de la que el cliente esperaba, con argumentos, es la señal más clara de un buen consultor de IA — y créeme: los clientes lo notan y lo agradecen.

Qué NO incluye este ejemplo (y tu informe SÍ debe incluir)

  • Sección completa de riesgos por oportunidad (aquí solo se insinúa el de alérgenos).
  • Estimaciones de valor con su origen detallado.
  • El análisis de Pandas completo con código reproducible.
  • Resumen ejecutivo redactado para un no-técnico.

Entrega final del módulo

  • [ ] analizador.py + al menos un informe generado de un CSV real
  • [ ] informe-viabilidad.md completo siguiendo la plantilla
  • [ ] anexo_analisis.py reproducible + su salida
  • [ ] Todo en un repositorio git con README breve que explique cómo ejecutar cada pieza
  • [ ] Autoevaluación con la rúbrica (proyecto A) y los criterios de calidad (proyecto B)

Nota

Conserva el informe de viabilidad. En el módulo 20 (Consultoría) lo retomarás con todo lo aprendido para convertirlo en una propuesta comercial completa, y en el módulo 22 podrá ser la base de tu proyecto final. Lo que hoy es un ejercicio, en unos meses puede ser tu primer cliente.


Anterior Módulo Siguiente
Laboratorios 01-FUNDAMENTOS Módulo 02: Machine Learning