DIPLOMADO EN ESTRATEGIAS DE DATOS
CAPÍTULO 2: PANDAS PRO
MÓDULO 1: PYTHON CORE

Optimización del Dataset NYC-Train-Trip

20 Retos para dominar la memoria, vectorización y agregaciones avanzadas.

Fase 1: Diagnóstico

1. Inspección Profunda

df.info() miente. Pandas subestima el peso de los objetos. El reto es descubrir la verdad.

Reto: Carga train.csv. Compara el uso de RAM reportado por defecto vs memory_usage='deep'.
df.info(memory_usage='deep')

Fase 1: Diagnóstico

2. Downcasting Numérico

¿Por qué usar 64 bits para contar hasta 6 pasajeros? int8 es suficiente.

Reto: Convierte passenger_count a int8 usando pd.to_numeric.
pd.to_numeric(df['col'], downcast='integer')
graph TD A[Int64: 8 Bytes por fila] -->|Downcast| B(Análisis de Rango); B --> C{¿Cabe en 8 bits?}; C -->|Sí| D[Int8: 1 Byte por fila]; C -->|No| E[Int16/32]; D --> F[Ahorro: 87.5% RAM]; style D fill:#DA291C,color:white style F fill:#FFCC00,color:black

Fase 1: Diagnóstico

3. Categoricals

Los strings repetitivos consumen gigabytes. Las categorías guardan índices.

Reto: Optimiza store_and_fwd_flag ('Y'/'N') convirtiéndola a tipo categoría.
df['flag'] = df['flag'].astype('category')

Fase 2: Vectorización

4. Parsing Explícito

Dejar que Pandas "adivine" el formato fecha por fecha es lento. Sé explícito.

Reto: Mide la velocidad de to_datetime con y sin format='%Y-%m-%d...'.
pd.to_datetime(col, format='%Y-...')

Fase 2: Vectorización

5. Accessors (.dt)

Extrae componentes de fecha en C, sin loops de Python.

Reto: Crea hour y day_name. Encuentra la hora pico de NYC.
df['hour'] = df['datetime'].dt.hour
graph LR A[Columna Datetime] --> B((.dt Accessor)); B --> C[Array de Horas]; B --> D[Array de Meses]; B --> E[Días de Semana]; style B fill:#003366,color:white,stroke-width:4px,stroke:#FFCC00

Fase 2: Vectorización

6. Lógica Vectorizada

apply con if/else es un crimen en Big Data. Usa NumPy.

Reto: Etiqueta "Largo" (>3600s) o "Corto" usando np.where.
np.where(condicion, 'Valor Si', 'Valor No')
flowchart TB subgraph Lento A[Fila 1] --> B{If > 3600}; C[Fila 2] --> B; D[Fila N] --> B; end subgraph Vectorizado E[Array Completo Duración] --> F{{np.where}}; F --> G[Array Completo Resultado]; end style F fill:#DA291C,color:white

Fase 2: Vectorización

7. Matemáticas Geoespaciales

Trigonometría sobre arrays enteros para calcular distancias reales.

Reto: Implementa la fórmula Haversine con np.sin y np.cos para obtener Km.
a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)

c = 2 ⋅ atan2( √a, √(1−a) )

d = R ⋅ c

Fase 3: Código Elegante

8. Filtrado con .query()

Sintaxis tipo SQL, más limpia que los corchetes anidados.

Reto: Filtra: Pasajeros > 1 Y Distancia entre 0 y 100km en una línea.
df.query('passenger > 1 and 0 < dist < 100')
graph TD A[DataFrame Bruto] --> B(Query Parser); B --> C{Evalua String}; C --> D[DataFrame Filtrado]; style B fill:#FFCC00,stroke:#333

Fase 3: Código Elegante

9. Creación (.assign)

Crea columnas al vuelo sin romper la cadena de métodos.

Reto: Crea velocidad_kph y ordena descendentemente en un solo bloque.
.assign(vel = lambda x: x.dist / x.time)
.sort_values('vel')

Fase 3: Código Elegante

10. Outliers (.clip)

No borres datos, "tópalos" a límites lógicos.

Reto: Limita la duración entre 60s y 7200s usando clip.
.clip(lower=60, upper=7200)

Fase 3: Código Elegante

11. Funciones Propias (.pipe)

Inyecta tus propias funciones dentro de una cadena de Pandas.

Reto: Crea def etiqueta_trafico(df) y úsala al final de tu cadena.
df.query(...).assign(...).pipe(mi_funcion)
graph LR A[Inicio Cadena] --> B(.query); B --> C(.assign); C --> D((.pipe)); D -- Pasa DF --> E[Función Custom]; E -- Retorna DF --> F[Fin Cadena]; style D fill:#DA291C,color:white

Fase 4: Agregaciones

12. Named Aggregation

Control total sobre los nombres de columnas resultantes.

Reto: Agrupa por vendor y calcula mean_duration y total_km.
agg(nueva_col=('col_orig', 'func'))
Vendor 1
Stats
Vendor 2
Stats

Fase 4: Agregaciones

13. La Magia de .transform

Agrega estadísticas del grupo a cada fila original (Window Function).

Reto: Columna avg_duration_by_hour. Cada fila sabe el promedio de su hora.
graph TD A[100 Filas Originales] --> B{Groupby}; B --> C[Calcula Media - Reduce a 24 filas]; C --> D[Transform Broadcast]; D --> E[100 Filas con valor promedio pegado]; style D fill:#003366,color:white

Fase 4: Agregaciones

14. Filtrado de Grupos

Elimina grupos enteros que no cumplan una condición estadística.

Reto: Mantén solo las horas del día que tengan > 10,000 viajes totales.
groupby('hour').filter(lambda x: len(x) > 10k)

Fase 4: Agregaciones

15. Binning (qcut)

Convierte variable continua en discreta por cuantiles.

Reto: Divide distancia en 4 cuartiles: "Muy Corto" a "Muy Largo".
pd.qcut(df['dist'], 4, labels=[...])
graph LR A[Datos Continuos] --> B{Qcut=4}; B --> C[0-25%
Muy Corto]; B --> D[25-50%
Corto]; B --> E[50-75%
Largo]; B --> F[75-100%
Muy Largo]; style B fill:#DA291C,color:white

Fase 5: Series Temporales

16. Resample()

El groupby superpoderoso para índices de tiempo.

Reto: Conteo total de viajes por día ('D'). ¿Qué día es el más bajo?
df.set_index('ts').resample('D').size()

Fase 5: Series Temporales

17. Rolling Windows

Suaviza el ruido diario para ver la tendencia real.

Reto: Calcula media móvil de 7 días. Grafica Original vs Suavizada.
.rolling(7).mean()

Fase 5: Visualización

18. Scatter con Alpha

Millones de puntos sólidos no dicen nada. La transparencia revela densidad.

Reto: Plot Distancia vs Duración con alpha=0.1. Busca líneas raras.
Simulación: Líneas horizontales visibles

Fase 5: Visualización

19. Correlaciones

Entiende qué variables se mueven juntas.

Reto: Matriz de correlación (`df.corr()`) visualizada con Heatmap.

Fase 5: Exportación

20. Formato Parquet

CSV es lento y pierde tipos de datos. Parquet comprime y preserva esquema.

Reto: Guarda como clean.parquet y compara tamaño vs CSV.
df.to_parquet('archivo.parquet')

¡Reto Completado!

Has pasado de Pandas Básico a Ingeniería de Datos Eficiente.

Próximo Módulo: SQL Server & Bases Relacionales