D
Datos y automatizacion M12 intermedio 12 min

Capitulo 02

Python para Analisis y Automatizacion

El gap especifico que separa a un Analyst que sabe Python de uno que lo usa para automatizar de verdad

Automatizacion de reportes recurrentes, manejo de series temporales con pandas, testing de scripts de datos y como escribir codigo reutilizable en vez de notebooks desechables.

Python aparecio en el 52% de las ofertas

Y cada vez con mas frecuencia como requisito, no como “deseable”, incluso en roles de Analyst puro. La diferencia no es saber la sintaxis de Python — es saber usarlo para dejar de hacer a mano lo que un script puede hacer solo.

Si ya conoces pandas y numpy (temas cubiertos en profundidad en el curso de Data Science I), este capitulo se enfoca en lo que el mercado realmente pide de un Analyst que usa Python: automatizacion, no ciencia de datos.

2.1 Automatizar reportes recurrentes

El patron mas pedido: leer varias fuentes (CSV, Excel, una base de datos), consolidar, y exportar un reporte formateado — sin tocarlo a mano cada semana.

python reporte_semanal.py
import pandas as pd
from pathlib import Path
from openpyxl.styles import Font

def cargar_ventas(carpeta: str) -> pd.DataFrame:
    """Lee todos los CSV de una carpeta y los concatena en un solo DataFrame."""
    archivos = Path(carpeta).glob("*.csv")
    dfs = [pd.read_csv(f, parse_dates=["fecha"]) for f in archivos]
    return pd.concat(dfs, ignore_index=True)

def generar_reporte(df: pd.DataFrame, salida: str) -> None:
    resumen = (
        df.groupby("region", as_index=False)
          .agg(total_ventas=("monto", "sum"), transacciones=("monto", "count"))
          .sort_values("total_ventas", ascending=False)
    )
    with pd.ExcelWriter(salida, engine="openpyxl") as writer:
        resumen.to_excel(writer, index=False, sheet_name="Resumen")
        ws = writer.sheets["Resumen"]
        for cell in ws[1]:
            cell.font = Font(bold=True)

if __name__ == "__main__":
    ventas = cargar_ventas("data/ventas_semanales")
    generar_reporte(ventas, "reporte_semanal.xlsx")
    print(f"Reporte generado con {len(ventas)} filas procesadas.")
La diferencia clave

Esto no es “un notebook con celdas”. Es un script con funciones nombradas, que otra persona (o tú en 3 meses) puede leer, testear y correr con un solo comando: python reporte_semanal.py. Esa es la diferencia entre “sabe Python” y “automatiza con Python”.

Caso real: consolidar reportes de multiples sucursales

Un escenario tipico en retail (Falabella, Crossing Hurdles en la muestra de mercado): cada sucursal sube su CSV de ventas a una carpeta compartida cada viernes. Antes de automatizarlo, alguien del equipo abria cada archivo a mano en Excel y copiaba/pegaba en un consolidado — un proceso de 2 horas propenso a errores. El script de este capitulo reduce eso a segundos y, al estar versionado en Git, cualquiera del equipo puede revisar o modificar la logica sin depender de la persona que “sabe donde esta el Excel”.

1. Hardcodear rutas de archivos especificas de una maquina
✗ pd.read_csv("C:/Users/denny/Desktop/ventas.csv") -- falla en cualquier otra maquina o servidor
✓ Usar rutas relativas o parametros (Path(carpeta) / "ventas.csv"), y pasar la carpeta como argumento del script.
2. No manejar el caso de un archivo con formato inesperado
✗ Asumir que todos los CSV de todas las sucursales tienen exactamente las mismas columnas, sin validar.
✓ Validar columnas esperadas antes de concatenar (o envolver la lectura en un try/except que loguee y salte el archivo problematico sin tumbar todo el proceso).

2.2 Series temporales con pandas

resample (Pandas)

M12

Metodo que cambia la frecuencia de una serie temporal (por ejemplo, de datos diarios a mensuales), aplicando una funcion de agregacion en el proceso. Requiere un DatetimeIndex.

Ej: df.set_index('fecha').resample('M')['monto'].sum()

#python #pandas
python series_temporales.py
import pandas as pd

df = pd.read_csv("ventas.csv", parse_dates=["fecha"])
df = df.set_index("fecha")

# Ventas totales por mes
ventas_mensuales = df["monto"].resample("M").sum()

# Promedio movil de 7 dias (suaviza ruido diario)
promedio_movil = df["monto"].resample("D").sum().rolling(window=7).mean()

# Variacion porcentual mes a mes
variacion = ventas_mensuales.pct_change() * 100
Por que resample y no agrupar manualmente por mes

La alternativa naive es extraer año y mes con .dt.year/.dt.month y agrupar con groupby. Funciona, pero resample entiende la frecuencia calendario (meses de distinta duracion, semanas que empiezan lunes vs domingo, trimestres fiscales) y rellena huecos automaticamente si un periodo no tiene datos — algo que un groupby manual no hace, y que produce reportes con periodos “faltantes” silenciosamente saltados.

Caso real: deteccion de caida de ventas

Un Analyst que automatiza el promedio movil de 7 dias sobre ventas diarias puede detectar una caida sostenida (no solo un mal dia aislado) antes de que aparezca en el reporte mensual — el tipo de alerta temprana que un dashboard “solo con totales mensuales” no puede dar.

1. Llamar resample() sin un DatetimeIndex
✗ df.resample('M') sobre un DataFrame cuyo indice es un entero comun -- lanza error o da resultados sin sentido.
✓ df.set_index('fecha').resample('M') -- primero establecer la columna de fecha como indice.

2.3 Testing de scripts de datos con pytest

Un script que genera un reporte que alguien mas va a leer merece, como minimo, un test que verifique que la logica de negocio no se rompio silenciosamente.

python test_reporte.py
import pandas as pd
from reporte_semanal import generar_reporte

def test_resumen_suma_correctamente(tmp_path):
    df = pd.DataFrame({
        "region": ["Norte", "Norte", "Sur"],
        "monto": [100, 200, 50],
    })
    salida = tmp_path / "test.xlsx"
    generar_reporte(df, str(salida))

    resultado = pd.read_excel(salida)
    total_norte = resultado.loc[resultado["region"] == "Norte", "total_ventas"].iloc[0]
    assert total_norte == 300
Trampa comun

Testear el DataFrame en memoria es facil; testear que el ARCHIVO exportado tiene los datos correctos (como en el ejemplo) es lo que realmente da confianza de que el reporte final es correcto — no solo la logica intermedia.

Caso real: por que 'funciona en mi maquina' no alcanza

Un script de reporte que un Analyst corre y verifica visualmente cada semana “parece funcionar” hasta que alguien cambia una columna en la fuente de datos y el reporte sigue corriendo, pero con un total mal calculado silenciosamente. Un test que verifica el calculo esperado sobre datos conocidos hubiera detectado el cambio de inmediato, en vez de que lo note un gerente semanas despues comparando contra otro reporte.

2.4 Codigo reutilizable, no scripts unicos

Cuando una oferta dice “Python como requisito” para un Analyst, esto es lo que estan evaluando: funciones con un proposito claro, parametros en vez de valores hardcodeados, y separacion entre “logica” y “ejecucion” (el bloque if __name__ == "__main__":).

2.5 Recursos

Articulo: Pandas Docs: Time series / date functionality (documentacion oficial)
Herramienta: pytest.org — Getting Started (guia oficial de testing en Python)
Articulo: openpyxl documentation (para exportar Excel formateado desde Python)

2.6 Preguntas de entrevista

Q: ¿Por que preferirias un script en vez de un notebook de Jupyter para un reporte que corre cada semana?

Un script se puede versionar en Git, testear con pytest, programar con un scheduler (cron, Airflow), y ejecutar sin intervencion manual. Un notebook es excelente para explorar datos, pero mal candidato para produccion: el orden de ejecucion de celdas no esta garantizado y es dificil de automatizar sin herramientas adicionales.

🪤 Decir que 'los notebooks son malos' en general — son la herramienta correcta para exploracion, solo no para automatizacion recurrente.
Practica: automatiza un reporte real intermedio
  1. Elige un reporte que hagas (o harias) manualmente cada semana en Excel.
  2. Escribi un script en Python que lo genere automaticamente desde uno o mas archivos fuente.
  3. Agrega al menos un test con pytest que valide un calculo clave del reporte.
  4. Documenta en un README como correrlo con un solo comando.