时间序列之季节性

news2024/11/17 12:48:22

什么是季节性?

当一个时间序列的均值有规律的、周期性的变化时,我们就说这个时间序列表现出季节性。季节性的变化通常是遵循时间的——以一天、一周或一年为单位重复。

在这里插入图片描述

时间序列中的四种季节性模式

这里介绍两种季节性特征。一种适用于观测较少的季节,例如在一周中每日观测的序列;另一种是傅里叶特征,适用于观测较多的季节,例如在一年中每日观测的序列。


季节图和季节指标

类似于用移动平均图来发现时间序列的趋势,我们可以使用季节图来发现时间序列的季节模式。

季节性图将时间序列按固定周期分割成了片段,这些片段对应于一个相同的周期,这个周期就是我们想要观察的**“季节”**。下图为维基百科关于三角学文章的日浏览量的季节图,周期为一周。

在这里插入图片描述

该时间序列有一个明显的季节性模式,即工作日升高,周末较低。

季节指标是二元特征,表示时间序列水平的季节差异,将季节性时期视为分类特征并进行独热编码,就可以得到季节性指标。通过对一周中的天数进行独热编码,我们得到每周的季节性指标,即六个新的“虚拟特征”。(如果去掉其中一个指标,线性回归的效果会更好,这里剔除了星期一):

DateTuesdayWednesdayThursdayFridaySaturdaySunday
2016-01-040.00.00.00.00.00.0
2016-01-051.00.00.00.00.00.0
2016-01-060.01.00.00.00.00.0
2016-01-070.00.01.00.00.00.0
2016-01-080.00.00.01.00.00.0
2016-01-090.00.00.00.01.00.0
2016-01-100.00.00.00.00.01.0
2016-01-110.00.00.00.00.00.0

在训练集数据中加入季节性指标有助于模型区分季节期间的均值:

在这里插入图片描述

普通线性回归学习了季节中每个时间点的均值

傅里叶特征和周期图

傅里叶特征更适用于长季节的观测,它不会用独热编码的方式为每个日期创建一个特征,而是试图用几个特征来捕捉季节曲线的整体形状。

在这里插入图片描述

维基三角学序列的年度季节性

从图中我们可以发现三角学序列在不同频率上的重复:一年中三次长时间的上下运动,一年 52 次短时间的每周运动,也许还有其他频率。现在我们试图用傅里叶特征来捕捉一个季节内的这些频率,采用三角函数正弦和余弦的曲线。

傅里叶特征是一对正弦和余弦曲线,从最长的季节开始,每个潜在频率对应一对,模拟年度季节性的傅里叶对将具有的频率:每年一次、每年两次、每年三次,等等。

在这里插入图片描述

上图:每年一次的频率, 下图:每年两次的频率

如果我们将一组这样的正弦/余弦曲线添加到我们的训练数据中,线性回归算法将计算出适合目标序列中季节成分的权重。下图中给出了如何使用四个傅里叶对来模拟维基三角学序列中的年度季节性。

在这里插入图片描述

上图:四个傅里叶对的曲线,带回归系数的正弦和余弦之和, 下图:这些曲线的综合近似于季节模式

我们发现只需要 8 个特征(4 个正弦/余弦对)就可以很好地估计年度季节性,与此相比,季节性指标方法需要数百个特征(一年中的每一天特征)。通过傅里叶特征我们只模拟了季节性的“主效应”,通常需要在训练数据中添加更少的特征,这意味着减少了计算时间和降低了过拟合的风险。

用周期图选择傅里叶特征

应该在特征集中包含多少傅里叶对?通常我们用周期图来回答这个问题,周期图给出了时间序列中频率的强度,具体来说,下图中 y 轴上的值为 (a ** 2 + b ** 2) / 2,其中 ab 是该频率下的正弦和余弦的系数。

在这里插入图片描述

维基三角学序列的周期图

可以看出,从左到右,周期图在 Quarterly 之后下降,一年四次。这就是为什么我们选择了四个傅里叶对来模拟每年的季节,这里忽略了“每周”的频率,因为它更适合用独热编码的季节指标来建模。

计算傅里叶特征

尽管 statsmodel 库已经对傅里叶特征的计算进行了完美的封装,这里还是给出了逐步的计算过程,以便帮助我们加深对细节的了解,这里给出了如何从时间序列的索引中推到出一组傅里叶特征。

import numpy as np
import pandas as pd

def fourier_features(index, freq, order):
    time = np.arange(len(index), dtype=np.float32)
    k = 2 * np.pi * (1 / freq) * time
    features = {}
    for i in range(1, order+1):
        features.update({
            f"sin_{freq}_{i}": np.sin(i * k),
            f"cos_{freq}_{i}": np.cos(i * k),
        })
    return pd.DataFrame(features, index=index)

# 利用 4 个傅里叶特征对计算一年中每日观察的时间序列的季节性
# fourier_features(y, freq=365.25, order=4)

示例:隧道交通

这里定义了两个函数:seasonal_plotplot_periodogram

from pathlib import Path
from warnings import simplefilter

import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from sklearn.linear_model import LinearRegression
from statsmodels.tsa.deterministic import CalendarFourier, DeterministicProcess

simplefilter("ignore")

# Configuration
simplefilter("ignore")

sns.set(style="whitegrid")
plt.rc("figure", autolayout=True, figsize=(11, 5))
plt.rc(
    "axes",
    labelweight="bold",
    labelsize="large",
    titleweight="bold",
    titlesize=14,
    titlepad=10,
)
plot_params = dict(
    color="0.75",
    style=".-",
    markeredgecolor="0.25",
    markerfacecolor="0.25",
    legend=False,
)
%config InlineBackend.figure_format = "retina"


def seasonal_plot(X, y, period, freq, ax=None):
    if ax is None:
        _, ax = plt.subplots()
    palette = sns.color_palette("husl", n_colors=X[period].nunique(),)
    ax = sns.lineplot(
        x=freq,
        y=y,
        hue=period,
        data=X,
        ci=False,
        ax=ax,
        palette=palette,
        legend=False,
    )
    ax.set_title(f"Seasonal Plot ({period}/{freq})")
    for line, name in zip(ax.lines, X[period].unique()):
        y_ = line.get_ydata()[-1]
        ax.annotate(
            name,
            xy=(1, y_),
            xytext = (6, 6),
            color=line.get_color(),
            xycoords=ax.get_yaxis_transform(),
            textcoords="offset points",
            size=14,
            va="center",
        )
    return ax


def plot_periodogram(ts, detrend='linear', ax=None):
    from scipy.signal import periodogram
    fs = pd.Timedelta('365D') / pd.Timedelta('1D')
    freqencis, spectrum = periodogram(
        ts,
        fs=fs,
        detrend=detrend,
        window='boxcar',
        scaling='spectrum',
    )
    if ax is None:
        _, ax = plt.subplots()
    ax.step(freqencis, spectrum, color='purple')
    ax.set_xscale('log')
    ax.set_xticks([1, 2, 4, 6, 12, 26, 52, 104])
    ax.set_xticklabels(
        [
            'Annual (1)',
            'Semiannual (2)',
            'Quarterly (4)',
            'Bimonthly (6)',
            'Monthly (12)',
            'Biweekly (26)',
            'Weekly (52)',
            'Semiweekly (104)',
        ],
        rotation=30
    )
    ax.ticklabel_format(axis='y', style='sci', scilimits=(0, 0))
    ax.set_ylabel('Variance')
    ax.set_title('Periodogram')
    return ax


data_dir = Path('data/ts-course-data')
tunnel = pd.read_csv(data_dir / 'tunnel.csv', parse_dates=['Day'])
tunnel = tunnel.set_index('Day').to_period('D')
X = tunnel.copy()

# days within a week
X['day'] = X.index.dayofweek   # the x-axis (freq)
X['week'] = X.index.week       # the seasonal period (period)

# days within a year
X['dayofyear'] = X.index.dayofyear
X['year'] = X.index.year

fig, (ax0, ax1) = plt.subplots(2, 1, figsize=(11, 6))
seasonal_plot(X, y='NumVehicles', period='week', freq='day', ax=ax0)
seasonal_plot(X, y='NumVehicles', period='year', freq='dayofyear', ax=ax1)
<Axes: title={'center': 'Seasonal Plot (year/dayofyear)'}, xlabel='dayofyear', ylabel='NumVehicles'>

在这里插入图片描述

# 看一下周期图
plot_periodogram(tunnel.NumVehicles)
<Axes: title={'center': 'Periodogram'}, ylabel='Variance'>

在这里插入图片描述

从周期图可以发现:周季较强,年季较弱。周季的建模我们采用季节指标,年季的建模采用傅里叶特征,周期图在双月 Bimonthly(6) 和 Monthly(12) 之间下降,所以我们使用 10 个傅里叶对。季节性特征的创建使用 DeterministicProcess

from statsmodels.tsa.deterministic import CalendarFourier, DeterministicProcess

fourier = CalendarFourier(freq='A', order=10)      # 10 sin/cos pairs for 'A'nnual seasonality

dp = DeterministicProcess(
    index=tunnel.index,                        
    constant=True,                             # dummy feature for bias (y-intercept)
    order=1,                                   # trend (order 1 means linear)
    seasonal=True,                             # weekly seasonality (indicators)
    additional_terms=[fourier],                # annual seasonality (fourier)
    drop=True,                                 # drop terms to avoid collinearity
)

X = dp.in_sample()
X.head()
consttrends(2,7)s(3,7)s(4,7)s(5,7)s(6,7)s(7,7)sin(1,freq=A-DEC)cos(1,freq=A-DEC)sin(2,freq=A-DEC)cos(2,freq=A-DEC)sin(3,freq=A-DEC)cos(3,freq=A-DEC)sin(4,freq=A-DEC)cos(4,freq=A-DEC)sin(5,freq=A-DEC)cos(5,freq=A-DEC)sin(6,freq=A-DEC)cos(6,freq=A-DEC)sin(7,freq=A-DEC)cos(7,freq=A-DEC)sin(8,freq=A-DEC)cos(8,freq=A-DEC)sin(9,freq=A-DEC)cos(9,freq=A-DEC)sin(10,freq=A-DEC)cos(10,freq=A-DEC)
Day
2003-11-011.01.00.00.00.00.00.00.0-0.8674560.497513-0.863142-0.5049610.008607-0.9999630.871706-0.4900290.8587640.512371-0.0172130.999852-0.8758920.482508-0.854322-0.5197440.025818-0.9996670.880012-0.474951
2003-11-021.02.01.00.00.00.00.00.0-0.8587640.512371-0.880012-0.474951-0.043022-0.9990740.835925-0.5488430.8996310.4366510.0859650.996298-0.8115390.584298-0.917584-0.397543-0.128748-0.9916770.785650-0.618671
2003-11-031.03.00.01.00.00.00.00.0-0.8498170.527078-0.895839-0.444378-0.094537-0.9955210.796183-0.6050560.9338370.3576980.1882270.982126-0.7354170.677615-0.963471-0.267814-0.280231-0.9599330.668064-0.744104
2003-11-041.04.00.00.01.00.00.00.0-0.8406180.541628-0.910605-0.413279-0.145799-0.9893140.752667-0.6584020.9611300.2760970.2884820.957485-0.6486300.761104-0.991114-0.133015-0.425000-0.9051930.530730-0.847541
2003-11-051.05.00.00.00.01.00.00.0-0.8311710.556017-0.924291-0.381689-0.196673-0.9804690.705584-0.7086270.9813060.1924520.3856630.922640-0.5524350.833556-0.9999910.004304-0.559589-0.8287700.377708-0.925925
# 进行 90 天的预测
y = tunnel['NumVehicles']

model = LinearRegression(fit_intercept=False)
_ = model.fit(X, y)

y_pred = pd.Series(model.predict(X), index=y.index)
X_fore = dp.out_of_sample(steps=90)
y_fore = pd.Series(model.predict(X_fore), index=X_fore.index)

ax = y.plot(color='0.25', style='.', title='Tunnel Traffic - Seasonal Forecast')
ax = y_pred.plot(ax=ax, label='Seasonal')
ax = y_fore.plot(ax=ax, label='Seasonal Forecast', color='C3')
_  = ax.legend()

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1438346.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

告别mPDF迎来TCPDF和中文打印遇到的问题

mPDF是一个用PHP编写的开源PDF生成库。它最初由Claus Holler创建&#xff0c;于2004年发布。原来用开源软件打印中文没有问题&#xff0c;最近发现新的软件包中mPDF被TCPDF代替了&#xff0c;当然如果只用西文的PDF是没有发现问题&#xff0c;但要打印中文就有点抓瞎了如图1&am…

网络爬虫,使用存放在C的谷歌驱动报错

月 06, 2024 11:43:40 上午 org.openqa.selenium.os.OsProcess checkForError 严重: org.apache.commons.exec.ExecuteException: Execution failed (Exit value: -559038737. Caused by java.io.IOException: Cannot run program "C:\chromedriver121.exe" (in dir…

【Linux系统化学习】文件描述符fd

目录 基础IO预备知识 C语言文件接口 "w"的方式打开&#xff0c;fputs写入 以"a"的方式打开&#xff0c;fputs写入 使用位图传参 系统调用操作文件 open的使用 第一种形式 第二种形式 write() 文件描述符 文件描述符和进程的关系 默认的三个IO流…

Bagging的随机森林;Boosting的AdaBoost和GBDT

集成学习应用实践 import numpy as np import os %matplotlib inline import matplotlib import matplotlib.pyplot as plt plt.rcParams[axes.labelsize] 14 plt.rcParams[xtick.labelsize] 12 plt.rcParams[ytick.labelsize] 12 import warnings warnings.filterwarnin…

【Java】ArrayList和LinkedList的区别是什么

目录 1. 数据结构 2. 性能特点 3. 源码分析 4. 代码演示 5. 细节和使用场景 ArrayList 和 LinkedList 分别代表了两类不同的数据结构&#xff1a;动态数组和链表。它们都实现了 Java 的 List 接口&#xff0c;但是有着各自独特的特点和性能表现。 1. 数据结构 ArrayList…

微调实操二: 有监督微调(Supervised Finetuning)

1、背景 在上一章《微调实操一: 增量预训练(Pretraining)》中进行了第一阶段的增量专业知识训练,这篇开始实践一下指令微调的训练&#xff0c;在预训练模型基础上做指令精调&#xff0c;以对齐指令意图。通过输入中添加指令&#xff0c;使得模型可以将指令作为上下文的信息&am…

kmp算法板子及例题

对板子的详细解释见&#xff1a;pecco:kmp 板子 void get_pmt(const string& p) {//求pmt数组for (int i 1, j 0;i < p.size();i) {while (j && p[i] ! p[j])j pmt[j - 1];if (p[i] p[j])j;pmt[i] j;} }void kmp(const string& s, const string&…

亚信安慧AntDB零故障割接方案的实践

亚信安慧AntDB秉持着为客户提供最佳数据库解决方案的理念&#xff0c;不断探索并创新&#xff0c;最近取得了重大的突破。他们成功地研发出一种先进的数据库割接方案&#xff0c;实现了不停服、零故障的数据库割接操作&#xff0c;有效地将替换所带来的业务影响降至最低。 这一…

spring boot整合 cache 以redis服务 处理数据缓存 便捷开发

我们常规开发中 就是程序去数据库取数据 然后返回给客户端 但是 如果有些业务业务量非常庞大 不断访问数据库 性能就会非常糟糕 从而造成不好的用户体验 那么 我们自然就可以将数据查到缓存中 然后 用户访问 从缓存中取 这样就会大大提高用户的访问效率 之前 我的文章 java …

【Linux开发工具】gcc/g++的使用

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 1.前言2.gcc/g使用方…

python实现k路归并排序

从归并排序中可以衍生出来一个新的问题&#xff0c;关于k路归并排序&#xff0c;给定k个已经排好序的数组&#xff0c;每个数组含有n各元素&#xff0c;要求将这k个数组合并成一个排好序的大数组。在对两路排好序的数组进行归并时候&#xff0c;会用两个指针指向两个数组首元素…

单片机学习笔记---串口通信(2)

目录 串口内部结构 串口相关寄存器 串口控制寄存器SCON SM0和SM1 SM2 REN TB8和RB8 TI和RI 电源控制寄存器PCON SMOD 串口工作方式 方式0 方式0输出&#xff1a; 方式0输入 方式1 方式1输出。 方式1输入 方式2和方式3 方式2和方式3输出&#xff1a; 方式2和…

ArcGIS学习(五)坐标系-2

3.不同基准面坐标系之间的转换 在上一关中,我们学习了ArcGIS中的投影(投影栅格)工具,并以"WGS1984地理坐标系与WGS1984的UTM投影坐标系的转换”为例进行讲解。 "WGS1984地理坐标系与WGS1984的UTM投影坐标系的转换”代表的是同一个基准面下的两个坐标的转换。 …

jsp课程管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 课程管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

[office] Excel如何快速统一数字编号长度 #经验分享#其他

Excel如何快速统一数字编号长度 我们在办公室使用Excel统计数据的时候&#xff0c;经常会遇到第一列数据全部是数字编号&#xff0c;但是因为数字的位数不一样&#xff0c;长短不一的样子看起来不是很协调。那么如何快速统一数字编号长度呢&#xff1f;一起来了解一下吧 我们在…

11 插入排序和希尔排序

1. 插入排序 基本思想 直接插入排序是一种简单的插入排序法&#xff0c;基本思想&#xff1a; 把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完为止&#xff0c;得到一个新的有序序列 在玩扑克牌时&#xff0c;就用…

【Spring】Spring 对 Ioc 的实现

一、Ioc 控制反转 控制反转是一种思想 控制反转是为了降低程序耦合度&#xff0c;提高程序扩展力&#xff0c;达到 OCP 原则&#xff0c;达到 DIP 原则 控制反转&#xff0c;反转的是什么&#xff1f; 将对象的创建权利交出去&#xff0c;交给第三方容器负责 将对象和对象之…

高速接口PCB布局指南(五)高速差分信号布线(三)

高速接口PCB布局指南&#xff08;五&#xff09;高速差分信号布线&#xff08;三&#xff09; 1.表面贴装器件焊盘不连续性缓解2.信号线弯曲3.高速信号建议的 PCB 叠层设计4.ESD/EMI 注意事项5.ESD/EMI 布局规则 tips&#xff1a;资料主要来自网络&#xff0c;仅供学习使用。 …

SQL如何实现数据表行转列、列转行?

SQL行转列、列转行可以帮助我们更方便地处理数据&#xff0c;生成需要的报表和结果集。本文将介绍在SQL中如何实现数据表地行转列、列转行操作&#xff0c;以及实际应用示例。 这里通过表下面三张表进行举例 SQL创建数据库和数据表 数据表示例数据分别如下&#xff1a; data_…

算法提升——LeetCode123场双周赛总结

周赛题目 三角形类型 II 给你一个下标从0开始长度为3的整数数组nums&#xff0c;需要用它们来构造三角形。 如果一个三角形的所有边长度相等&#xff0c;那么这个三角形称为equilateral。 如果一个三角形恰好有两条边长度相等&#xff0c;那么这个三角形称为isosceles。 如…