第 5 篇:初试牛刀 - 简单的预测方法

第 5 篇:初试牛刀 - 简单的预测方法

经过前面四篇的学习,我们已经具备了处理时间序列数据的基本功:加载、可视化、分解以及处理平稳性。现在,激动人心的时刻到来了——我们要开始尝试预测 (Forecasting) 未来!

预测是时间序列分析最核心的应用之一。虽然存在很多复杂的预测模型,但万丈高楼平地起,一些看似简单的预测方法不仅容易理解和实现,有时效果还出奇地好,并且它们是理解更高级模型的重要基础。

本篇,我们将学习几种“入门级”的时间序列预测方法:

  1. 预测的基本概念: 区分训练与预测,划分数据集。
  2. 朴素预测 (Naive Forecast): 最简单的方法。
  3. 简单平均法 (Simple Average): 用历史平均值预测。
  4. 移动平均法 (Moving Average): 用近期历史平均值预测。
  5. (可选) 季节性朴素预测 (Seasonal Naive Forecast): 考虑季节性的朴素方法。

我们将用 Python 实现这些方法,并看看它们的预测效果如何。

预测的基本概念

在进行预测之前,我们需要明确两个基本概念:

  • 拟合 (In-sample Fit) vs. 预测 (Out-of-sample Forecast):

    • 拟合: 使用模型去“解释”或“匹配”我们已经拥有的历史数据。
    • 预测: 使用模型去推断我们尚未观测到未来数据点。这才是我们通常意义上的“预测”。
  • 训练集 (Training Set) vs. 测试集 (Test Set):

    • 为了评估模型的真实预测能力,我们不能用全部历史数据来构建模型,然后又用这些数据来评估。这就像考试前知道了所有答案。

    • 标准的做法是:将历史数据划分为两部分:

      • 训练集: 用于构建(或“训练”)我们的预测模型。模型只能看到这部分数据。
      • 测试集: 用于评估模型的预测效果。模型在训练阶段看不到这部分数据。我们将模型的预测结果与测试集的真实值进行比较。
    • 对于时间序列,通常是按时间顺序划分,较早的数据作为训练集,较晚的数据作为测试集。例如,用前 80% 的数据训练,后 20% 的数据测试。

最简单的预测模型

现在,让我们来认识几位简单但重要的“预测选手”。我们将继续使用之前的月度 CO2 数据(或你可以替换成自己的数据)。

import pandas as pd
import numpy as np
import statsmodels.api as sm
import matplotlib.pyplot as plt
import seaborn as sns# --- 数据准备 ---
# 1. 加载数据
data = sm.datasets.co2.load_pandas().data
data['co2'].interpolate(inplace=True)
monthly_data = data.resample('M').mean()# 2. 划分训练集和测试集 (例如,最后 2 年作为测试集)
train_data = monthly_data[:-24] # 除去最后 24 个月
test_data = monthly_data[-24:]  # 最后 24 个月print(f"训练集范围: {train_data.index.min()} to {train_data.index.max()}")
print(f"测试集范围: {test_data.index.min()} to {test_data.index.max()}")# --- 可视化划分结果 (可选) ---
plt.figure(figsize=(12, 6))
plt.plot(train_data.index, train_data['co2'], label='Train Data')
plt.plot(test_data.index, test_data['co2'], label='Test Data (Actual)')
plt.title('CO2 Data: Train/Test Split')
plt.xlabel('Date')
plt.ylabel('CO2 Concentration')
plt.legend()
plt.show()

在这里插入图片描述
在这里插入图片描述

1. 朴素预测 (Naive Forecast)

  • 逻辑: 假设未来跟现在(最近的已知值)一样。预测下一期的值就等于训练集中最后一期的实际值。
    • Ŷ(t+1) = Y(t_last_train)
  • 优点: 极其简单,无需参数,是一个重要的基准 (Baseline) 模型(任何更复杂的模型都应该比它做得更好才有意义)。
  • 缺点: 无法捕捉趋势和季节性,对波动敏感。
  • 实现:
# 获取训练集最后一个值
last_train_value = train_data['co2'].iloc[-1]# 创建测试集长度的预测值,所有值都等于 last_train_value
naive_forecast = pd.Series([last_train_value] * len(test_data), index=test_data.index)print("\n朴素预测 (Naive Forecast):")
print(naive_forecast.head())

在这里插入图片描述

2. 简单平均法 (Simple Average)

  • 逻辑: 假设未来会和历史的平均水平一样。预测未来所有期的值都等于训练集中所有数据的平均值
    • Ŷ(t+k) = mean(Y_train) for all k > 0
  • 优点: 简单,考虑了所有历史信息。
  • 缺点: 忽略了时间序列的演变(趋势、季节性),对早期数据和近期数据给予同等权重。如果序列有明显趋势,效果通常很差。
  • 实现:
# 计算训练集平均值
train_mean = train_data['co2'].mean()# 创建测试集长度的预测值,所有值都等于 train_mean
simple_avg_forecast = pd.Series([train_mean] * len(test_data), index=test_data.index)print("\n简单平均法预测 (Simple Average Forecast):")
print(simple_avg_forecast.head())

在这里插入图片描述

3. 移动平均法 (Moving Average)

  • 逻辑: 只考虑最近的一段历史。预测下一期的值等于训练集中最近 N 个数据点的平均值。N 是需要我们指定的窗口大小 (Window Size)
    • Ŷ(t+1) = mean(Y(t), Y(t-1), ..., Y(t-N+1))
  • 优点: 比简单平均法更关注近期变化,能一定程度平滑短期波动。
  • 缺点: 无法很好地处理趋势和季节性。预测值对窗口大小 N 很敏感。它本质上是对近期水平的估计,不是趋势预测。严格来说,移动平均更多用于平滑数据或作为更复杂模型的组件,直接用于多步预测效果有限(通常只预测一步,或者假设未来多步都等于这个平均值)。
  • 实现 (预测未来所有期都等于最后窗口的平均值):
# 设置移动平均窗口大小 (例如,最近 12 个月)
window_size = 12# 计算训练集最后 N 个点的平均值
moving_avg = train_data['co2'].iloc[-window_size:].mean()# 创建测试集长度的预测值
moving_avg_forecast = pd.Series([moving_avg] * len(test_data), index=test_data.index)print(f"\n移动平均法预测 (Moving Average Forecast, N={window_size}):")
print(moving_avg_forecast.head())

在这里插入图片描述

4. (可选) 季节性朴素预测 (Seasonal Naive Forecast)

  • 逻辑: 假设下个季节/周期的同一时间点会和上个季节/周期一样。例如,预测明年 1 月的值等于今年 1 月的值。
    • Ŷ(t+k) = Y(t+k-s),其中 s 是季节周期长度 (e.g., 12 for monthly data with annual seasonality)。
  • 优点: 考虑了季节性,对于有强季节性模式的数据可能效果不错。也是一个重要的基准。
  • 缺点: 忽略了趋势和其他变化。
  • 实现 (需要访问训练集中更早的数据):
# 季节周期
seasonality = 12seasonal_naive_forecast_list = []
for i in range(len(test_data)):if i >= seasonality:# 使用测试集前一个季节周期的预测值seasonal_value = test_data['co2'].iloc[i - seasonality]else:# 不足一个周期,用训练集最后一个完整周期前的值seasonal_value = train_data['co2'].iloc[-seasonality + i]seasonal_naive_forecast_list.append(seasonal_value)seasonal_naive_forecast = pd.Series(seasonal_naive_forecast_list, index=test_data.index)print("\n季节性朴素预测 (Seasonal Naive Forecast):")
print(seasonal_naive_forecast.head())

在这里插入图片描述

可视化预测结果

光看数字不够直观,让我们把预测结果和测试集的真实值画在一起比较一下。

plt.figure(figsize=(14, 8))# 绘制训练数据
plt.plot(train_data.index, train_data['co2'], label='Train Data')# 绘制测试数据 (真实值)
plt.plot(test_data.index, test_data['co2'], label='Test Data (Actual)', color='black', linewidth=2)# 绘制各种预测结果
plt.plot(test_data.index, naive_forecast, label='Naive Forecast', linestyle='--')
plt.plot(test_data.index, simple_avg_forecast, label='Simple Average Forecast', linestyle='--')
plt.plot(test_data.index, moving_avg_forecast, label=f'Moving Average (N={window_size}) Forecast', linestyle='--')
plt.plot(test_data.index, seasonal_naive_forecast, label='Seasonal Naive Forecast', linestyle='--')# 添加标题和标签
plt.title('Comparison of Simple Forecast Methods')
plt.xlabel('Date')
plt.ylabel('CO2 Concentration')
plt.legend()
plt.tight_layout()
plt.show()

在这里插入图片描述

解读图形:

  • 观察每种预测方法(虚线)与测试集真实值(黑色实线)的接近程度。
  • 对于 CO2 数据(有明显趋势和季节性):
    • 朴素预测简单平均 显然跟不上趋势,预测线是平的。
    • 移动平均 (N=12) 也基本是平的,因为它只是最后12个月的平均,没有预测趋势。
    • 季节性朴素预测 捕捉到了季节波动,但没有捕捉到整体上升的趋势。
  • 这表明,对于具有明显趋势和/或季节性的数据,这些简单方法可能不足以做出准确预测。它们更多是作为后续更复杂模型的比较基准

小结

今天我们迈出了预测的第一步:

  • 理解了预测的目标是推断未来值,以及训练集/测试集划分的重要性。
  • 学习并实现了四种简单的预测方法:
    • 朴素预测 (Naive): Ŷ(t+1) = Y(t)
    • 简单平均法 (Simple Average): Ŷ(t+k) = mean(Y_train)
    • 移动平均法 (Moving Average): Ŷ(t+1) = mean(Y(t), ..., Y(t-N+1))
    • 季节性朴素预测 (Seasonal Naive): Ŷ(t+k) = Y(t+k-s)
  • 通过可视化比较了这些方法在测试集上的表现,并认识到它们作为基准模型的价值。

下一篇预告

我们已经做出了几种预测,但是怎么量化地评价哪个预测“更好”呢?光靠看图是不够严谨的。下一篇,我们将学习常用的预测评估指标 (Evaluation Metrics),如 MAE, MSE, RMSE 等,它们将帮助我们用数字来衡量预测的准确性。

准备好给你的预测打分了吗?敬请期待!


(尝试用你自己的时间序列数据跑一遍这些简单预测方法,看看哪个效果相对最好?窗口大小 N 对移动平均预测影响大吗?欢迎分享!)

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

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

相关文章

从代码学习深度学习 - 学习率调度器 PyTorch 版

文章目录 前言一、理论背景二、代码解析2.1. 基本问题和环境设置2.2. 训练函数2.3. 无学习率调度器实验2.4. SquareRootScheduler 实验2.5. FactorScheduler 实验2.6. MultiFactorScheduler 实验2.7. CosineScheduler 实验2.8. 带预热的 CosineScheduler 实验三、结果对比与分析…

k8s 基础入门篇之开启 firewalld

前面在部署k8s时,都是直接关闭的防火墙。由于生产环境需要开启防火墙,只能放行一些特定的端口, 简单记录一下过程。 1. firewall 与 iptables 的关系 1.1 防火墙(Firewall) 定义: 防火墙是网络安全系统&…

RSS 2025|苏黎世提出「LLM-MPC混合架构」增强自动驾驶,推理速度提升10.5倍!

论文题目:Enhancing Autonomous Driving Systems with On-Board Deployed Large Language Models 论文作者:Nicolas Baumann,Cheng Hu,Paviththiren Sivasothilingam,Haotong Qin,Lei Xie,Miche…

list的学习

list的介绍 list文档的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一…

生物信息学技能树(Bioinformatics)与学习路径

李升伟 整理 生物信息学是一门跨学科领域,涉及生物学、计算机科学以及统计学等多个方面。以下是关于生物信息学的学习路径及相关技能的详细介绍。 一、基础理论知识 1. 生物学基础知识 需要掌握分子生物学、遗传学、细胞生物学等相关概念。 对基因组结构、蛋白质…

AOSP Android14 Launcher3——远程窗口动画关键类SurfaceControl详解

在 Launcher3 执行涉及其他应用窗口(即“远程窗口”)的动画时,例如“点击桌面图标启动应用”或“从应用上滑回到桌面”的过渡动画,SurfaceControl 扮演着至关重要的角色。它是实现这些跨进程、高性能、精确定制动画的核心技术。 …

超详细实现单链表的基础增删改查——基于C语言实现

文章目录 1、链表的概念与分类1.1 链表的概念1.2 链表的分类 2、单链表的结构和定义2.1 单链表的结构2.2 单链表的定义 3、单链表的实现3.1 创建新节点3.2 头插和尾插的实现3.3 头删和尾删的实现3.4 链表的查找3.5 指定位置之前和之后插入数据3.6 删除指定位置的数据和删除指定…

17.整体代码讲解

从入门AI到手写Transformer-17.整体代码讲解 17.整体代码讲解代码 整理自视频 老袁不说话 。 17.整体代码讲解 代码 import collectionsimport math import torch from torch import nn import os import time import numpy as np from matplotlib import pyplot as plt fro…

前端性能优化:所有权转移

前端性能优化:所有权转移 在学习rust过程中,学到了所有权概念,于是便联想到了前端,前端是否有相关内容,于是进行了一些实验,并整理了这些内容。 所有权转移(Transfer of Ownership)…

Missashe考研日记-day23

Missashe考研日记-day23 0 写在前面 博主前几天有事回家去了,断更几天了不好意思,就当回家休息一下调整一下状态了,今天接着开始更新。虽然每天的博客写的内容不算多,但其实还是挺费时间的,比如这篇就花了我40多分钟…

Docker 中将文件映射到 Linux 宿主机

在 Docker 中,有多种方式可以将文件映射到 Linux 宿主机,以下是常见的几种方法: 使用-v参数• 基本语法:docker run -v [宿主机文件路径]:[容器内文件路径] 容器名称• 示例:docker run -it -v /home/user/myfile.txt:…

HarmonyOS-ArkUI-动画分类简介

本文的目的是,了解一下HarmonyOS动画体系中的分类。有个大致的了解即可。 动效与动画简介 动画,是客户端提升界面交互用户体验的一个重要的方式。可以使应用程序更加生动灵越,提高用户体验。 HarmonyOS对于界面的交互方面,围绕回归本源的设计理念,打造自然,流畅品质一提…

C++如何处理多线程环境下的异常?如何确保资源在异常情况下也能正确释放

多线程编程的基本概念与挑战 多线程编程的核心思想是将程序的执行划分为多个并行运行的线程,每个线程可以独立处理任务,从而充分利用多核处理器的性能优势。在C中,开发者可以通过std::thread创建线程,并使用同步原语如std::mutex、…

区间选点详解

步骤 operator< 的作用在 C 中&#xff0c; operator< 是一个运算符重载函数&#xff0c;它定义了如何比较两个对象的大小。在 std::sort 函数中&#xff0c;它会用到这个比较函数来决定排序的顺序。 在 sort 中&#xff0c;默认会使用 < 运算符来比较两个对象…

前端配置代理解决发送cookie问题

场景&#xff1a; 在开发任务管理系统时&#xff0c;我遇到了一个典型的身份认证问题&#xff1a;​​用户登录成功后&#xff0c;调获取当前用户信息接口却提示"用户未登录"​​。系统核心流程如下&#xff1a; ​​用户登录​​&#xff1a;调用 /login 接口&…

8.1 线性变换的思想

一、线性变换的概念 当一个矩阵 A A A 乘一个向量 v \boldsymbol v v 时&#xff0c;它将 v \boldsymbol v v “变换” 成另一个向量 A v A\boldsymbol v Av. 输入 v \boldsymbol v v&#xff0c;输出 T ( v ) A v T(\boldsymbol v)A\boldsymbol v T(v)Av. 变换 T T T…

【java实现+4种变体完整例子】排序算法中【冒泡排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格

以下是冒泡排序的详细解析&#xff0c;包含基础实现、常见变体的完整代码示例&#xff0c;以及各变体的对比表格&#xff1a; 一、冒泡排序基础实现 原理 通过重复遍历数组&#xff0c;比较相邻元素并交换逆序对&#xff0c;逐步将最大值“冒泡”到数组末尾。 代码示例 pu…

系统架构设计(二):基于架构的软件设计方法ABSD

“基于架构的软件设计方法”&#xff08;Architecture-Based Software Design, ABSD&#xff09;是一种通过从软件架构层面出发指导详细设计的系统化方法。它旨在桥接架构设计与详细设计之间的鸿沟&#xff0c;确保系统的高层结构能够有效指导后续开发。 ABSD 的核心思想 ABS…

Office文件内容提取 | 获取Word文件内容 |Javascript提取PDF文字内容 |PPT文档文字内容提取

关于Office系列文件文字内容的提取 本文主要通过接口的方式获取Office文件和PDF、OFD文件的文字内容。适用于需要获取Word、OFD、PDF、PPT等文件内容的提取实现。例如在线文字统计以及论文文字内容的提取。 一、提取Word及WPS文档的文字内容。 支持以下文件格式&#xff1a; …

Cesium学习笔记——dem/tif地形的分块与加载

前言 在Cesium的学习中&#xff0c;学会读文档十分重要&#xff01;&#xff01;&#xff01;在这里附上Cesium中英文文档1.117。 在Cesium项目中&#xff0c;在平坦坦地球中加入三维地形不仅可以增强真实感与可视化效果&#xff0c;还可以​​提升用户体验与交互性&#xff0c…