calidad_aire_sensores
🌫️ Ejercicio: Detección de Outliers en Datos de Calidad del Aire
Contexto
Una red de sensores distribuidos por cinco ciudades españolas registra diariamente la concentración de dos contaminantes atmosféricos:
- PM2.5 (
pm25_ug_m3): partículas finas en suspensión (µg/m³). Valores normales entre 5 y 40 µg/m³. - NO₂ (
no2_ug_m3): dióxido de nitrógeno (µg/m³). Valores normales entre 5 y 55 µg/m³.
El dataset calidad_aire_sensores.csv contiene 1.000 registros de distintas estaciones, ciudades y estaciones del año. Algunos registros son erróneos (fallos del sensor, picos de polución extrema) y deben ser identificados antes de cualquier análisis.
Columnas del dataset
| Columna | Tipo | Descripción |
|---|---|---|
sensor_id |
texto | Identificador único del sensor |
ciudad |
texto | Ciudad donde está instalado el sensor |
tipo_estacion |
texto | Tipo de ubicación: Urbana, Suburbana o Rural |
estacion_año |
texto | Estación del año: Primavera, Verano, Otoño, Invierno |
pm25_ug_m3 |
numérico | Concentración de PM2.5 (µg/m³) |
no2_ug_m3 |
numérico | Concentración de NO₂ (µg/m³) |
outlier_tipo |
texto | Solo para corrección: indica si la fila es normal o qué tipo de outlier es |
⚠️ Nota: la columna
outlier_tipoexiste para que puedas comprobar tus resultados al final, pero no debes usarla durante el análisis.
Tareas
Tarea 1 — Carga y exploración inicial
- Carga el fichero CSV con pandas y muestra las primeras filas.
- Comprueba el número de filas y columnas.
- Revisa los tipos de datos de cada columna.
- Busca si hay valores nulos en alguna columna.
💡 Pista: usa
df.head(),df.shape,df.dtypesydf.isnull().sum().
Tarea 2 — Estadística descriptiva
- Calcula las estadísticas básicas (media, mediana, desviación típica, mínimo y máximo) de
pm25_ug_m3yno2_ug_m3. - Fíjate especialmente en los valores mínimos y máximos: ¿te parecen razonables para una medición ambiental?
💡 Pista: usa
df.describe(). Un valor negativo de concentración de un gas es físicamente imposible.
Tarea 3 — Visualización de la distribución
- Dibuja un histograma para cada columna numérica.
- Dibuja un boxplot para cada columna numérica.
- Describe con palabras lo que observas: ¿la distribución es simétrica? ¿hay «colas» muy largas?
💡 Pista: usa
matplotliboseaborn. El boxplot muestra los outliers como puntos individuales fuera de los bigotes.
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(2, 2, figsize=(12, 8))
sns.histplot(df["pm25_ug_m3"], ax=axes[0, 0])
sns.boxplot(x=df["pm25_ug_m3"], ax=axes[0, 1])
sns.histplot(df["no2_ug_m3"], ax=axes[1, 0])
sns.boxplot(x=df["no2_ug_m3"], ax=axes[1, 1])
plt.tight_layout()
plt.show()
Tarea 4 — Detección de outliers con el método IQR
El método IQR (rango intercuartílico) define los límites fuera de los cuales un valor se considera atípico:
Límite inferior = Q1 - 1.5 × IQR
Límite superior = Q3 + 1.5 × IQR
- Calcula Q1, Q3 e IQR para cada columna numérica.
- Calcula los límites inferior y superior.
- Filtra las filas que queden fuera de esos límites.
- ¿Cuántos outliers has encontrado en cada columna?
💡 Pista:
Q1 = df["pm25_ug_m3"].quantile(0.25) Q3 = df["pm25_ug_m3"].quantile(0.75) IQR = Q3 - Q1 outliers = df[(df["pm25_ug_m3"] < Q1 - 1.5*IQR) | (df["pm25_ug_m3"] > Q3 + 1.5*IQR)]
Tarea 5 — Detección de outliers con el método Z-score
El Z-score mide cuántas desviaciones típicas se aleja un valor de la media. Se considera outlier si |Z| > 3.
- Calcula el Z-score para cada columna numérica.
- Filtra las filas con |Z| > 3.
- Compara el número de outliers detectados con el método IQR. ¿Son los mismos? ¿Por qué puede haber diferencias?
💡 Pista:
from scipy import stats df["z_pm25"] = stats.zscore(df["pm25_ug_m3"]) outliers_z = df[df["z_pm25"].abs() > 3]
Tarea 6 — Análisis de los outliers encontrados
- Muestra en una tabla los registros identificados como outliers (puedes usar los del método IQR).
- ¿Los outliers corresponden a valores muy altos, muy bajos o ambos?
- ¿Hay ciudades o tipos de estación con más outliers?
💡 Pista: usa
value_counts()sobre las columnas categóricas del subconjunto de outliers.
Tarea 7 — Verificación (solo al final)
- Compara tus outliers detectados con la columna
outlier_tipodel dataset. - Calcula cuántos outliers reales has conseguido detectar (verdaderos positivos) y cuántos registros normales has marcado por error (falsos positivos).
💡 Pista: cruza tu máscara de outliers con
df["outlier_tipo"] != "normal"usando una tabla de contingencia.
Tarea 8 (EXTRA) — Tratamiento de outliers
Una vez detectados los outliers, hay varias estrategias posibles:
- Eliminarlos: elimina las filas con outliers y guarda el dataset limpio.
- Imputarlos: reemplaza los valores extremos por la mediana de la columna.
- Recortarlos (capping): sustituye los valores que superan el límite superior por el propio límite superior (y los que caen por debajo del inferior, por el inferior).
Aplica al menos una de las tres estrategias a pm25_ug_m3 y justifica tu elección.
💡 Pista para el capping:
df["pm25_limpio"] = df["pm25_ug_m3"].clip(lower=limite_inf, upper=limite_sup)