Análisis exploratorio¶
Test 2 Prueba Data Science Capgemini
Javier Crespo Guerrero (javicrespi2000@gmail.com)
En este notebook realizaremos el análisis exploratorio y comprobaciones de estacionalidad de la serie temporal escogida.
El Dataset Escogido¶
El dataset escogido es Electricity Transformer Dataset, donde tendremos que predecir la temperatura del aceite dentro del transformador a partir de una serie de indicadores de carga, con datos correspondientes a dos años recogidos cada hora. En este caso utilizaremos la versión del dataset accesible a través de la libería darts como ETTh1Dataset. Las variables son las siguientes, según la descripción de la fuente:
date: The recorded dateHUFL: High UseFul LoadHULL: High UseLess LoadMUFL: Medium UseFul LoadMULL: Medium UseLess LoadLUFL: Low UseFul LoadLULL: Low UseLess LoadOT: Oil Temperature (Target)
¿Por qué este Dataset?¶
He escogido este Dataset porque presenta un problema de regresión de una serie temporal multivariante, pero con un tamaño asequible para este ejercicio.
La estacionalidad¶
Uno de los requisitos del ejercicio era que la variable objetivo fuese no estacional. Para ello, vamos a utilizar métodos de desestacionalización sobre la serie original y a partir de la serie desestacionalizada construiremos el modelo de regresión.
# Lectura y procesado de datos
import pandas as pd
# Visualizacion
import matplotlib.pyplot as plt
# Tratamiento y visualizacion de Series Temporales
from darts.utils.statistics import (
plot_acf,
check_seasonality,
remove_seasonality,
plot_ccf,
)
from darts.utils.utils import SeasonalityMode
# Dataset
from darts.datasets import ETTh1Dataset
# Parametros necesarios
RANDOM_SEED = 2024
TARGET = "OT"
PAST_COVARIATES = ["HUFL", "HULL", "MUFL", "MULL", "LUFL", "LULL"]
Lectura y visualización básica¶
# Lectura de los datos
series = ETTh1Dataset().load()
print(f"Tenemos {len(series)} datos")
print(series.time_index[:5])
print(series.time_index[-5:])
plt.figure(figsize=(20, 6))
series[TARGET].plot()
plt.show()
Tenemos 17420 datos
DatetimeIndex(['2016-07-01 00:00:00', '2016-07-01 01:00:00',
'2016-07-01 02:00:00', '2016-07-01 03:00:00',
'2016-07-01 04:00:00'],
dtype='datetime64[ns]', name='date', freq='h')
DatetimeIndex(['2018-06-26 15:00:00', '2018-06-26 16:00:00',
'2018-06-26 17:00:00', '2018-06-26 18:00:00',
'2018-06-26 19:00:00'],
dtype='datetime64[ns]', name='date', freq='h')
Tenemos 17420 puntos de datos. Por razones computacionales vamos a utilizar solamente los datos correspondientes a los últimos 3 meses para ajustar los modelos, puesto que se van a ejecutar algoritmos y métodos costosos que sobrepasan la capacidad de esta máquina.
Por supuesto, en un entorno real habría que usar el dataset completo y buscar formas de mejorar el rendimiento mediante, por ejemplo, aceleración por GPU.
_, series = series.split_after(pd.Timestamp("2018-04-01 00:00:00"))
len(series)
2083
Ahora disponemos de 2083 puntos de datos correspondientes al año 2018.
La variable objetivo¶
plt.figure(figsize=(20, 6))
series[TARGET].plot()
<Axes: xlabel='date'>
Parece que estamos ante una serie con tendencia ligeramente creciente, varianza aparentemente constante y sin outliers apartenes. Vamos a estudiar el resto de regresores que utilizaremos.
Las covariables¶
A continuación vamos a pasar a estudiar las covariables. Hay dos grupos: los que hablan de "Useful Load" (HUFL, MUFL y LULF) y sobre "UseLess Load" (HULL, MULL, LULL), vamos a representar cada uno de estos dos grupos juntos.
plt.figure(figsize=(20, 10))
series[["HUFL", "MUFL", "LUFL"]].plot()
<Axes: xlabel='date'>
plt.figure(figsize=(20, 10))
series[["HULL", "MULL", "LULL"]].plot()
<Axes: xlabel='date'>
Las variables parecen recoger cierta variedad y tendencias, lo que a priori es útil para predecir la serie objetivo. Sin embargo, parece que algunas series tienen una forma muy similar entre sí, lo que podría afectar al modelo final. Vamos a representar cada covariable por separado para poder visualizar mejor la forma.
fig, axs = plt.subplots(len(PAST_COVARIATES), 1)
fig.set_figheight(50)
fig.set_figwidth(30)
colors = ["red", "green", "blue", "orange", "purple", "brown"]
for var, axis, color in zip(PAST_COVARIATES, axs, colors):
series[var].plot(new_plot=False, ax=axis, color=color)
Efectivamente, hay parejas de variables con formas bastante similares (por ejemplo, HUFL y MUFL), por lo que tendremos que ser cuidadosos a la hora de establecer los parámetros de regularización de los modelos que vayamos a escoger.
Correlación entre variable objetivo y covariables¶
for var in PAST_COVARIATES:
print(f"Variable - {var}")
plot_ccf(series[TARGET], series[var], max_lag=100)
plt.show()
Variable - HUFL
Variable - HULL
Variable - MUFL
Variable - MULL
Variable - LUFL
Variable - LULL
Sin entrar al detalle de cada variable, vemos que las covariables parecen estar correladas con distintos aspectos de la serie objetivo, lo que a priori es un buen indicador de poder predictivo.
Estacionalidad de la serie¶
A continuación vamos a comprobar la estacionalida de la serie objetivo comprobando su correlograma.
plot_acf(series[TARGET], max_lag=200, m=22)
Claramente la autocorrelación en el retardo 22 destaca y es indicativa de estacionalidad.
Vamos a utilizar el test que incluye la librería darts utilizando la fórmula de Barlett. En este caso el test nos devolverá el primer retardo en el que la serie es estacional, por lo que podría haber más periodos.
is_seasonal, period = check_seasonality(series[TARGET], alpha=0.05, max_lag=200)
if is_seasonal:
print("There is seasonality of order {}.".format(period))
There is seasonality of order 22.
Hay estacionalidad, al menos de orden 22. Como en el ejercicio se nos pide trabajar con una serie desestacionalizada vamos a desestacionalizar la serie asumiendo una estacionalidad aditiva, puesto que vimos en el plot que la varianza no parecía aumentar con el tiempo.
unseasonal_series = remove_seasonality(series[TARGET], model=SeasonalityMode.ADDITIVE)
series = series[PAST_COVARIATES].stack(unseasonal_series)
plt.figure(figsize=(20, 6))
series[TARGET].plot()
<Axes: xlabel='date'>
plot_acf(series[TARGET], max_lag=175, m=22)
is_seasonal, period = check_seasonality(series[TARGET], alpha=0.05, max_lag=175)
if is_seasonal:
print("There is seasonality of order {}.".format(period))
Podemos considerar esta nueva serie como no estacional, por lo que vamos a construir el modelo a partir de ella en el siguiente notebook.
# Guardamos los datos con la nueva serie desestacionalizada
series.to_csv("electricity_transformer.csv")