Detaillierte Python-Implementierung von Zeitreihen-Glättungsmethoden: gleitender Durchschnitt, lineare exponentielle Glättung, quadratische exponentielle Glättung und kubische exponentielle Glättung
1. Glättungsmethode
Zu den häufig verwendeten Glättungsmethoden gehören:
gleitender Durchschnitt
Erste exponentielle Glättung, zweite exponentielle Glättung, kubische exponentielle Glättung
Die spezifische Theorie ist leichter zu verstehen, Sie können sich auf Folgendes beziehen:
https://zhuanlan.zhihu.com/p/441373033
https://zhuanlan.zhihu.com/p/78848809
2. Python-Implementierung
Die folgenden Schreibmethoden werden alle im Streaming-Verfahren geschrieben, d. h. ein Datentyp wird verarbeitet und eine Art von Streaming-Daten wird verarbeitet.
2.1 Gleitender Durchschnitt
class MovAvgSmoothing(object):
def __init__(self, window_size=7):
self.window_size = window_size
self.data_queue = []
def update(self, data):
if len(self.data_queue) == self.window_size:
del self.data_queue[0]
self.data_queue.append(data)
return sum(self.data_queue) / len(self.data_queue)
2.2 Exponentielle Glättung
2.2.1 Exponentielle Glättung erster Ordnung
class ExpSmoothing(object):
def __init__(self, alpha=0.9):
self.alpha = alpha
self.prev_smooth = None
def update(self, data):
if self.prev_smooth is None:
self.prev_smooth = data
return data
else:
smooth = self.alpha * data + (1 - self.alpha) * self.prev_smooth
self.prev_smooth = smooth
return smooth
2.2.2 Quadratische exponentielle Glättung
"""
Holt指数平滑,方法中包含一个预测方程和两个平滑方程(水平平滑方程+趋势预测方程)
趋势部分又可分为加性趋势和乘性趋势
对于较大时间步长的预测,趋势可能不会无限延长,就需要抑制这种趋势,加性趋势和乘性趋势的抑制分别对应加性抑制(抑制线性趋势)、乘性抑制(抑制指数趋势
"""
class SmoothMode(Enum):
Addition = "add mode"
Multiplication = "multiply mode"
class DoubleExpSmoothing(object):
def __init__(self, alpha=0.5, beta=0.5, mode=SmoothMode.Addition):
self.alpha = alpha
self.beta = beta
self.prev_smooth = None
self.prev_trend = None
self.mode = mode
def update(self, data):
if self.prev_smooth is None:
self.prev_smooth = data
return data
elif self.prev_trend is None:
smooth = None
if self.mode == SmoothMode.Addition:
self.prev_trend = data - self.prev_smooth
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth + self.prev_trend)
elif self.mode == SmoothMode.Multiplication:
self.prev_trend = data / self.prev_smooth
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth * self.prev_trend)
self.prev_smooth = smooth
return smooth
else:
trend = None
smooth = None
if self.mode == SmoothMode.Addition:
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth + self.prev_trend)
trend = self.beta * (smooth - self.prev_smooth) + (1 - self.beta) * self.prev_trend
elif self.mode == SmoothMode.Multiplication:
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth * self.prev_trend)
trend = self.beta * (smooth / self.prev_smooth) + (1 - self.beta) * self.prev_trend
self.prev_smooth = smooth
self.prev_trend = trend
return smooth
2.2.3 Kubische exponentielle Glättung
"""
Holt-Winters加法模型(Holt-Winters指数平滑)
方法中包含一个预测方程和三个平滑方程 (一个用于水平,一个用于趋势,一个用于季节性分量)
当季节变化在时间序列中大致保持不变时,通常选择加法模型
"""
class SmoothMode(Enum):
Addition = "add mode"
Multiplication = "multiply mode"
class TripleExpSmoothing(object):
def __init__(self, alpha=0.5, beta=0.5, gamma=0.5, m=12, mode=SmoothMode.Addition):
self.alpha = alpha
self.beta = beta
self.gamma = gamma
self.m = m
self.prev_smooth = None
self.prev_trend = None
self.seasonal = [0] * m
self.mode = mode
def update(self, data):
if self.prev_smooth is None:
self.prev_smooth = data
return data
elif self.prev_trend is None:
trend, smooth = None, None
if self.mode == SmoothMode.Addition:
trend = data - self.prev_smooth
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth + trend)
elif self.mode == SmoothMode.Multiplication:
trend = data / self.prev_smooth
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth + trend)
self.prev_smooth = smooth
self.prev_trend = trend
return smooth
else:
season, trend, smooth = None, None, None
pre_m_season = self.seasonal[len(self.seasonal) - self.m]
if self.mode == SmoothMode.Addition:
smooth = self.alpha * (data - pre_m_season) + (1 - self.alpha) * (self.prev_smooth + self.prev_trend)
trend = self.beta * (smooth - self.prev_smooth) + (1 - self.beta) * self.prev_trend
season = self.gamma * (data - self.prev_smooth - self.prev_trend) + (1 - self.gamma) * pre_m_season
elif self.mode == SmoothMode.Multiplication:
smooth = self.alpha * (data / pre_m_season) + (1 - self.alpha) * (self.prev_smooth + self.prev_trend)
trend = self.beta * (smooth - self.prev_smooth) + (1 - self.beta) * self.prev_trend
season = self.gamma * (data / (self.prev_smooth + self.prev_trend)) + (1 - self.gamma) * pre_m_season
self.seasonal.append(season)
self.season_garbage_collection()
self.prev_smooth, self.prev_trend = smooth, trend
return smooth
# 60s 一个点,一天1440,周期如果是一周则是1440*7
def season_garbage_collection(self):
if len(self.seasonal) >= 1440 * 7:
self.seasonal = self.seasonal[-1440 * 7:]
3. Einheitliche Verwaltung
Sie können eine Klasse verwenden, um diese Glättungsmethoden dynamisch und flexibel zu verwalten und dann basierend auf der verwendeten Planung auszuwählen, welche verwendet werden soll.
class MovSmoothManager(object):
def __init__(self, m):
self.avg_smooth = MovAvgSmoothing(window_size=3)
self.exp_smooth = ExpSmoothing(alpha=0.75)
self.double_exp_smooth_add = DoubleExpSmoothing(alpha=0.75, beta=0.75)
self.double_exp_smooth_multiply = DoubleExpSmoothing(alpha=0.75, beta=0.75, mode=SmoothMode.Multiplication)
self.triple_exp_smooth_add = TripleExpSmoothing(alpha=0.75, beta=0.75, gamma=0.75, m=m)
self.triple_exp_smooth_multiply = TripleExpSmoothing(alpha=0.75, beta=0.75, gamma=0.75, m=m, mode=SmoothMode.Multiplication)
def update_data(self, fea_pd: pd.DataFrame, fea_cols):
smooth_pd = fea_pd.copy(deep=True)
smooth_fea = ['avgSmooth', 'expSmooth', 'doubleExpSmoothAdd', 'doubleExpSmoothMultiply',
'tripleExpSmoothAdd', 'tripleExpSmoothMultiply']
smooth_data = {}
for fea_col in fea_cols:
smooth_pd['avgSmooth'] = smooth_pd[fea_col].apply(lambda x: self.avg_smooth.update(x))
smooth_pd['expSmooth'] = smooth_pd[fea_col].apply(lambda x: self.exp_smooth.update(x))
smooth_pd['doubleExpSmoothAdd'] = smooth_pd[fea_col].apply(lambda x: self.double_exp_smooth_add.update(x))
smooth_pd['doubleExpSmoothMultiply'] = smooth_pd[fea_col].apply(lambda x: self.double_exp_smooth_multiply.update(x))
smooth_pd['tripleExpSmoothAdd'] = smooth_pd[fea_col].apply(lambda x: self.triple_exp_smooth_add.update(x))
smooth_pd['tripleExpSmoothMultiply'] = smooth_pd[fea_col].apply(lambda x: self.triple_exp_smooth_multiply.update(x))
smooth_data[fea_col] = smooth_pd[smooth_fea]
return smooth_data
4. Gesamtcode
from enum import Enum
import pandas as pd
class SmoothMode(Enum):
Addition = "add mode"
Multiplication = "multiply mode"
class MovAvgSmoothing(object):
def __init__(self, window_size=7):
self.window_size = window_size
self.data_queue = []
def update(self, data):
if len(self.data_queue) == self.window_size:
del self.data_queue[0]
self.data_queue.append(data)
return sum(self.data_queue) / len(self.data_queue)
class ExpSmoothing(object):
def __init__(self, alpha=0.9):
self.alpha = alpha
self.prev_smooth = None
def update(self, data):
if self.prev_smooth is None:
self.prev_smooth = data
return data
else:
smooth = self.alpha * data + (1 - self.alpha) * self.prev_smooth
self.prev_smooth = smooth
return smooth
"""
Holt指数平滑,方法中包含一个预测方程和两个平滑方程(水平平滑方程+趋势预测方程)
趋势部分又可分为加性趋势和乘性趋势
对于较大时间步长的预测,趋势可能不会无限延长,就需要抑制这种趋势,加性趋势和乘性趋势的抑制分别对应加性抑制(抑制线性趋势)、乘性抑制(抑制指数趋势
"""
class DoubleExpSmoothing(object):
def __init__(self, alpha=0.5, beta=0.5, mode=SmoothMode.Addition):
self.alpha = alpha
self.beta = beta
self.prev_smooth = None
self.prev_trend = None
self.mode = mode
def update(self, data):
if self.prev_smooth is None:
self.prev_smooth = data
return data
elif self.prev_trend is None:
smooth = None
if self.mode == SmoothMode.Addition:
self.prev_trend = data - self.prev_smooth
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth + self.prev_trend)
elif self.mode == SmoothMode.Multiplication:
self.prev_trend = data / self.prev_smooth
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth * self.prev_trend)
self.prev_smooth = smooth
return smooth
else:
trend = None
smooth = None
if self.mode == SmoothMode.Addition:
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth + self.prev_trend)
trend = self.beta * (smooth - self.prev_smooth) + (1 - self.beta) * self.prev_trend
elif self.mode == SmoothMode.Multiplication:
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth * self.prev_trend)
trend = self.beta * (smooth / self.prev_smooth) + (1 - self.beta) * self.prev_trend
self.prev_smooth = smooth
self.prev_trend = trend
return smooth
"""
Holt-Winters加法模型(Holt-Winters指数平滑)
方法中包含一个预测方程和三个平滑方程 (一个用于水平,一个用于趋势,一个用于季节性分量)
当季节变化在时间序列中大致保持不变时,通常选择加法模型
"""
class TripleExpSmoothing(object):
def __init__(self, alpha=0.5, beta=0.5, gamma=0.5, m=12, mode=SmoothMode.Addition):
self.alpha = alpha
self.beta = beta
self.gamma = gamma
self.m = m
self.prev_smooth = None
self.prev_trend = None
self.seasonal = [0] * m
self.mode = mode
def update(self, data):
if self.prev_smooth is None:
self.prev_smooth = data
return data
elif self.prev_trend is None:
trend, smooth = None, None
if self.mode == SmoothMode.Addition:
trend = data - self.prev_smooth
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth + trend)
elif self.mode == SmoothMode.Multiplication:
trend = data / self.prev_smooth
smooth = self.alpha * data + (1 - self.alpha) * (self.prev_smooth + trend)
self.prev_smooth = smooth
self.prev_trend = trend
return smooth
else:
season, trend, smooth = None, None, None
pre_m_season = self.seasonal[len(self.seasonal) - self.m]
if self.mode == SmoothMode.Addition:
smooth = self.alpha * (data - pre_m_season) + (1 - self.alpha) * (self.prev_smooth + self.prev_trend)
trend = self.beta * (smooth - self.prev_smooth) + (1 - self.beta) * self.prev_trend
season = self.gamma * (data - self.prev_smooth - self.prev_trend) + (1 - self.gamma) * pre_m_season
elif self.mode == SmoothMode.Multiplication:
smooth = self.alpha * (data / pre_m_season) + (1 - self.alpha) * (self.prev_smooth + self.prev_trend)
trend = self.beta * (smooth - self.prev_smooth) + (1 - self.beta) * self.prev_trend
season = self.gamma * (data / (self.prev_smooth + self.prev_trend)) + (1 - self.gamma) * pre_m_season
self.seasonal.append(season)
self.season_garbage_collection()
self.prev_smooth, self.prev_trend = smooth, trend
return smooth
# 60s 一个点,一天1440,周期如果是一周则是1440*7
def season_garbage_collection(self):
if len(self.seasonal) >= 1440 * 7:
self.seasonal = self.seasonal[-1440 * 7:]
class MovSmoothManager(object):
def __init__(self, m):
self.avg_smooth = MovAvgSmoothing(window_size=3)
self.exp_smooth = ExpSmoothing(alpha=0.75)
self.double_exp_smooth_add = DoubleExpSmoothing(alpha=0.75, beta=0.75)
self.double_exp_smooth_multiply = DoubleExpSmoothing(alpha=0.75, beta=0.75, mode=SmoothMode.Multiplication)
self.triple_exp_smooth_add = TripleExpSmoothing(alpha=0.75, beta=0.75, gamma=0.75, m=m)
self.triple_exp_smooth_multiply = TripleExpSmoothing(alpha=0.75, beta=0.75, gamma=0.75, m=m, mode=SmoothMode.Multiplication)
def update_data(self, fea_pd: pd.DataFrame, fea_cols):
smooth_pd = fea_pd.copy(deep=True)
smooth_fea = ['avgSmooth', 'expSmooth', 'doubleExpSmoothAdd', 'doubleExpSmoothMultiply',
'tripleExpSmoothAdd', 'tripleExpSmoothMultiply']
smooth_data = {}
for fea_col in fea_cols:
smooth_pd['avgSmooth'] = smooth_pd[fea_col].apply(lambda x: self.avg_smooth.update(x))
smooth_pd['expSmooth'] = smooth_pd[fea_col].apply(lambda x: self.exp_smooth.update(x))
smooth_pd['doubleExpSmoothAdd'] = smooth_pd[fea_col].apply(lambda x: self.double_exp_smooth_add.update(x))
smooth_pd['doubleExpSmoothMultiply'] = smooth_pd[fea_col].apply(lambda x: self.double_exp_smooth_multiply.update(x))
smooth_pd['tripleExpSmoothAdd'] = smooth_pd[fea_col].apply(lambda x: self.triple_exp_smooth_add.update(x))
smooth_pd['tripleExpSmoothMultiply'] = smooth_pd[fea_col].apply(lambda x: self.triple_exp_smooth_multiply.update(x))
smooth_data[fea_col] = smooth_pd[smooth_fea]
return smooth_data
Literatur-Empfehlungen:
Meine Rekrutierungsfreigabe für die Internetschule 2022
Meine Zusammenfassung für 2021
Eine kurze Diskussion über den Unterschied zwischen Algorithmuspositionen und Entwicklungspositionen
Gehaltsübersicht für die Rekrutierung von Internetschulen im Bereich Forschung und Entwicklung
Öffentliches Konto:KI-Schneckenauto
Bleiben Sie bescheiden, bleiben Sie diszipliniert und verbessern Sie sich weiter
Senden Sie [Snail], um eine Kopie von „Hand-in-Hand AI Project“ (AI Snail Cart) zu erhalten.
Senden Sie [1222], um eine gute Leetcode-Testnotiz zu erhalten
Senden Sie [Vier klassische Bücher über KI], um vier klassische KI-E-Books zu erhalten