Saltar a contenido

🔗 Práctica 4: EDA multi‑fuentes y joins con pandas

🎯 Objetivos

  • Ingerir datos desde fuentes heterogéneas: CSV/Parquet/JSON/SQLite/URL/ZIP
  • Unificar esquemas, normalizar tipos y limpiar mínimos
  • Hacer joins (merge) y groupby/agg para responder preguntas
  • Entregar un reporte corto con hallazgos y visualizaciones

📚 Referencias (leer al usar)

  • read_csv: https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html
  • to_parquet / read_parquet: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_parquet.html
  • read_json: https://pandas.pydata.org/docs/reference/api/pandas.read_json.html
  • read_sql: https://pandas.pydata.org/docs/reference/api/pandas.read_sql.html
  • merge: https://pandas.pydata.org/docs/reference/api/pandas.merge.html
  • groupby: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html
  • matplotlib savefig: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.savefig.html
  • sqlite3 (Python): https://docs.python.org/3/library/sqlite3.html

📁 Datos de ejemplo incluidos en el repo

  • https://juanfkurucz.com/ucu-id/ut1/data/trips_sample.csv: 10 filas de viajes (NYC Taxi)
  • https://juanfkurucz.com/ucu-id/ut1/data/taxi_zone_lookup.csv: tabla lookup (LocationID → Borough/Zone)
  • https://juanfkurucz.com/ucu-id/ut1/data/calendar.json: fechas especiales con flag special
  • https://juanfkurucz.com/ucu-id/ut1/data/borough_info.csv: metadatos de boroughs (para cargar a SQLite)
  • https://juanfkurucz.com/ucu-id/ut1/data/trips_sample.parquet: mismo sample en Parquet (opcional)
  • https://juanfkurucz.com/ucu-id/ut1/data/lookup.db: base SQLite con borough_info (opcional)

Puedes usarlos tal cual para completar la práctica sin buscar fuentes externas.

📁 Estructura sugerida

ID-UT1-multifuentes/
  data/
    trips_sample.csv
    trips_sample.parquet
    taxi_zone_lookup.csv
    calendar.json
    lookup.db
  results/
    perfiles/
    reportes/
    visualizaciones/
  src/
    eda_multifuentes.ipynb (o .py)
  README.md

Paso a paso (sin soluciones)

1) Ingesta (10 min) - Lee trips_sample.csv con read_csv(parse_dates=['tpep_pickup_datetime']) y nómbralo trips. - Lee trips_sample.parquet con read_parquet() (si lo generaste) y compara dtypes vs CSV. - Lee taxi_zone_lookup.csv con read_csv() y nómbralo zones. - Lee calendar.json con read_json() y nómbralo calendar; luego calendar['date'] = pd.to_datetime(calendar['date']).dt.date. - (Opcional) Conecta a lookup.db y trae borough_info con read_sql('SELECT * FROM borough_info', con) para enriquecer luego.

Pistas:

  • Definí rutas con pathlib.Path para portabilidad.
  • En read_csv, especificá dtype para IDs (p. ej., Int64) si querés preservar nulos.
  • Validá tamaños con len(df) y primeras filas con DataFrame.head.
  • Exportá un resumen de tipos y missing por fuente a results/perfiles/*.csv (p. ej., trips_types_missing.csv).

2) Normalización (10 min) - Estandariza nombres de columnas: trips.columns = trips.columns.str.lower() y lo mismo para zones. - Crea columna pickup_date = trips['tpep_pickup_datetime'].dt.date. - Verifica tipos: trips.dtypes y trips.isna().sum(); documenta si no tocas missing (ok en este sample).

Pistas:

  • Acordá un naming consistente: snake_case, sin espacios.
  • Convertí categóricas a category cuando apliquen (p. ej., borough) con Series.astype('category').
  • Confirmá que claves de join tengan el mismo tipo (int vs str).
  • Revisa duplicados después del join integrado y exporta conteo a results/perfiles/duplicates_after_join.txt.

3) Joins (10–15 min) - Enlaza zonas: trips_z = trips.merge(zones, left_on='pulocationid', right_on='locationid', how='left'). - Enlaza calendario por fecha: trips_z = trips_z.merge(calendar, left_on='pickup_date', right_on='date', how='left') y crea calendar_flag = trips_z['special'].fillna(False). - (Opcional) Enlaza con borough_info vía Borough para sumar area_km2.

Pistas:

  • Seleccioná solo columnas necesarias antes de los joins para evitar colisiones.
  • Usá validate='m:1' en DataFrame.merge cuando corresponda para chequear cardinalidades.
  • Si aparecen sufijos _x/_y, especificá suffixes=('_trips','_zones') y/o renombrá columnas clave.

4) GroupBy/agg (10–15 min) - Por borough: n viajes, avg_trip_distance, avg_total_amount. - Por borough y calendar_flag: mismos agregados para comparar. - Guarda ambos resultados en results/reportes/*.csv.

Pistas:

  • Usá DataFrame.groupby().agg({'trip_distance':'mean','total_amount':'mean','LocationID':'count'}) o equivalentes.
  • Ordená resultados con DataFrame.sort_values y redondeá con DataFrame.round antes de exportar.
  • (Opcional) Calculá correlaciones y covarianzas numéricas del dataset integrado y expórtalas a results/perfiles/corr.csv y results/perfiles/cov.csv.

5) Visualizaciones (10–15 min) - Barras por borough (conteo) y barras apiladas por calendar_flag. - Box/violin de trip_distance por borough. - Guarda imágenes en results/visualizaciones/ con savefig(..., dpi=200, bbox_inches='tight').

Pistas:

  • Asegurá un orden consistente de categorías (p. ej., Manhattan, Brooklyn, Queens, Bronx, Staten Island).
  • Etiquetá ejes y agrega títulos descriptivos; usa paletas consistentes con seaborn.barplot y seaborn.boxplot.

6) Reporte corto (5–10 min) - results/reportes/resumen.md: propósito → fuentes → pasos (1–2 líneas c/u) → 3 hallazgos accionables.

Pistas:

  • Explicá el tipo de join elegido y por qué.
  • Incluí tamaños de muestra y cualquier limitación (p. ej., fechas especiales incompletas).

✅ Checklist

  • Ingesta correcta de los 3–4 archivos (CSV/Parquet/JSON/SQLite)
  • 2 joins funcionando (trips+zones y trips+calendar; opcional borough_info)
  • 2 tablas de agregación guardadas + 2 gráficos con títulos/ejes claros
  • Resumen final con 3 hallazgos y decisiones tomadas

🧯 Errores comunes

  • Fechas: usa parse_dates y .dt.date para comparar contra calendar['date'].
  • Joins: revisa colisiones de nombres; si aparece locationid_x/y, renombra antes o selecciona columnas necesarias.
  • Parquet: instala pyarrow o usa CSV si no podés instalarlo.

Resultados de ejemplo (en el repo)

Los siguientes artefactos están generados en examples/UT1/04-eda-multifuentes-joins/results/:

  • reportes/agg_by_borough.csv, reportes/agg_by_borough_calendar.csv
  • visualizaciones/count_borough.png, visualizaciones/box_trip_distance.png
  • perfiles/trips_dtypes.csv, perfiles/trips_missing.csv, perfiles/zones_dtypes.csv, perfiles/zones_missing.csv, perfiles/calendar_dtypes.csv, perfiles/calendar_missing.csv
  • perfiles/corr.csv, perfiles/cov.csv (dataset integrado, numéricas)