🔗 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 flagspecial
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 conborough_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 conDataFrame.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
) conSeries.astype('category')
. - Confirmá que claves de join tengan el mismo tipo (
int
vsstr
). - 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'
enDataFrame.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á conDataFrame.round
antes de exportar. - (Opcional) Calculá correlaciones y covarianzas numéricas del dataset integrado y expórtalas a
results/perfiles/corr.csv
yresults/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
yseaborn.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 contracalendar['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)