news 2026/9/8 23:22:04

在 ML-For-Beginners 中构建全新的 ARIMA 模型:从新数据准备、可视化到 MAPE 精度评估的完整实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
在 ML-For-Beginners 中构建全新的 ARIMA 模型:从新数据准备、可视化到 MAPE 精度评估的完整实战

在 ML-For-Beginners 中构建全新的 ARIMA 模型:从新数据准备、可视化到 MAPE 精度评估的完整实战

【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners

导读

本指南以机器学习初学者课程 ML-For-Beginners 中 7-TimeSeries/2-ARIMA/assignment.md(保加利亚语译本位于 translations/bg/7-TimeSeries/2-ARIMA/assignment.md,英文原版位于 translations/en/7-TimeSeries/2-ARIMA/assignment.md)所布置的实践作业为核心主题。该作业要求学习者:在课程示例 ARIMA 模型之外,用全新数据再构建一个 ARIMA 模型,把全过程注释在 Jupyter Notebook 中,完成数据与模型的可视化,并采用 MAPE(平均绝对百分比误差)检验模型精度。本文将把这份作业拆解为可直接照做的技术路线,结合仓库中能量负荷(energy load)数据的完整参考流水线,说明如何正确切分时间序列、缩放数据、确定(p,d,q)与季节阶数、执行 walk-forward 验证并解读 MAPE,最终交付一份能匹配评分表中“优秀”档位的高质量 Notebook。

作业要求拆解与评分标准

先精确理解作业本身。原文指令只有一段核心描述:你已经在课程中构建过一个 ARIMA 模型,现在请用新鲜的数据再构建一个新模型(可尝试 Duke 大学提供的时间序列数据集之一),把工作注释在 notebook 中,可视化数据与模型,并用MAPE检验其精度。

配套的评分表(Rubric)是判断完成度的关键,对应关系如下:

评分标准优秀(Exemplary)合格(Adequate)待改进(Needs Improvement)
交付物提交的 notebook 中构建并测试了新 ARIMA 模型,配有可视化解释,并明确给出模型精度提交的 notebook 未做注释或含有 bug提交的 notebook 不完整

翻译脚注(免责声明)提示:保加利亚语版本由 AI 翻译服务生成,准确性以英语原文为准。因此下面所有技术细节均以仓库中英文课程内容为准,这一点在引用时需要注意。

由此可归纳出作业的四个显式验收点,本文随后将逐一覆盖:

  1. 新数据:与课程示例(energy.csv)不同的、独立的时间序列数据;
  2. 新 ARIMA 模型:完整经历“切分 → 建模 → 预测”流程;
  3. 注释 + 可视化:notebook 中每一关键步骤配有解释文字与图表;
  4. MAPE 精度:以量化数字陈述模型误差。

前置技术概念:ARIMA / SARIMA 核心知识回顾

作业要求“可视化数据与模型”“解释精度”,若没有扎实的概念支撑,注释环节将无从下笔。课程正文 7-TimeSeries/2-ARIMA/README.md 已系统给出 ARIMA 建模所需的核心概念,以下按“解释进 notebook 注释”的维度整理:

  • 平稳性(Stationarity):统计意义上,数据分布在时间平移后不发生变化即为平稳。非平稳数据会因趋势、季节性等产生波动,分析前必须做变换处理;例如季节性可通过“季节性差分”消除。
  • 差分(Differencing):将非平稳数据转化为平稳数据的过程——通过差分去除时间序列水平的变化,从而消除趋势与季节性、稳定序列均值。
  • AR(自回归):模型“回看”过去的取值(即滞后项 lag)来对当前值建模,例如“用前几月的销量解释本月销量”。
  • I(整合):相对于 ARMA 模型,ARIMA 的“I”指差分步骤的施加,即数据经过若干次差分以消除非平稳性后称为“整合”。
  • MA(移动平均):输出变量由当前与过去若干期的误差项决定。
  • 参数组p, d, qp对应自回归部分(纳入历史值),d对应差分的阶数,q对应移动平均部分。当数据具有季节性(energy 数据即如此)时,还需要第二组季节参数P, D, Q与季节周期长度m,这就是 SARIMA;本课实际使用的是 statsmodels 的SARIMAX(含外生变量的季节 ARIMA),即便本例不传外生变量。

参考流水线:课程里 energy 负荷数据是如何“从零到 MAPE”的

作业的真正难点在于:你不是凭空创新,而是要在课程已跑通的完整流水线上替换数据。因此吃透课程示例代码,是新模型能否一次做对的关键。完整代码位于课程working目录:7-TimeSeries/2-ARIMA/working/notebook.ipynb(保加利亚语译本对应 translations/bg/7-TimeSeries/2-ARIMA/working/notebook.ipynb),示例数据为 7-TimeSeries/data/energy.csv(GEFCom 2014 电力负荷数据,列为timestamp, load, temp,2012 年初至 2014 年底逐小时 26000 余条记录)。

第一步:工具函数与数据装载

仓库把数据读取与 MAPE 计算封装进了公共模块 common/utils.py。load_data(见 load_data 定义)读取 CSV 后将timestamp解析为索引,并用pd.date_range(..., freq='H')按小时重索引,从而暴露数据中缺失的时间片:

energy = load_data('./data')[['load']] energy.head(10)

这里只取了load一列,因为作业与课程都聚焦单变量时间序列预测。数据装载后先画出 2012 年 1 月到 2014 年 12 月全部负荷曲线,确认明显的日周期与季节周期——“可视化数据”正是评分表中优秀档的显式要求之一

energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12) plt.xlabel('timestamp', fontsize=12) plt.ylabel('load', fontsize=12) plt.show()

第二步:按时间先后切分训练集与测试集

时间序列建模最忌讳“用未来信息预测过去”。课程给出的切分原则是:测试集必须在时间上晚于训练集。示例中训练期为 2014-11-01 起、测试期自 2014-12-30 起的逐小时数据:

train_start_dt = '2014-11-01 00:00:00' test_start_dt = '2014-12-30 00:00:00' train = energy.copy()[(energy.index >= train_start_dt) & (energy.index < test_start_dt)][['load']] test = energy.copy()[energy.index >= test_start_dt][['load']] print('Training data shape: ', train.shape) print('Test data shape: ', test.shape)

输出训练集 1416 行、测试集 48 行。课程随后把两段数据并置绘制,直观展示“前段训练、后段测试”的时序关系:

由于电力负荷具有强烈的季节规律且近期行为更相似,用较近的短窗口训练即可得到不错效果;课程还注明:由于拟合函数在拟合期内做样本内验证,这里省略单独的验证集。

第三步:缩放数据到 (0,1)

ARIMA/SARIMAX 建模前先做两步准备:按时间段过滤出需要的数据,再做缩放,把数据投影到 0 到 1 区间:

scaler = MinMaxScaler() train['load'] = scaler.fit_transform(train) test['load'] = scaler.transform(test)

关键陷阱是scaler只能对训练集fit,测试集只用transform,否则会把测试集分布信息泄漏进训练流程。课程用并排直方图对比原始数据与缩放后数据的分布,这类可视化也应写进你的作业 notebook。

第四步:定义 SARIMAX 模型并拟合

定义模型分三步:用SARIMAX()声明模型并传入参数,用fit()训练,用forecast()指定未来步数(horizon)预测:

order = (4, 1, 0) # (p, d, q) seasonal_order = (1, 1, 0, 24) # (P, D, Q, m),m=24 表示以 24 小时为季节周期 model = SARIMAX(endog=train, order=order, seasonal_order=seasonal_order) results = model.fit() print(results.summary())

seasonal_order中的24与逐小时数据的“一天 24 小时”周期对应;换成新数据时,这一步必须依据你自己的数据频率与周期重设(见下文第五节的通用化说明)。课程同时提示:人工挑选最优参数较为困难且耗时,正文中建议考虑借助auto_arima()一类的自动搜索函数辅助确定参数组合。

第五步:walk-forward(前向滚动)验证

要评估时序模型,课程采用业界标准的walk-forward 验证:从序列起点开始,在训练集上训练,预测下一个时间步,用真实值评估预测,再把真实值并入训练集、同时按“固定窗口”丢掉序列开头最旧的观测,如此滚动直到覆盖全部测试数据。这种重训机制让模型在每个时间步上都能给出尽可能好的预测,代价是计算量随滚动次数线性增长。

HORIZON = 3 # 一次向前预测 3 小时 test_shifted = test.copy() for t in range(1, HORIZON+1): test_shifted['load+'+str(t)] = test_shifted['load'].shift(-t, freq='H') test_shifted = test_shifted.dropna(how='any')

shift(-t, freq='H')把真实负荷按时间向前平移t小时,从而为每个时间点生成“t+1、t+2、… 的真实值”列,供预测对照。随后以固定 720 小时(30 天)窗口滚动拟合与预测:

%%time training_window = 720 # 用最近 30 天(720 小时)训练 train_ts = train['load'] test_ts = test_shifted history = [x for x in train_ts] history = history[(-training_window):] predictions = list() order = (2, 1, 0) seasonal_order = (1, 1, 0, 24) for t in range(test_ts.shape[0]): model = SARIMAX(endog=history, order=order, seasonal_order=seasonal_order) model_fit = model.fit() yhat = model_fit.forecast(steps = HORIZON) predictions.append(yhat) obs = list(test_ts.iloc[t]) # 滚动窗口:加入新观测,弹出最旧观测 history.append(obs[0]) history.pop(0) print(test_ts.index[t]) print(t+1, ': predicted =', yhat, 'expected =', obs)

注意示例中滚动验证阶段使用的阶数为order=(2,1,0)seasonal_order=(1,1,0,24),与先前演示拟合的(4,1,0)不同——参数选择本就需要在多组候选中尝试取舍,这也是作业要求在 notebook 中注释模型理由的原因。

预测完成后,把所有预测拼成便于评估的长表,并用scaler.inverse_transform把预测与真实值还原回原始量纲(兆瓦级负荷),否则无法解释误差:

eval_df = pd.DataFrame(predictions, columns=['t+'+str(t) for t in range(1, HORIZON+1)]) eval_df['timestamp'] = test.index[0:len(test.index)-HORIZON+1] eval_df = pd.melt(eval_df, id_vars='timestamp', value_name='prediction', var_name='h') eval_df['actual'] = np.array(np.transpose(test_ts)).ravel() eval_df[['prediction', 'actual']] = scaler.inverse_transform(eval_df[['prediction', 'actual']]) eval_df.head()

课程给出的前几行输出为prediction约 2900–3010、actual约 2886–3023,量纲与原始负荷一致。

第六步:用 MAPE 检验精度并可视化

MAPE(平均绝对百分比误差)把每个预测点的|actual − predicted| / actual累加并除以拟合点数,得到一个百分比形式的相对误差。课程对该指标的分步计算如下(多步时先按h分组再求平均):

if(HORIZON > 1): eval_df['APE'] = (eval_df['prediction'] - eval_df['actual']).abs() / eval_df['actual'] print(eval_df.groupby('h')['APE'].mean()) print('One step forecast MAPE: ', (mape(eval_df[eval_df['h'] == 't+1']['prediction'], eval_df[eval_df['h'] == 't+1']['actual']))*100, '%') print('Multi-step forecast MAPE: ', mape(eval_df['prediction'], eval_df['actual'])*100, '%')

其中mape(predictions, actuals)即 utils.py 中的同名函数:

def mape(predictions, actuals): """Mean absolute percentage error""" return ((predictions - actuals).abs() / actuals).mean()

课程在 energy 数据上得到的参考结果是:单步预测 MAPE ≈0.557%,多步预测 MAPE ≈1.146%。MAPE 数值越小越好——可以粗浅理解为“MAPE 为 10 表示预测平均偏了 10%”。最后把红色“实际值”曲线与蓝色、随预测步长变淡变细的“预测值”曲线叠绘,肉眼核对模型贴合度:

为“全新数据集”构建新 ARIMA 的五步通用方案

理解了参考流水线后,把它泛化到作业所需的新数据上。以下每个阶段都对应 notebook 中应出现的一个注释小节,可直接套用。

1. 选择并导入新数据,统一时间索引

作业建议的数据源(Duke 大学时间序列数据集合集)不在仓库内,需自行下载,因此导入代码必须按数据实际格式改写。可沿用的原则是:load_data这类工具期望 CSV 内含时间列,并希望将其设为索引、按固定频率重排以暴露缺失时间片。若新数据是月度季度粒度,示例中freq='H'、季节周期24必须相应替换为'MS'/'QS'与对应周期数。建议在 notebook 首个注释单元中写明:数据来源、时间范围、采样频率、是否单变量/含缺失,这正是评分表“注释清楚”的体现。

2. 时间上严格“前训后测”地切分

无论新数据粒度如何,都要保证test_start_dt晚于训练区间,并将训练起始日与测试起始日写成变量。切分后用课程同款并置绘图确认“训练/测试在时间上不重叠”,可直接套用前文traintest的过滤代码。

3. 审视平稳性并说明差分

新数据很可能非平稳。可在 notebook 里先绘制原始序列,观察趋势与季节周期;必要时给出差分解释(这与dD阶数的设定直接相关)。对明显的季节周期,把季节差分与seasonal_order的设定一并写进注释。

4. 确定(p,d,q)与季节参数,声明并拟合模型

先手工设定一组合适候选(可从较小的阶数如(2,1,0)起步),再用课程示范的SARIMAX+fit()流程验证;如需自动化搜索,可参考课程正文提到的auto_arima()。务必在注释中记录:你尝试过哪些组合、为何保留最终组合、results.summary()给出的拟合统计如何支撑该选择。

5. 滚动预测、反缩放、MAPE 与可视化收尾

复用 walk-forward 循环与eval_df构造逻辑:forecast(steps=HORIZON)得到多步预测,scaler.inverse_transform还原量纲,最后输出单步与多步两个 MAPE 数值并绘图。把 MAPE 结果作为一个醒目结论句写进 notebook(例如“本模型在验证期单步 MAPE 为 x%”),这正是评分表“给出精度”的落点。

把工作“注释化”:决定优秀档与合格档的分水岭

按评分表,未注释或含 bug 的 notebook 只能评为“合格”,可见注释本身就是作业的核心交付物。一份优秀 notebook 应做到:

  • 每个代码单元前有一个 Markdown 单元,回答“这步在做什么、为什么这样做、结果说明什么”;
  • 可视化出现在数据探索、切分、缩放分布、滚动预测对比等每个关键节点;
  • 模型构建处说明所选order/seasonal_order的考量;
  • 结尾明确给出 MAPE 数值与一句结论。

仓库中 7-TimeSeries/2-ARIMA/solution/notebook.ipynb(译本见 translations/bg/7-TimeSeries/2-ARIMA/solution/notebook.ipynb)是上述完整流程的“完成态”示例,可作为注释风格与代码组织的直接参照。

MAPE 之外:评估的局限与课后挑战

MAPE 直观、无量纲、便于跨场景比较,但它的分母是真实值actual当真实值接近 0 时误差会被急剧放大,因此并不适合所有数据。这也是为什么课程在课后挑战中要求进一步研究时间序列精度的其他检验方式(如 MAD、MSD 等),并把调研结果注记在 notebook 中——你在新模型的作业里可以顺带补充 1~2 个对比指标及其结果,作为对“精度评估”的加分说明。

提交前的自查清单

对照评分表做最终检查:

  1. 数据确实是“新的”——与课程 energy.csv 无关的另一组时间序列;
  2. 训练/测试严格按时间先后切分,代码中无未来信息泄漏(缩放器只对训练集fit);
  3. 每个代码块前都有解释性 Markdown 注释,无 bug、可从头到尾运行;
  4. 可视化齐备:数据曲线、切分图、缩放分布图、预测 vs 实际对比图;
  5. 明确打印/陈述 MAPE 数值(单步与多步);
  6. notebook 结论段落总结模型结构、参数选择理由与最终精度。

完成以上六项,即可对齐评分表“优秀”档:一份注释完整、经过测试、配可视化解释且精度明确的新 ARIMA 模型 notebook

仓库内相关文件速查

用途路径
作业原文(保加利亚语,关联文档)translations/bg/7-TimeSeries/2-ARIMA/assignment.md
作业原文(英文)7-TimeSeries/2-ARIMA/assignment.md
ARIMA 课程正文7-TimeSeries/2-ARIMA/README.md
课程 working notebook7-TimeSeries/2-ARIMA/working/notebook.ipynb
完成态示例 notebook7-TimeSeries/2-ARIMA/solution/notebook.ipynb
数据装载与 MAPE 工具common/utils.py
示例数据 energy.csv7-TimeSeries/data/energy.csv
前序课时(时间序列与数据准备)7-TimeSeries/1-Introduction/README.md

【免费下载链接】ML-For-Beginners12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 23:20:50

2026大模型学习路线图:从零基础到项目实战,程序员小白必看指南,存一下吧很难找全的!_ai大模型学习路线图

本文提供AI大模型系统学习路线&#xff0c;分四个阶段&#xff1a;入门阶段掌握Python、数学基础及机器学习&#xff1b;中级阶段深入学习算法并实践项目&#xff1b;进阶阶段学习自然语言处理、计算机视觉等&#xff1b;高级阶段探索深度强化学习和生成模型。文章还包含学习资…

作者头像 李华
网站建设 2026/9/8 23:20:15

免费抓包嗅探下载视频号与抖音资源:res-downloader 快速上手指南

免费抓包嗅探下载视频号与抖音资源&#xff1a;res-downloader 快速上手指南 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader …

作者头像 李华
网站建设 2026/9/8 23:17:49

Isaac Lab 3.0.0实战:齿轮插入任务Sim2Real迁移全攻略

把机械臂从仿真搬到真实产线&#xff0c;中间隔着的那道鸿沟到底有多大&#xff0c;没做过的人真的很难体会。我见过太多团队&#xff0c;仿真里跑得飞快的策略&#xff0c;一上真机就像丢了魂一样——位姿偏一点就怼不进去&#xff0c;光照变一下就抓不准孔位&#xff0c;摩擦…

作者头像 李华
网站建设 2026/9/8 23:15:53

用DOM与getComputedStyle提取网站设计风格,生成DESIGN.md规范

1. 为什么我需要从别人的网站里“扒”出设计风格先说个场景&#xff1a;我去年接手一个老项目&#xff0c;客户指着隔壁竞品的官网说“就照这个风格改&#xff0c;但我也说不清具体是啥风格”。和客户反复确认的过程非常痛苦——他说“高级感”&#xff0c;你理解为深色&#x…

作者头像 李华