ScikitLearn
Tutorial ScikitLearn: Preprocesamiento de datos de series temporales
Aprende a convertir, manipular y operar fechas de Series temporales en Python con Scikit Learn. Mejora tus habilidades en el análisis de series temporales con Pandas.
Aprende ScikitLearn GRATIS y certifícateManejo de fechas y tiempos en Python con pandas
En el análisis de series temporales, es fundamental manejar adecuadamente las fechas y los tiempos. La biblioteca pandas ofrece un conjunto robusto de herramientas para trabajar con datos temporales de forma eficiente.
Para comenzar, es común que las fechas en los conjuntos de datos se encuentren en formato de cadena. Es esencial convertir estas cadenas a objetos datetime para poder realizar operaciones temporales. La función pd.to_datetime()
de pandas permite convertir una serie de textos a objetos datetime:
import pandas as pd
fechas_texto = ['2024-01-01', '2024-02-15', '2024-03-20']
fechas_datetime = pd.to_datetime(fechas_texto)
print(fechas_datetime)
Al ejecutar este código, obtendremos una Serie de pandas con datos de tipo datetime, lo que facilita su manipulación posterior.
Una vez convertidas las fechas, podemos establecer una DatetimeIndex para nuestro DataFrame. Esto es especialmente útil cuando las fechas representan índices temporales en nuestras series de datos:
datos = pd.DataFrame({'valor': [10, 20, 15]}, index=fechas_datetime)
print(datos)
La DatetimeIndex permite acceder a funcionalidades avanzadas, como la selección de datos por fecha. Por ejemplo, podemos filtrar los datos de un mes específico:
datos_enero = datos['2024-01']
print(datos_enero)
Además, pandas proporciona atributos para extraer componentes de las fechas. Podemos obtener el año, mes, día, día de la semana y más:
datos['año'] = datos.index.year
datos['mes'] = datos.index.month
datos['día'] = datos.index.day
print(datos)
El manejo de zonas horarias es otro aspecto crucial en series temporales internacionales. Podemos asignar una zona horaria utilizando el atributo tz
:
datos.index = datos.index.tz_localize('Europe/Madrid')
print(datos)
Si necesitamos convertir las fechas a otra zona horaria, utilizamos tz_convert()
:
datos_ny = datos.tz_convert('America/New_York')
print(datos_ny)
Las operaciones aritméticas con fechas son esenciales para calcular diferencias temporales. Podemos calcular el desplazamiento temporal entre fechas utilizando objetos Timedelta
:
datos['cambio_días'] = datos.index - datos.index[0]
print(datos)
Para generar secuencias de fechas, pandas ofrece la función pd.date_range()
, que es útil para crear índices temporales:
rango_fechas = pd.date_range(start='2024-01-01', periods=5, freq='D')
print(rango_fechas)
En este ejemplo, se ha creado un rango de fechas diario de cinco días a partir del 1 de enero de 2024.
El manejo de frecuencias y períodos es esencial para trabajar con series temporales. Podemos especificar la frecuencia al crear rangos de fechas o al reindexar datos. Algunas frecuencias comunes incluyen 'D'
para diario, 'M'
para mensual y 'A'
para anual:
rango_mensual = pd.date_range(start='2024-01-01', periods=3, freq='M')
print(rango_mensual)
Para trabajar con fechas irregulares o eventos que ocurren en intervalos no uniformes, pandas maneja eficientemente estas situaciones sin requerir una frecuencia fija.
Si disponemos de columnas separadas para año, mes y día, podemos combinarlas para crear una columna datetime:
df = pd.DataFrame({'año': [2024, 2024], 'mes': [1, 2], 'día': [10, 15]})
df['fecha'] = pd.to_datetime(df[['año', 'mes', 'día']])
print(df)
El manejo de fechas parciales también es posible. Si solo se tiene el año y el mes, pandas interpreta el día como el primero por defecto:
fechas_parciales = pd.to_datetime(['2024-01', '2024-02'], format='%Y-%m')
print(fechas_parciales)
En resumen, pandas proporciona herramientas potentes para el manejo de fechas y tiempos, permitiendo una manipulación flexible y eficiente de datos temporales, lo cual es esencial en el preprocesamiento de series temporales para modelos predictivos.
Resampling y agregación de datos temporales
En el análisis de series temporales, a menudo es necesario ajustar la frecuencia de nuestros datos para adaptarlos a las necesidades del análisis o del modelo. El resampling es una técnica que permite cambiar la frecuencia temporal de un conjunto de datos, ya sea aumentando (upsampling) o disminuyendo (downsampling) la granularidad temporal.
Para realizar resampling en Python, utilizamos principalmente la biblioteca pandas, que ofrece métodos eficientes para este propósito. El método resample()
es fundamental y se aplica a objetos DataFrame o Series que tienen un DatetimeIndex.
Por ejemplo, si disponemos de datos diarios y queremos agruparlos a nivel mensual, podemos emplear el siguiente código:
import pandas as pd
# Supongamos que tenemos una serie de datos diarios
fechas = pd.date_range(start='2024-01-01', end='2024-01-10', freq='D')
valores = [5, 7, 6, 8, 7, 9, 5, 6, 8, 7]
datos_diarios = pd.Series(valores, index=fechas)
# Resampling a datos mensuales sumando los valores
datos_mensuales = datos_diarios.resample('M').sum()
print(datos_mensuales)
En este ejemplo, hemos realizado un downsampling de datos diarios a mensuales, utilizando la función de agregación sum()
para sumar los valores dentro de cada mes.
La elección de la función de agregación es crucial al resamplear los datos. Algunas funciones comunes incluyen mean()
, sum()
, max()
, min()
y median()
. Si quisiéramos obtener el promedio en lugar de la suma, simplemente cambiaríamos la función:
# Resampling a datos mensuales calculando la media
datos_mensuales = datos_diarios.resample('M').mean()
print(datos_mensuales)
Cuando realizamos upsampling, es decir, aumentamos la frecuencia temporal (por ejemplo, de datos mensuales a diarios), es posible que aparezcan valores faltantes debido a la ausencia de datos en los nuevos intervalos. Para manejar esta situación, podemos utilizar métodos de relleno como ffill()
(forward fill) o bfill()
(backward fill):
# Upsampling de datos mensuales a diarios
datos_mensuales = datos_diarios.resample('M').sum()
datos_upsampled = datos_mensuales.resample('D').ffill()
print(datos_upsampled)
En este caso, hemos rellenado los valores faltantes propagando el último valor conocido hacia adelante, manteniendo la coherencia temporal de los datos.
La función interpolate()
también es útil para estimar valores en los nuevos puntos temporales al realizar upsampling. Podemos aplicar diferentes métodos de interpolación, como linear
, time
o spline
:
# Upsampling con interpolación lineal
datos_upsampled = datos_mensuales.resample('D').interpolate(method='linear')
print(datos_upsampled)
Además del resampling simple, pandas permite realizar agregaciones personalizadas utilizando el método agg()
. Esto es especialmente útil cuando necesitamos aplicar múltiples funciones de agregación al mismo tiempo:
# Agregación personalizada al resamplear
datos_resampleados = datos_diarios.resample('W').agg(['mean', 'max', 'min'])
print(datos_resampleados)
En este ejemplo, hemos resampleado los datos a una frecuencia semanal y calculado la media, el máximo y el mínimo de cada semana.
Las ventanas móviles son otra herramienta poderosa en el análisis de series temporales. Podemos utilizar el método rolling()
para calcular estadísticas sobre ventanas temporales deslizantes:
# Cálculo de la media móvil de 3 días
media_movil = datos_diarios.rolling(window=3).mean()
print(media_movil)
La media móvil suaviza las fluctuaciones diarias y nos permite identificar tendencias subyacentes en los datos.
Cuando trabajamos con datos financieros u otros que requieren información específica, la función ohlc()
(open-high-low-close) proporciona un resumen detallado de los valores dentro de cada intervalo:
# Resumen OHLC al resamplear
datos_ohlc = datos_diarios.resample('W').ohlc()
print(datos_ohlc)
Este método es especialmente útil para visualizar y analizar el comportamiento de variables que presentan variaciones significativas en cortos períodos.
Es importante destacar que las frecuencias temporales en pandas se especifican mediante códigos de cadena. Algunos códigos comunes son:
'H'
: Horario'D'
: Diario'W'
: Semanal'M'
: Mensual'Q'
: Trimestral'A'
: Anual
Podemos combinar estas frecuencias con ajustes para especificar el momento exacto de la agrupación. Por ejemplo, 'W-MON'
indica una frecuencia semanal que inicia los lunes.
La combinación de resampling y agregación nos permite transformar y resumir los datos temporales de manera que sean más adecuados para el análisis y el modelado. Al preparar los datos de esta forma, facilitamos la detección de patrones y tendencias que los algoritmos de aprendizaje automático pueden aprovechar.
Por último, es recomendable visualizar los datos antes y después del resampling para comprender mejor el impacto de estas transformaciones:
import matplotlib.pyplot as plt
# Visualización de datos diarios vs. mensuales
plt.figure(figsize=(10,5))
plt.plot(datos_diarios, label='Datos Diarios')
plt.plot(datos_mensuales, label='Datos Mensuales', marker='o')
plt.legend()
plt.show()
La visualización nos ayuda a verificar que el preprocesamiento se ha realizado correctamente y que los datos resultantes conservan la información relevante para nuestro análisis.
Tratamiento de datos faltantes y valores atípicos en series temporales
En el análisis de series temporales, es común enfrentarse a datos faltantes y valores atípicos que pueden distorsionar los resultados si no se gestionan adecuadamente. Un manejo correcto de estos elementos es esencial para garantizar la calidad y fiabilidad de los modelos predictivos.
Los datos faltantes pueden surgir por diversas razones, como errores en la captura de datos o interrupciones en el registro. Antes de aplicar cualquier método de imputación, es fundamental identificar dónde se ubican estos valores:
import pandas as pd
# Supongamos que tenemos una serie temporal con valores faltantes
fechas = pd.date_range(start='2024-01-01', periods=10, freq='D')
valores = [5, 7, None, 8, 7, None, 5, 6, 8, 7]
serie = pd.Series(valores, index=fechas)
# Identificar los datos faltantes
datos_faltantes = serie.isnull()
print(datos_faltantes)
Una vez detectados, existen varias técnicas para imputar estos valores. Una de las más simples es el relleno hacia adelante (forward fill), que utiliza el último valor conocido para llenar los datos faltantes:
# Relleno hacia adelante
serie_ffill = serie.ffill()
print(serie_ffill)
Otra opción es el relleno hacia atrás (backward fill), que utiliza el siguiente valor conocido:
# Relleno hacia atrás
serie_bfill = serie.bfill()
print(serie_bfill)
La interpolación lineal es una técnica más precisa que estima los valores faltantes basándose en los valores adyacentes:
# Interpolación lineal
serie_interpolada = serie.interpolate(method='linear')
print(serie_interpolada)
Además de métodos lineales, pandas ofrece diversos métodos de interpolación, como time
, spline
o polynomial
, que pueden adaptarse mejor a la naturaleza de los datos:
# Interpolación basada en el tiempo
serie_interpolada_tiempo = serie.interpolate(method='time')
print(serie_interpolada_tiempo)
En el caso de valores atípicos, estos son datos que se desvían significativamente del resto de observaciones y pueden distorsionar el análisis. Para identificarlos, es común utilizar técnicas estadísticas como la detección basada en el z-score o el rango intercuartílico (IQR).
El z-score mide el número de desviaciones estándar que un dato está alejado de la media:
import numpy as np
# Calcular el z-score
media = serie.mean()
desviacion_estandar = serie.std()
z_scores = (serie - media) / desviacion_estandar
# Identificar valores atípicos con un umbral de 3 desviaciones estándar
umbral = 3
valores_atipicos = serie[np.abs(z_scores) > umbral]
print(valores_atipicos)
El método del IQR se basa en los cuartiles y es menos sensible a las distribuciones no normales:
# Calcular cuartiles
Q1 = serie.quantile(0.25)
Q3 = serie.quantile(0.75)
IQR = Q3 - Q1
# Definir límites para identificar outliers
limite_inferior = Q1 - 1.5 * IQR
limite_superior = Q3 + 1.5 * IQR
# Identificar valores atípicos
valores_atipicos_iqr = serie[(serie < limite_inferior) | (serie > limite_superior)]
print(valores_atipicos_iqr)
Una vez detectados los valores atípicos, existen varias estrategias para tratarlos:
- Eliminación: remover los valores atípicos de la serie. Es una opción cuando se tiene certeza de que son errores.
# Eliminar valores atípicos
serie_sin_atipicos = serie[~((serie < limite_inferior) | (serie > limite_superior))]
print(serie_sin_atipicos)
- Imputación: reemplazar los valores atípicos por una estimación, como la media o mediana.
# Reemplazar valores atípicos por la mediana
mediana = serie.median()
serie_imputada = serie.copy()
serie_imputada[(serie_imputada < limite_inferior) | (serie_imputada > limite_superior)] = mediana
print(serie_imputada)
- Transformación: aplicar transformaciones a los datos para reducir el impacto de los valores atípicos, como la transformada logarítmica.
# Aplicar transformación logarítmica
import numpy as np
serie_transformada = np.log(serie)
print(serie_transformada)
En series temporales, es importante considerar la naturaleza temporal de los datos al tratar valores atípicos y faltantes. Por ejemplo, si se detectan valores faltantes en momentos críticos, como fines de mes o períodos de alta actividad, es crucial imputarlos adecuadamente.
Para un enfoque más sofisticado, podemos utilizar métodos de imputación avanzados que tengan en cuenta la estructura temporal. La biblioteca Scikit-Learn ofrece herramientas como KNNImputer
, aunque su uso directo en series temporales requiere precaución debido a las dependencias temporales.
from sklearn.impute import KNNImputer
# Preparar datos para KNNImputer
datos_para_imputar = serie.values.reshape(-1, 1)
# Aplicar KNNImputer
imputador_knn = KNNImputer(n_neighbors=2)
serie_imputada_knn = imputador_knn.fit_transform(datos_para_imputar)
# Convertir de vuelta a serie
serie_imputada_knn = pd.Series(serie_imputada_knn.flatten(), index=serie.index)
print(serie_imputada_knn)
Al utilizar KNNImputer
, es esencial asegurarse de que el modelo respete la secuencia temporal para evitar introducir sesgos. Otra opción es emplear métodos basados en modelos estadísticos, como la suavización exponencial o modelos ARIMA, para imputar y ajustar los datos.
La suavización exponencial permite predecir valores futuros basándose en observaciones pasadas, asignando pesos decrecientes a medida que nos alejamos en el tiempo:
# Aplicar suavización exponencial para imputar datos faltantes
serie_suavizada = serie.interpolate(method='spline', order=2)
print(serie_suavizada)
Es importante visualizar los datos antes y después del tratamiento para entender el impacto de las imputaciones y ajustes:
import matplotlib.pyplot as plt
# Visualizar serie original y serie imputada
plt.figure(figsize=(10,5))
plt.plot(serie, label='Serie Original', marker='o')
plt.plot(serie_interpolada, label='Serie Interpolada', marker='x')
plt.legend()
plt.show()
La detección de rupturas estructurales o cambios abruptos en la serie también es crucial, ya que pueden confundirse con valores atípicos. Herramientas como la prueba de Chow o algoritmos de detección de cambios pueden ayudar en este análisis.
En resumen, el tratamiento de datos faltantes y valores atípicos en series temporales requiere una combinación de técnicas estadísticas y consideraciones sobre la naturaleza temporal de los datos. Un manejo adecuado garantiza que los modelos construidos sean más robustos y reflejen fielmente los patrones subyacentes de la serie.
Eliminación de tendencias y estacionalidades
En el análisis de series temporales, es fundamental eliminar tendencias y estacionalidades para lograr que los datos sean estacionarios y adecuados para ciertos modelos predictivos. Las tendencias y estacionalidades pueden ocultar patrones importantes y afectar la precisión de los algoritmos de aprendizaje automático.
La tendencia es una variación a largo plazo en la serie temporal que muestra un incremento o decremento persistente de los datos a lo largo del tiempo. Por otro lado, la estacionalidad se refiere a patrones que se repiten en intervalos regulares, como fluctuaciones anuales, mensuales o semanales.
Para muchos modelos, es necesario que los datos sean estacionarios, es decir, que sus propiedades estadísticas, como la media y la varianza, sean constantes en el tiempo. La eliminación de tendencia y estacionalidad ayuda a cumplir esta condición, permitiendo que los modelos capturen mejor las relaciones subyacentes.
Una técnica común para eliminar la tendencia es el diferenciado (differencing), que consiste en calcular la diferencia entre valores consecutivos de la serie temporal. Esto puede realizarse fácilmente utilizando las funciones de pandas:
import pandas as pd
# Supongamos que tenemos una serie temporal con tendencia
fechas = pd.date_range(start='2024-01-01', periods=10, freq='D')
valores = [5, 6, 8, 11, 15, 20, 26, 33, 41, 50]
serie = pd.Series(valores, index=fechas)
# Aplicar el primer diferenciado
serie_diferenciada = serie.diff()
print(serie_diferenciada)
Al aplicar diff()
, obtenemos la diferencia entre cada valor y el anterior, eliminando así la tendencia lineal. Si persiste una tendencia, es posible aplicar un segundo diferenciado utilizando diff().diff()
.
Otra forma de eliminar la tendencia es mediante la regresión lineal y luego restar el componente de tendencia estimado de la serie original. Esto se conoce como detrending:
import numpy as np
from sklearn.linear_model import LinearRegression
# Crear una variable de tiempo
tiempo = np.arange(len(serie)).reshape(-1, 1)
# Ajustar regresión lineal
modelo = LinearRegression()
modelo.fit(tiempo, serie.values)
# Obtener la tendencia estimada
tendencia_estimada = modelo.predict(tiempo)
# Eliminar la tendencia
serie_sin_tendencia = serie - tendencia_estimada
print(serie_sin_tendencia)
En este ejemplo, hemos utilizado LinearRegression de Scikit-Learn para estimar la tendencia y restarla de la serie original, obteniendo una serie más adecuada para el análisis.
Para eliminar la estacionalidad, una técnica frecuente es aplicar el diferenciado estacional, que resta los valores con un retardo igual al período estacional. Por ejemplo, si la estacionalidad es semanal en datos diarios, restamos cada valor con el de 7 días atrás:
# Aplicar diferenciado estacional con período de 7
serie_diferenciada_estacional = serie - serie.shift(7)
print(serie_diferenciada_estacional)
La función shift()
desplaza la serie temporal un número específico de períodos, permitiendo restar valores separados por el intervalo estacional y eliminar así los patrones estacionales.
Otra técnica más sofisticada es la descomposición de la serie temporal mediante el método aditivo o multiplicativo, que separa la serie en sus componentes de tendencia, estacionalidad y residuo. La biblioteca statsmodels proporciona la función seasonal_decompose
para este propósito:
from statsmodels.tsa.seasonal import seasonal_decompose
# Descomponer la serie temporal
descomposicion = seasonal_decompose(serie, model='additive', period=7)
# Extraer componentes
tendencia = descomposicion.trend
estacionalidad = descomposicion.seasonal
residuo = descomposicion.resid
# Mostrar componentes
print('Tendencia:')
print(tendencia)
print('Estacionalidad:')
print(estacionalidad)
print('Residuo:')
print(residuo)
Tras la descomposición, podemos restar la tendencia y la estacionalidad de la serie original para obtener los residuos, que representan la serie sin estos componentes.
En caso de no querer utilizar bibliotecas adicionales, podemos emplear la técnica de suavizado mediante promedios móviles para estimar y eliminar la tendencia y estacionalidad. Por ejemplo, para calcular un promedio móvil y eliminar la tendencia:
# Calcular promedio móvil de ventana de 3 períodos
promedio_movil = serie.rolling(window=3, center=True).mean()
# Eliminar la tendencia calculada
serie_sin_tendencia = serie - promedio_movil
print(serie_sin_tendencia)
El método rolling()
calcula estadísticas sobre ventanas móviles, y al restar el promedio móvil de la serie original, eliminamos componentes de baja frecuencia como la tendencia.
Para eliminar la estacionalidad, podemos aplicar un promedio móvil estacional que capte la estacionalidad y luego restarlo de la serie. Si la frecuencia estacional es de 7 períodos:
# Calcular promedio móvil estacional
promedio_movil_estacional = serie.rolling(window=7, center=True).mean()
# Eliminar estacionalidad
serie_sin_estacionalidad = serie - promedio_movil_estacional
print(serie_sin_estacionalidad)
Si combinamos ambos promedios móviles, podemos estimar y eliminar tanto la tendencia como la estacionalidad de la serie temporal.
Es importante visualizar la serie antes y después de la eliminación de tendencia y estacionalidad para asegurarnos de que el preprocesamiento ha sido efectivo. Podemos graficar las series utilizando matplotlib:
import matplotlib.pyplot as plt
plt.figure(figsize=(12,6))
plt.plot(serie, label='Serie Original')
plt.plot(tendencia, label='Tendencia')
plt.plot(estacionalidad, label='Estacionalidad')
plt.plot(residuo, label='Residuo')
plt.legend()
plt.show()
Al realizar correctamente la eliminación de tendencia y estacionalidad, obtenemos una serie más adecuada para técnicas de aprendizaje automático, especialmente aquellas que asumen que los datos son estacionarios en media y varianza.
Finalmente, es crucial validar que los datos resultantes cumplen con las propiedades necesarias para el modelado y que no se ha introducido ningún sesgo o distorsión en el proceso de eliminación de componentes.
Smoothing y filtrado de series temporales
En el análisis de series temporales, es común que los datos contengan ruido o fluctuaciones de corto plazo que pueden ocultar patrones subyacentes importantes. Las técnicas de smoothing y filtrado permiten suavizar estas fluctuaciones para destacar tendencias y estructuras significativas en los datos.
El smoothing o suavizado consiste en aplicar métodos que promedian los valores vecinos en la serie temporal, reduciendo la variabilidad aleatoria. Uno de los métodos más sencillos es el promedio móvil simple, que calcula la media de los valores en una ventana deslizante:
import pandas as pd
# Crear una serie temporal de ejemplo
fechas = pd.date_range(start='2024-01-01', periods=30, freq='D')
import numpy as np
valores = np.random.normal(loc=50, scale=5, size=30)
serie = pd.Series(valores, index=fechas)
# Calcular el promedio móvil de ventana de 5 días
promedio_movil = serie.rolling(window=5).mean()
En este código, utilizamos el método rolling()
de pandas para calcular el promedio móvil de la serie con una ventana de 5 días. El resultado es una serie suavizada que reduce la influencia de variaciones a corto plazo.
Además del promedio móvil simple, existe el promedio móvil ponderado, donde se asignan pesos diferentes a cada valor dentro de la ventana, dando mayor importancia a ciertos puntos. Una variante popular es el promedio móvil exponencial (EMA), que asigna pesos decrecientes exponencialmente a los valores anteriores:
# Calcular el promedio móvil exponencial con factor de ajuste alfa
promedio_exponencial = serie.ewm(alpha=0.3).mean()
El método ewm()
de pandas permite calcular el promedio móvil exponencial, donde el parámetro alpha
controla la rapidez con la que decrece la influencia de los datos previos. Un valor de alpha
alto da más peso a los datos recientes.
El filtrado es otra técnica que permite eliminar componentes no deseados de una serie temporal, como el ruido de alta frecuencia. Uno de los filtros más utilizados es el filtro de Savitzky-Golay, que suaviza la serie mediante el ajuste de un polinomio en ventanas locales:
from scipy.signal import savgol_filter
# Aplicar el filtro de Savitzky-Golay
serie_suavizada = savgol_filter(serie, window_length=5, polyorder=2)
En este ejemplo, utilizamos la función savgol_filter()
de SciPy para suavizar la serie. El parámetro window_length
define el tamaño de la ventana y polyorder
el orden del polinomio ajustado. Este filtro es útil para preservar características importantes como picos o valles en los datos.
Otra técnica es el suavizado exponencial simple, que es especialmente adecuado para datos sin tendencia ni estacionalidad. Se basa en la ecuación:
$$
S_t = \alpha Y_t + (1 - \alpha) S_{t-1}
$$
Donde $( \alpha )$ es el factor de suavizado entre 0 y 1, $( Y_t )$ es el valor original y $( S_t )$ es el valor suavizado. Podemos implementarlo utilizando el método ewm()
:
# Suavizado exponencial simple con factor alpha de 0.5
suavizado_exponencial = serie.ewm(alpha=0.5, adjust=False).mean()
El parámetro adjust=False
asegura que los pesos se calculen de forma recursiva, acorde con la fórmula del suavizado exponencial simple.
Para series temporales con tendencia o estacionalidad, se pueden utilizar modelos de suavizado exponencial más avanzados, como los modelos de Holt o Holt-Winters. Estos permiten capturar tendencias lineales y estacionales multiplicativas o aditivas. Si bien estos modelos no están disponibles directamente en Scikit-Learn, podemos implementarlos con statsmodels:
import statsmodels.api as sm
# Aplicar modelo de Holt-Winters para capturar tendencia y estacionalidad
modelo_hw = sm.tsa.ExponentialSmoothing(serie, trend='add', seasonal='add', seasonal_periods=7)
ajuste_hw = modelo_hw.fit()
serie_suavizada_hw = ajuste_hw.fittedvalues
En este código, aplicamos el modelo de suavizado exponencial triple de Holt-Winters, especificando componentes aditivos de tendencia y estacionalidad, con un período estacional de 7 días.
Es posible integrar técnicas de smoothing y filtrado dentro de un Pipeline de Scikit-Learn mediante la creación de transformadores personalizados. Por ejemplo, podemos crear un transformador que aplique el promedio móvil:
from sklearn.base import BaseEstimator, TransformerMixin
class PromedioMovilTransformer(BaseEstimator, TransformerMixin):
def __init__(self, window):
self.window = window
def fit(self, X, y=None):
return self
def transform(self, X):
return X.rolling(window=self.window).mean().fillna(method='bfill')
Con este transformador, podemos incluir el suavizado en un pipeline:
from sklearn.pipeline import Pipeline
# Crear pipeline con el transformador personalizado
pipeline = Pipeline([
('suavizado', PromedioMovilTransformer(window=5)),
# Agregar otros pasos como escalado o modelado
], memory = None)
Este enfoque es útil para mantener un flujo de trabajo organizado y reproducible, integrando el preprocesamiento y el modelado en un solo objeto.
El filtrado digital es otra área que utiliza técnicas como los filtros de Butterworth o Chebyshev para eliminar componentes de alta o baja frecuencia. Estos filtros se pueden diseñar utilizando SciPy:
from scipy.signal import butter, filtfilt
# Diseño de un filtro pasa bajos de Butterworth
orden = 2
frecuencia_corte = 0.1 # Entre 0 y 1, donde 1 es la frecuencia Nyquist
b, a = butter(N=orden, Wn=frecuencia_corte, btype='low', analog=False)
# Aplicar el filtro a la serie
serie_filtrada = filtfilt(b, a, serie)
El filtro pasa bajos elimina las frecuencias altas, suavizando aún más la serie. Es importante elegir adecuadamente la frecuencia de corte para conservar las características relevantes de los datos.
Al aplicar técnicas de smoothing y filtrado, es crucial tener en cuenta los efectos en los bordes. Los valores al inicio y al final de la serie pueden no estar bien definidos debido a la falta de datos suficientes en las ventanas de cálculo. Métodos como fillna()
pueden ayudar a manejar estos casos:
# Rellenar valores faltantes después del suavizado
promedio_movil = promedio_movil.fillna(method='bfill')
Además, es esencial considerar el sesgo que el suavizado puede introducir en los datos, especialmente si pretendemos utilizar la serie para predicción. El suavizado puede disminuir la varianza, pero también puede eliminar detalles importantes.
La visualización es una herramienta clave para evaluar el impacto del smoothing y filtrado. Podemos graficar la serie original y la suavizada para comparar:
import matplotlib.pyplot as plt
plt.figure(figsize=(12,6))
plt.plot(serie, label='Serie Original', marker='o')
plt.plot(promedio_movil, label='Promedio Móvil', linestyle='--')
plt.plot(suavizado_exponencial, label='Suavizado Exponencial')
plt.legend()
plt.show()
En este gráfico, observamos cómo las diferentes técnicas de suavizado afectan a la serie temporal, permitiendo seleccionar la más adecuada para nuestro análisis.
Finalmente, es recomendable experimentar con distintos métodos y parámetros para encontrar el equilibrio óptimo entre suavizado y preservación de la información relevante. Cada serie temporal es única, y las técnicas de smoothing y filtrado deben adaptarse a las características específicas de los datos.
Ejercicios de esta lección Preprocesamiento de datos de series temporales
Evalúa tus conocimientos de esta lección Preprocesamiento de datos de series temporales con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.
Todas las lecciones de ScikitLearn
Accede a todas las lecciones de ScikitLearn y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.
Aprendizaje Automático
Introducción Y Entorno
Introducción E Instalación
Introducción Y Entorno
Introducción Al Preprocesamiento De Datos
Preprocesamiento De Datos
Identificación Y Tratamiento De Valores Faltantes
Preprocesamiento De Datos
Escalado De Datos
Preprocesamiento De Datos
Normalización De Datos
Preprocesamiento De Datos
Codificación De Variables Categóricas
Preprocesamiento De Datos
Ingeniería De Características
Preprocesamiento De Datos
Selección De Características
Preprocesamiento De Datos
Extracción De Características
Preprocesamiento De Datos
Particionamiento De Datos
Preprocesamiento De Datos
Preprocesamiento De Datos Desbalanceados
Preprocesamiento De Datos
Introducción A La Regresión
Regresión
Regresión Lineal
Regresión
Regresión Knn Kneighborsregressor
Regresión
Regresión Svm Con Svr
Regresión
Regresión Con Árboles Decisiontreeregressor
Regresión
Regresión Con Algoritmos De Conjunto
Regresión
Introducción A La Clasificación
Clasificación
Clasificación Con Regresión Logística
Clasificación
Clasificación Knn Kneighborsclassifier
Clasificación
Clasificación Svm Con Svc
Clasificación
Clasificación Con Árboles Decisiontreeclassifier
Clasificación
Clasificación Con Algoritmos De Conjunto
Clasificación
Reducción De La Dimensionalidad Con Pca
Aprendizaje No Supervisado
Clustering Con Kmeans
Aprendizaje No Supervisado
Clustering Jerárquico
Aprendizaje No Supervisado
Clustering De Densidad Con Dbscan
Aprendizaje No Supervisado
Preprocesamiento De Textos Para Nlp
Nlp
Representación De Texto Y Extracción De Características
Nlp
Clasificación De Texto Con Scikit Learn
Nlp
Análisis De Sentimiento
Nlp
Técnicas Avanzadas De Extracción De Características
Nlp
Introducción Al Análisis De Series Temporales
Series Temporales
Preprocesamiento De Datos De Series Temporales
Series Temporales
Ingeniería De Características Para Series Temporales
Series Temporales
Transformación Y Escalado De Series Temporales
Series Temporales
Validación Y Evaluación De Modelos En Series Temporales
Series Temporales
Validación Y Evaluación De Modelos
Validación De Modelos
Técnicas De Validación Cruzada
Validación De Modelos
Métricas De Regresión
Validación De Modelos
Métricas De Clasificación
Validación De Modelos
Ajuste De Hiperparámetros
Validación De Modelos
Introducción A Pipelines
Pipelines Y Despliegue
Creación De Pipelines Básicos
Pipelines Y Despliegue
Preprocesamiento De Datos Con Pipelines
Pipelines Y Despliegue
Pipelines Y Validación Cruzada
Pipelines Y Despliegue
Pipelines Con Columntransformer
Pipelines Y Despliegue
Exportar E Importar Pipelines
Pipelines Y Despliegue
Objetivos de aprendizaje de esta lección
- Conversión de fechas en formato de texto a objetos datetime.
- Creación de índices temporales con DatetimeIndex.
- Acceso a atributos de fechas para extraer año, mes y día.
- Manejo de zonas horarias y conversiones entre ellas.
- Realización de operaciones aritméticas con fechas.
- Generación de secuencias de fechas con pd.date_range().
- Manipulación de frecuencias y períodos en series temporales.