Ejercicio outliers calidad de aire

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_tipo existe para que puedas comprobar tus resultados al final, pero no debes usarla durante el análisis.


Tareas

Tarea 1 — Carga y exploración inicial

  1. Carga el fichero CSV con pandas y muestra las primeras filas.
  2. Comprueba el número de filas y columnas.
  3. Revisa los tipos de datos de cada columna.
  4. Busca si hay valores nulos en alguna columna.

💡 Pista: usa df.head()df.shapedf.dtypes y df.isnull().sum().


Tarea 2 — Estadística descriptiva

  1. Calcula las estadísticas básicas (media, mediana, desviación típica, mínimo y máximo) de pm25_ug_m3 y no2_ug_m3.
  2. 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

  1. Dibuja un histograma para cada columna numérica.
  2. Dibuja un boxplot para cada columna numérica.
  3. Describe con palabras lo que observas: ¿la distribución es simétrica? ¿hay «colas» muy largas?

💡 Pista: usa matplotlib o seaborn. 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
  1. Calcula Q1, Q3 e IQR para cada columna numérica.
  2. Calcula los límites inferior y superior.
  3. Filtra las filas que queden fuera de esos límites.
  4. ¿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.

  1. Calcula el Z-score para cada columna numérica.
  2. Filtra las filas con |Z| > 3.
  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

  1. Muestra en una tabla los registros identificados como outliers (puedes usar los del método IQR).
  2. ¿Los outliers corresponden a valores muy altos, muy bajos o ambos?
  3. ¿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)

  1. Compara tus outliers detectados con la columna outlier_tipo del dataset.
  2. 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:

  1. Eliminarlos: elimina las filas con outliers y guarda el dataset limpio.
  2. Imputarlos: reemplaza los valores extremos por la mediana de la columna.
  3. 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)

solucion_calidad_aire


Publicado por

Juan Pablo Fuentes

Formador de programación y bases de datos