时间序列预测是一个过程,要想获得良好的预测,唯一的方法就是实践这个过程。
在本教程中,您将学习如何使用 Python 预测巴尔的摩的年度用水量。
完成本教程将为您提供一个框架,用于处理您自己的时间序列预测问题,并掌握相应的步骤和工具。
完成本教程后,您将了解:
- 如何确认您的 Python 环境并仔细定义时间序列预测问题。
- 如何创建评估模型的测试平台,开发一个基准预测,并通过时间序列分析工具更好地理解您的问题。
- 如何开发一个自回归积分移动平均模型,将其保存到文件,并在以后加载它以对新的时间步长进行预测。
使用我的新书《使用 Python 进行时间序列预测》启动您的项目,包括分步教程和所有示例的Python 源代码文件。
让我们开始吧。
- 2019 年 4 月更新:更新了数据集链接。
- 2019年8月更新:更新了数据加载以使用新的API。
- 更新于2020年2月:更新了to_csv()以消除警告。
- **2020 年 12 月更新**:针对 API 更改更新了建模。

使用 Python 进行时间序列预测研究 - 巴尔的摩年度用水量
图片来源:Andy Mitchell,保留部分权利。
概述
在本教程中,我们将端到端地完成一个时间序列预测项目,从下载数据集和定义问题到训练最终模型和进行预测。
这个项目并非详尽无遗,但它展示了如何通过系统地解决一个时间序列预测问题来快速获得良好结果。
我们将按以下步骤完成此项目。
- 环境。
- 问题描述。
- 测试平台。
- 持久性。
- 数据分析。
- ARIMA 模型。
- 模型验证。
这将为解决时间序列预测问题提供一个模板,您可以将其用于您自己的数据集。
停止以**慢速**学习时间序列预测!
参加我的免费7天电子邮件课程,了解如何入门(附带示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
1. 环境
本教程假定已安装并运行SciPy环境及相关依赖项,包括:
- SciPy
- NumPy
- Matplotlib
- Pandas
- scikit-learn
- statsmodels
如果您需要帮助在您的工作站上安装 Python 和 SciPy 环境,请考虑使用 Anaconda 发行版,它可以为您管理大部分工作。
此脚本将帮助您检查这些库的已安装版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 检查关键Python库的版本 # scipy import scipy print('scipy: %s' % scipy.__version__) # numpy import numpy print('numpy: %s' % numpy.__version__) # matplotlib import matplotlib print('matplotlib: %s' % matplotlib.__version__) # pandas import pandas print('pandas: %s' % pandas.__version__) # statsmodels import statsmodels print('statsmodels: %s' % statsmodels.__version__) # scikit-learn import sklearn print('sklearn: %s' % sklearn.__version__) |
在编写本教程的工作站上,我的结果如下:
1 2 3 4 5 6 |
scipy: 1.5.4 numpy: 1.18.5 matplotlib: 3.3.3 pandas: 1.1.4 statsmodels: 0.12.1 sklearn: 0.23.2 |
2. 问题描述
问题是预测年度用水量。
该数据集提供了巴尔的摩从 1885 年到 1963 年的年度用水量,共 79 年的数据。
这些值的单位是每人每天的升数,共有 79 个观测值。
该数据集归功于 Hipel 和 McLeod,1994 年。
将数据集下载为 CSV 文件并将其放在当前工作目录中,文件名为“water.csv”。
3. 测试平台
我们必须开发一个测试平台来研究数据和评估候选模型。
这涉及两个步骤
- 定义验证数据集。
- 开发模型评估方法。
3.1 验证数据集
该数据集不是最新的。这意味着我们无法轻易收集更新的数据来验证模型。
因此,我们将假定现在是 1953 年,并从分析和模型选择中扣除最后 10 年的数据。
这最后十年数据将用于验证最终模型。
下面的代码将加载数据集为一个Pandas Series,并将其分为两部分:一部分用于模型开发(dataset.csv),另一部分用于验证(validation.csv)。
1 2 3 4 5 6 7 |
from pandas import read_csv series = read_csv('water.csv', header=0, index_col=0) split_point = len(series) - 10 dataset, validation = series[0:split_point], series[split_point:] print('Dataset %d, Validation %d' % (len(dataset), len(validation))) dataset.to_csv('dataset.csv', index=False, header=False) validation.to_csv('validation.csv', index=False, header=False) |
运行该示例会创建两个文件,并打印出每个文件中的观测数量。
1 |
数据集 69,验证集 10 |
这些文件的具体内容是:
- dataset.csv:1885 年至 1953 年的观测值(69 个观测值)。
- validation.csv:1954 年至 1963 年的观测值(10 个观测值)。
验证数据集约占原始数据集的 12%。
请注意,保存的数据集没有标题行,因此我们稍后处理这些文件时不需要考虑这一点。
3.2. 模型评估
模型评估仅在上一节准备的dataset.csv文件中进行。
模型评估包括两个要素:
- 性能度量。
- 测试策略。
3.2.1 性能度量
我们将使用均方根误差(RMSE)来评估预测的性能。这将为严重错误的预测提供更高的权重,并且其单位与原始数据相同。
在计算和报告RMSE之前,必须撤销对数据进行的任何转换,以便不同方法之间的性能可以直接进行比较。
我们可以使用 scikit-learn 库中的辅助函数 `mean_squared_error()` 计算 RMSE,该函数计算预期值列表(测试集)和预测列表之间的均方误差。然后我们可以对该值取平方根以获得 RMSE 分数。
例如
1 2 3 4 5 6 7 8 |
from sklearn.metrics import mean_squared_error from math import sqrt ... test = ... predictions = ... mse = mean_squared_error(test, predictions) rmse = sqrt(mse) print('RMSE: %.3f' % rmse) |
3.2.2 测试策略
候选模型将使用前向验证进行评估。
这是因为问题定义要求使用滚动预测类型的模型。在这种情况下,需要根据所有可用数据进行一步预测。
前向验证将按以下方式工作:
- 数据集的前50%将保留用于训练模型。
- 剩余50%的数据集将被迭代并用于测试模型。
- 对于测试数据集中的每一步:
- 将训练一个模型。
- 进行一步预测,并将预测存储起来以供以后评估。
- 测试数据集中实际的观测值将在下一次迭代中添加到训练数据集中。
- 在测试数据集枚举期间进行的预测将被评估并报告 RMSE 分数。
鉴于数据量较小,我们将允许模型在每次预测之前使用所有可用数据进行重新训练。
我们可以使用简单的NumPy和Python代码来编写测试平台的代码。
首先,我们可以直接将数据集拆分为训练集和测试集。我们始终注意将加载的数据集转换为 `float32`,以防加载的数据仍具有某些 `String` 或 `Integer` 数据类型。
1 2 3 4 5 |
# 准备数据 X = series.values X = X.astype('float32') train_size = int(len(X) * 0.50) train, test = X[0:train_size], X[train_size:] |
接下来,我们可以遍历测试数据集中的时间步长。训练数据集存储在 Python 列表中,因为我们需要在每次迭代中轻松附加新的观测值,而 NumPy 数组连接感觉有些大材小用。
模型所做的预测按照惯例称为“yhat”,因为结果或观测值被称为“y”,而“yhat”(带有标记的“y”)是“y”变量预测的数学符号。
每次观测值都会打印预测值和观测值,以便在模型存在问题时进行健全性检查预测。
1 2 3 4 5 6 7 8 9 10 11 |
# 步进验证 history = [x for x in train] predictions = list() for i in range(len(test)): # 预测 yhat = ... predictions.append(yhat) # 观测 obs = test[i] history.append(obs) print('>Predicted=%.3f, Expected=%3.f' % (yhat, obs)) |
4. 持久性
在深入进行数据分析和建模之前,第一步是建立一个性能基准。
这将为使用提出的测试平台评估模型提供一个模板,并为所有更复杂的预测模型提供一个性能比较基准。
时间序列预测的基准预测称为朴素预测,或持久性预测。
这是将前一个时间步长的观测值用作下一个时间步长观测值的预测。
我们可以将其直接插入上一节定义的测试平台。
完整的代码列表如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
from pandas import read_csv from sklearn.metrics import mean_squared_error from math import sqrt # 加载数据 series = read_csv('dataset.csv') # 准备数据 X = series.values X = X.astype('float32') train_size = int(len(X) * 0.50) train, test = X[0:train_size], X[train_size:] # 步进验证 history = [x for x in train] predictions = list() for i in range(len(test)): # 预测 yhat = history[-1] predictions.append(yhat) # 观测 obs = test[i] history.append(obs) print('>Predicted=%.3f, Expected=%3.f' % (yhat, obs)) # 报告表现 mse = mean_squared_error(test, predictions) rmse = sqrt(mse) print('RMSE: %.3f' % rmse) |
运行测试平台会打印测试数据集每次迭代的预测值和观测值。
示例最后会打印模型的RMSE。
在这种情况下,我们可以看到持久性模型实现了 21.975 的 RMSE。这意味着平均而言,模型在每次预测时都有大约 22 升/人/天的误差。
1 2 3 4 5 6 7 |
... >预测值=613.000,期望值=598 >预测值=598.000,期望值=575 >预测值=575.000,期望值=564 >预测值=564.000,期望值=549 >预测值=549.000,期望值=538 RMSE:21.975 |
我们现在有了基准预测方法和性能;现在我们可以开始深入挖掘我们的数据了。
5. 数据分析
我们可以使用汇总统计数据和数据图表来快速了解预测问题的结构。
在本节中,我们将从四个角度审视数据
- 汇总统计。
- 折线图。
- 密度图。
- 箱线图。
5.1. 总结统计
汇总统计数据可以快速了解观测值的范围。它可以帮助我们快速了解我们正在处理的数据。
下面的示例计算并打印时间序列的汇总统计数据。
1 2 3 |
from pandas import read_csv series = read_csv('dataset.csv') print(series.describe()) |
运行该示例会提供一系列汇总统计数据供您查看。
从这些统计数据中可以观察到:
- 观测数量(count)与我们的预期相符,这意味着我们正确地处理了数据。
- 平均值约为 500,我们可以将其视为该系列中的水平。
- 标准差和百分位数表明围绕平均值的分布相当紧密。
1 2 3 4 5 6 7 8 |
计数 69.000000 平均值 500.478261 标准差 73.901685 最小值 344.000000 25% 458.000000 50% 492.000000 75% 538.000000 最大值 662.000000 |
5.2. 线图
时间序列数据集的线图可以提供对问题的很多洞察。
下面的示例创建并显示了数据集的折线图。
1 2 3 4 5 |
from pandas import read_csv from matplotlib import pyplot series = read_csv('dataset.csv') series.plot() pyplot.show() |
运行示例并查看图表。注意序列中任何明显的时序结构。
从图表中可以观察到:
- 随着时间的推移,用水量似乎呈增加趋势。
- 似乎没有明显的异常值,尽管有一些大的波动。
- 该系列最后几年呈下降趋势。

年度用水量线图
明确地对趋势分量进行建模并将其去除可能会有一些好处。您还可以探索使用一两个级别的差分以使序列平稳。
5.3. 密度图
审视观测值密度图可以为数据结构提供进一步的见解。
下面的示例创建了观测值的直方图和密度图,而不考虑任何时间结构。
1 2 3 4 5 6 7 8 9 |
from pandas import read_csv from matplotlib import pyplot series = read_csv('dataset.csv') pyplot.figure(1) pyplot.子图(211) series.hist() pyplot.子图(212) series.plot(kind='kde') pyplot.show() |
运行示例并查看图表。
从图表中可以观察到:
- 分布不是高斯分布,但非常接近。
- 该分布具有一个长的右尾,可能暗示指数分布或双高斯分布。

年度用水量密度图
这表明在建模之前探索一些数据幂变换可能值得。
5.4. 箱线图
我们可以按十年分组年度数据,了解每个十年观测值的分布以及它可能如何变化。
我们预计会看到一些趋势(均值或中位数增加),但查看分布的其余部分如何变化可能会很有趣。
以下示例按十年对观测值进行分组,并为每个十年的观测值创建一个箱线图。最后一个十年只包含 9 年,可能无法与其他十年进行有用的比较。因此,只绘制了 1885 年至 1944 年之间的数据。
1 2 3 4 5 6 7 8 9 10 11 |
from pandas import read_csv from pandas import DataFrame from pandas import Grouper from matplotlib import pyplot series = read_csv('dataset.csv') groups = series['1885':'1944'].groupby(Grouper(freq='10AS')) decades = DataFrame() for name, group in groups: decades[name.year] = group.values decades.boxplot() pyplot.show() |
运行示例会并排创建 6 个箱线图,每个图对应所选数据的 6 个十年中的一个。
审查该图的一些观察结果包括
- 每年(红线)的中值可能显示出非线性的增加趋势。
- 数据的分布或中间 50%(蓝色框)确实显示出一些可变性。
- 某些十年可能存在异常值(箱线图之外的叉号)。
- 倒数第二个十年的平均消费量似乎较低,可能与第一次世界大战有关。

年度用水量箱线图
这种年度数据视图是一个有趣的途径,可以通过查看十年间的汇总统计数据以及汇总统计数据的变化来进一步探索。
6. ARIMA模型
在本节中,我们将为该问题开发自回归综合移动平均 (ARIMA) 模型。
我们将通过手动和自动配置 ARIMA 模型来解决建模问题。之后是第三步,调查所选模型的残差错误。
因此,本节分为 3 个步骤
- 手动配置 ARIMA。
- 自动配置 ARIMA。
- 审查残差错误。
6.1 手动配置ARIMA
ARIMA(p,d,q) 模型需要三个参数,传统上是手动配置的。
时间序列数据的分析假设我们处理的是平稳时间序列。
时间序列可能不是平稳的。我们可以通过首先对序列进行差分并使用统计检验来确认结果是平稳的来使其平稳。
下面的示例创建了一个序列的平稳版本并将其保存到文件 `stationary.csv` 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
from pandas import read_csv from statsmodels.tsa.stattools import adfuller from matplotlib import pyplot # 创建一个差分 def difference(dataset): diff = list() for i in range(1, len(dataset)): value = dataset[i] - dataset[i - 1] diff.append(value) return Series(diff) series = read_csv('dataset.csv') X = series.values X = X.astype('float32') # 差分数据 stationary = difference(X) stationary.index = series.index[1:] # 检查是否平稳 result = adfuller(stationary) print('ADF Statistic: %f' % result[0]) print('p-value: %f' % result[1]) print('Critical Values:') for key, value in result[4].items(): print('\t%s: %.3f' % (key, value)) # 绘制差分数据 stationary.plot() pyplot.show() # 保存 stationary.to_csv('stationary.csv', index=False, header=False) |
运行示例将输出对差分序列是否平稳的统计显著性检验结果。具体来说,是增强迪基-富勒检验。
结果显示,检验统计量值 -6.126719 小于 1% 时的临界值 -3.534。这表明我们可以以低于 1% 的显著性水平拒绝原假设(即结果是统计巧合的概率很低)。
拒绝零假设意味着该过程没有单位根,进而意味着时间序列是平稳的或不具有时间相关结构。
1 2 3 4 5 6 |
ADF 统计量:-6.126719 p值:0.000000 临界值 5%: -2.906 1%: -3.534 10%: -2.591 |
这表明至少需要一级差分。我们 ARIMA 模型中的 d 参数至少应为 1。
还创建了差分数据的图。它表明这确实消除了增加的趋势。

差分后的年度用水量数据集
下一步是为自回归 (AR) 和移动平均 (MA) 参数分别选择滞后值 p 和 q。
我们可以通过查看自相关函数(ACF)和偏自相关函数(PACF)图来做到这一点。
下面的示例为序列生成了 ACF 和 PACF 图。
1 2 3 4 5 6 7 8 9 10 11 |
from pandas import read_csv from statsmodels.graphics.tsaplots import plot_acf from statsmodels.graphics.tsaplots import plot_pacf from matplotlib import pyplot series = read_csv('dataset.csv') pyplot.figure() pyplot.子图(211) plot_acf(series, ax=pyplot.gca()) pyplot.子图(212) plot_pacf(series, ax=pyplot.gca()) pyplot.show() |
运行示例并查看图表,以了解如何为 ARIMA 模型设置 p 和 q 变量。
以下是图表中的一些观察结果。
- ACF 显示没有显著滞后。
- PACF 也显示没有显著滞后。
p 和 q 值的一个好的起始点也是 0。

平稳年度用水量数据集的 ACF 和 PACF 图
这个快速分析表明,原始数据上的 ARIMA(0,1,0) 可能是一个很好的起点。
这实际上是一个持久性模型。完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# 评估手动配置的 ARIMA 模型 from pandas import read_csv from sklearn.metrics import mean_squared_error from statsmodels.tsa.arima.model import ARIMA from math import sqrt # 加载数据 series = read_csv('dataset.csv', header=None, index_col=0, parse_dates=True, squeeze=True) # 准备数据 X = series.values X = X.astype('float32') train_size = int(len(X) * 0.50) train, test = X[0:train_size], X[train_size:] # 步进验证 history = [x for x in train] predictions = list() for i in range(len(test)): # 预测 model = ARIMA(history, order=(4,1,1)) model_fit = model.fit() yhat = model_fit.forecast()[0] predictions.append(yhat) # 观测 obs = test[i] history.append(obs) print('>Predicted=%.3f, Expected=%.3f' % (yhat, obs)) # 报告表现 rmse = sqrt(mean_squared_error(test, predictions)) print('RMSE: %.3f' % rmse) |
运行此示例会得到 22.311 的 RMSE,这略高于上面的持久性模型。
这可能是因为 ARIMA 实现的细节,例如自动计算并添加了趋势常数。
1 2 3 4 5 6 7 |
... >预测值=617.079,期望值=598 >预测值=601.781,期望值=575 >预测值=578.369,期望值=564 >预测值=567.152,期望值=549 >预测值=551.881,期望值=538 RMSE:22.311 |
6.2 网格搜索 ARIMA 超参数
ACF 和 PACF 图表明我们在这个数据集上无法做得比持久性模型更好。
为了确认此分析,我们可以网格搜索一套 ARIMA 超参数,并检查没有模型能带来更好的样本外 RMSE 性能。
在本节中,我们将搜索 p、d 和 q 的值组合(跳过那些无法收敛的),并找到产生最佳性能的组合。我们将使用网格搜索来探索整数值子集中的所有组合。
具体来说,我们将搜索以下参数的所有组合
- p: 0 到 4。
- d: 0 到 2。
- q: 0 到 4。
这将是 (5 * 3 * 5),即 300 次潜在的测试运行,并且需要一些时间来执行。
带有网格搜索版本测试框架的完整示例代码如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# 对时间序列进行 ARIMA 参数的网格搜索 import warnings from pandas import read_csv from statsmodels.tsa.arima.model import ARIMA from sklearn.metrics import mean_squared_error from math import sqrt # 评估给定阶数 (p,d,q) 的 ARIMA 模型,并返回 RMSE def evaluate_arima_model(X, arima_order): # 准备训练数据集 X = X.astype('float32') train_size = int(len(X) * 0.50) train, test = X[0:train_size], X[train_size:] history = [x for x in train] # 进行预测 predictions = list() for t in range(len(test)): model = ARIMA(history, order=arima_order) model_fit = model.fit() yhat = model_fit.forecast()[0] predictions.append(yhat) history.append(test[t]) # 计算样本外误差 rmse = sqrt(mean_squared_error(test, predictions)) return rmse # 评估 ARIMA 模型的 p、d 和 q 值组合 def evaluate_models(dataset, p_values, d_values, q_values): dataset = dataset.astype('float32') best_score, best_cfg = float("inf"), None for p in p_values: for d in d_values: for q in q_values: order = (p,d,q) try: rmse = evaluate_arima_model(dataset, order) if rmse < best_score: best_score, best_cfg = rmse, order print('ARIMA%s RMSE=%.3f' % (order,rmse)) except: continue print('Best ARIMA%s RMSE=%.3f' % (best_cfg, best_score)) # 加载数据集 series = read_csv('dataset.csv', header=None, index_col=0, parse_dates=True, squeeze=True) # 评估参数 p_values = range(0, 5) d_values = range(0, 3) q_values = range(0, 5) warnings.filterwarnings("ignore") evaluate_models(series.values, p_values, d_values, q_values) |
运行该示例将遍历所有组合并报告那些在没有错误的情况下收敛的结果。在现代硬件上,该示例运行时间略长于2分钟。
结果显示,发现的最佳配置是 ARIMA(2, 1, 0),RMSE 为 21.733,略低于之前测试的手动持久性模型,但可能没有显著差异。
1 2 3 4 5 6 7 |
... ARIMA(4, 1, 0) RMSE=24.802 ARIMA(4, 1, 1) RMSE=25.103 ARIMA(4, 2, 0) RMSE=27.089 ARIMA(4, 2, 1) RMSE=25.932 ARIMA(4, 2, 2) RMSE=25.418 最佳 ARIMA(2, 1, 0) RMSE=21.733 |
我们将选择这个 ARIMA(2, 1, 0) 模型。
6.3 检查残差误差
对模型进行良好最终检查是检查残差预测误差。
理想情况下,残差误差的分布应为零均值的正态分布。
我们可以通过使用汇总统计和图表来调查 ARIMA(2, 1, 0) 模型的残差误差。下面的示例计算并汇总了残差预测误差。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# 汇总 ARIMA 模型的残差误差 from pandas import read_csv from pandas import DataFrame from statsmodels.tsa.arima.model import ARIMA from matplotlib import pyplot # 加载数据 series = read_csv('dataset.csv', header=None, index_col=0, parse_dates=True, squeeze=True) # 准备数据 X = series.values X = X.astype('float32') train_size = int(len(X) * 0.50) train, test = X[0:train_size], X[train_size:] # 步进验证 history = [x for x in train] predictions = list() for i in range(len(test)): # 预测 model = ARIMA(history, order=(2,1,0)) model_fit = model.fit() yhat = model_fit.forecast()[0] predictions.append(yhat) # 观测 obs = test[i] history.append(obs) # 误差 residuals = [test[i]-predictions[i] for i in range(len(test))] residuals = DataFrame(residuals) print(residuals.describe()) pyplot.figure() pyplot.子图(211) residuals.hist(ax=pyplot.gca()) pyplot.子图(212) residuals.plot(kind='kde', ax=pyplot.gca()) pyplot.show() |
运行该示例首先描述残差的分布。
我们可以看到分布有一个右移,并且平均值不为零,为 1.081624。
这可能表明预测存在偏差。
1 2 3 4 5 6 7 8 |
count 35.000000 mean 1.081624 std 22.022566 min -52.103811 25% -16.202283 50% -0.459801 75% 12.085091 max 51.284336 |
还绘制了残差误差的分布。
这些图表显示了一个类似高斯分布的图,右尾较长,这进一步证明了幂变换可能值得探索。

残差预测误差密度图
我们可以利用这些信息通过将平均残差误差 1.081624 添加到每个预测中来纠正预测偏差。
下面的示例执行此偏差校正。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# 汇总经过偏差校正的预测的残差误差 from pandas import read_csv from pandas import DataFrame from sklearn.metrics import mean_squared_error from statsmodels.tsa.arima.model import ARIMA from math import sqrt from matplotlib import pyplot # 加载数据 series = read_csv('dataset.csv', header=None, index_col=0, parse_dates=True, squeeze=True) # 准备数据 X = series.values X = X.astype('float32') train_size = int(len(X) * 0.50) train, test = X[0:train_size], X[train_size:] # 步进验证 history = [x for x in train] predictions = list() bias = 1.081624 for i in range(len(test)): # 预测 model = ARIMA(history, order=(2,1,0)) model_fit = model.fit() yhat = bias + float(model_fit.forecast()[0]) predictions.append(yhat) # 观测 obs = test[i] history.append(obs) # 报告表现 rmse = sqrt(mean_squared_error(test, predictions)) print('RMSE: %.3f' % rmse) # 汇总残差误差 residuals = [test[i]-predictions[i] for i in range(len(test))] residuals = DataFrame(residuals) print(residuals.describe()) # 绘制残差误差 pyplot.figure() pyplot.子图(211) residuals.hist(ax=pyplot.gca()) pyplot.子图(212) residuals.plot(kind='kde', ax=pyplot.gca()) pyplot.show() |
预测性能略有提高,从 21.733 提高到 21.706,这可能显著也可能不显著。
预测残差误差的摘要显示,平均值确实非常接近零。
1 2 3 4 5 6 7 8 9 10 |
RMSE: 21.706 0 count 3.500000e+01 mean -3.537544e-07 std 2.202257e+01 min -5.318543e+01 25% -1.728391e+01 50% -1.541425e+00 75% 1.100347e+01 max 5.020271e+01 |
最后,残差误差的密度图确实显示出向零的小幅移动。

偏差校正的残差预测误差密度图
这种偏差校正是否值得商榷,但我们现在将使用它。
7. 模型验证
在模型开发和选定最终模型后,必须对其进行验证和定稿。
验证是该过程的可选部分,但它提供了一个“最后检查”,以确保我们没有欺骗或误导自己。
本节包括以下步骤:
- 最终确定模型:训练并保存最终模型。
- 进行预测:加载已定型的模型并进行预测。
- 验证模型:加载并验证最终模型。
7.1 最终确定模型
模型定型涉及在整个数据集上拟合 ARIMA 模型,在本例中,是在整个数据集的转换版本上拟合。
一旦拟合,模型就可以保存到文件中以供以后使用。
下面的示例在数据集上训练 ARIMA(2,1,0) 模型,并将整个拟合对象和偏差保存到文件中。
下面的示例将拟合模型保存到文件中,使其处于正确状态,以便以后可以成功加载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 将定型模型保存到文件 from pandas import read_csv from statsmodels.tsa.arima.model import ARIMA import numpy # 加载数据 series = read_csv('dataset.csv', header=None, index_col=0, parse_dates=True, squeeze=True) # 准备数据 X = series.values X = X.astype('float32') # 拟合模型 model = ARIMA(X, order=(2,1,0)) model_fit = model.fit() # 偏差常数,可以从样本内平均残差计算 bias = 1.081624 # 保存模型 model_fit.save('model.pkl') numpy.save('model_bias.npy', [bias]) |
运行示例将创建两个本地文件:
- model.pkl 这是调用 ARIMA.fit() 返回的 ARIMAResult 对象。这包括系数和拟合模型时返回的所有其他内部数据。
- model_bias.npy 这是存储为一行一列 NumPy 数组的偏差值。
7.2 进行预测
一个自然的需求可能是加载模型并进行单次预测。
这相对简单,涉及恢复保存的模型和偏差,并调用 forecast() 函数。
下面的示例加载模型,对下一个时间步进行预测,并打印预测。
1 2 3 4 5 6 7 |
# 加载定型模型并进行预测 from statsmodels.tsa.arima.model import ARIMAResults import numpy model_fit = ARIMAResults.load('model.pkl') bias = numpy.load('model_bias.npy') yhat = bias + float(model_fit.forecast()[0]) print('Predicted: %.3f' % yhat) |
运行该示例会打印约 540 的预测值。
1 |
Predicted: 540.013 |
如果我们查看 validation.csv,我们可以看到第一个行中下一个时间段的值是 568。预测值在合理的范围内。
7.3 验证模型
我们可以加载模型并以模拟的实际操作方式来使用它。
在测试工具部分,我们将原始数据集的最后 10 年保存到一个单独的文件中,以验证最终模型。
我们现在可以加载这个 validation.csv 文件,并用它来查看我们的模型在“未见过”的数据上的表现如何。
我们有两种可能的方法:
- 加载模型并用它来预测未来 10 年。超出前一两年后,预测的准确性将迅速下降。
- 加载模型并以滚动预测的方式使用它,为每个时间步更新变换和模型。这是首选方法,因为在实践中会这样使用该模型,它将达到最佳性能。
与前面章节中的模型评估一样,我们将以滚动预测的方式进行预测。这意味着我们将遍历验证数据集中的提前期,并将观测值作为历史记录的更新。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# 在验证数据集上加载并评估最终模型 from pandas import read_csv from matplotlib import pyplot from statsmodels.tsa.arima.model import ARIMA from statsmodels.tsa.arima.model import ARIMAResults from sklearn.metrics import mean_squared_error from math import sqrt import numpy # 加载和准备数据集 dataset = read_csv('dataset.csv', header=None, index_col=0, parse_dates=True, squeeze=True) X = dataset.values.astype('float32') history = [x for x in X] validation = read_csv('validation.csv', header=None, index_col=0, parse_dates=True, squeeze=True) y = validation.values.astype('float32') # 加载模型 model_fit = ARIMAResults.load('model.pkl') bias = numpy.load('model_bias.npy') # 进行第一次预测 predictions = list() yhat = bias + float(model_fit.forecast()[0]) predictions.append(yhat) history.append(y[0]) print('>Predicted=%.3f, Expected=%.3f' % (yhat, y[0])) # 滚动预测 for i in range(1, len(y)): # 预测 model = ARIMA(history, order=(2,1,0)) model_fit = model.fit() yhat = bias + float(model_fit.forecast()[0]) predictions.append(yhat) # 观测 obs = y[i] history.append(obs) print('>Predicted=%.3f, Expected=%.3f' % (yhat, obs)) # 报告表现 rmse = sqrt(mean_squared_error(y, predictions)) print('RMSE: %.3f' % rmse) pyplot.plot(y) pyplot.plot(predictions, color='red') pyplot.show() |
运行示例将打印出验证数据集中时间步长的每个预测值和期望值。
验证期的最终 RMSE 预测为每人每天 16 升。这与预期的 21 误差相差不大,但我认为这与简单的持久性模型也相差不大。
1 2 3 4 5 6 7 8 9 10 11 |
>Predicted=540.013, Expected=568 >Predicted=571.589, Expected=575 >Predicted=573.289, Expected=579 >Predicted=579.561, Expected=587 >Predicted=588.063, Expected=602 >Predicted=603.022, Expected=594 >Predicted=593.178, Expected=587 >Predicted=588.558, Expected=587 >Predicted=588.797, Expected=625 >Predicted=627.941, Expected=613 RMSE: 16.532 |
同时还提供了预测与验证数据集的比较图。
该预测确实具有持久性预测的特征。这表明,尽管这个时间序列具有明显的趋势,但它仍然是一个相当困难的问题。

验证数据集的预测图
总结
在本教程中,您发现了使用 Python 进行时间序列预测项目的步骤和工具。
本教程涵盖了很多内容;具体来说
- 如何开发具有性能度量和评估方法的测试框架,以及如何快速开发基线预测和技能。
- 如何使用时间序列分析来提出关于如何最佳地对预测问题进行建模的想法。
- 如何开发 ARIMA 模型、保存它,然后稍后加载它以对新数据进行预测。
您做得怎么样?您对本教程有任何疑问吗?
在下面的评论中提出你的问题,我会尽力回答。
一篇很棒的文章。非常感谢。
谢谢 Salem。
Jason,好文章!
几个问题,
1) 如何通过查看 ACF 和 PACF 图以及自相关图来设置 (p,d,q)?
2) 我们最初如何知道应该进行一阶差分还是二阶差分?
3) 以下是我原始数据在没有进行任何差分/变换/移动平均的情况下的 Dicker-Fuller 检验结果
如您所见,由于 p 值 <0.05,我可以拒绝我的原假设,这意味着时间序列是平稳的。接下来我应该如何进行?
检验统计量 -3.841070
p 值 0.002514
使用的滞后数 1.000000
使用的观测值数 106.000000
临界值 (5%) -2.889217
临界值 (1%) -3.493602
临界值 (10%) -2.581533
4) 如何研究残差图(您在文章中提到的非零均值)?
5) 我想在整个数据集上运行代码,并仅将未来日期值(没有实际值)用作测试集,例如 2015 年 1 月 1 日、2015 年 2 月 1 日等。我如何简化您的代码来实现这一点?
非常感谢您的帮助!
你好 Kuber,好问题!
1. 这篇文章更详细地介绍了如何根据 ACF 和 PACF 图配置 ARIMA
https://machinelearning.org.cn/gentle-introduction-autocorrelation-partial-autocorrelation/
2. 如果一阶差分不能使序列平稳,则重复直到它平稳为止。
3. 结果表明该序列可能是平稳的。
4. 在这里了解更多关于残差图的信息
https://machinelearning.org.cn/visualize-time-series-residual-forecast-errors-with-python/
5. 在所有数据上训练一个 ARIMA 模型,然后使用 predict() 函数,它将执行多个一步预测,并使用之前的预测值作为下一个预测的输入。
希望这能有所帮助。
嗨,Jason,
如您所见,根据 Dicker Fuller 检验的结果,我的数据在没有任何差异的情况下已经平稳。
我仍然不确定如何获得未来日期的预测。
我在整个数据集上训练了我的数据,然后尝试使用 predict 函数进行预测,但 predict 函数有以下参数(start,end,typ,dynamic)
当我尝试运行我的 predict 函数时
model = ARIMA(history, order=(0,1,1))
model_fit = model.fit(disp=0)
model_fit.predict(dates.get_loc(pd.Timestamp(“1-22-2017”)),dates.get_loc(pd.Timestamp(“1-28-2018”)),dynamic=True,typ=’levels’)
它给我以下错误,说“原始序列的起始索引 -1 已经被差分掉了”。??
不确定您所说的“使用先前的预测值作为下一个预测的输入”是什么意思。
如果您能给出一个例子,我将不胜感激。
谢谢!
请注意,我正在尝试进行每周预测,即我希望我的开始参数为 2017 年 1 月 22 日,结束参数为 2018 年 1 月 28 日,以 7 天的间隔进行每周预测。
你好 Kuber,
看看你的 ARIMA(0,1,1),你有一个 1 的差分(顺序的中间部分)。如果你的数据是平稳的,你可能不需要这个(例如,将 d 设置为 0)。
我喜欢在 predict 函数中使用时间索引而不是时间。尽管如此,请先尝试一步预测
这应该与
然后尝试更长的预测,例如多个时间步长
此模型的局限性在于,要预测 t+2,我们必须首先预测 t+1 并将其用作输入(滞后变量)来预测 t+2。这意味着预测技能可能会在未来的时间步长中迅速下降。
这有帮助吗?
谢谢您的回复 Jason!
那么如果我的数据是平稳的,我应该设置 (p,d,q) 的哪些值?
我的 ACF/PACF 图在第一个滞后之前就穿过零线,那么如果一切都是 0,0,0,它是什么类型的模型(AR/MA/ARIMA/SARIMAX)?
如果我在开始和结束参数中使用 len(history),则 predict 函数会将其视为整数值而不是日期格式,因此接下来的 7 个预测彼此非常接近而不是不同。
请告诉我。
你好 Kuber,
对于 ACF 和 PACF 图,我们关注的不是穿过零线,而是显著的自相关。
如果您不确定参数以及如何解释 ACF 和 PACF 图,请考虑对参数进行网格搜索,以找到具有最佳样本外 RMSE 分数的模型。
关于 predict() 函数,是的,我假设您想要接下来的 7 个连续时间步,抱歉。
在查看 ACF/PACF 图时,我发现 p 和 q 的滞后值小于 1,即 0.05 和 0.02。不确定如何进行?
有什么想法吗?
你好 Kuber,
尝试对参数进行网格搜索
https://machinelearning.org.cn/grid-search-arima-hyperparameters-with-python/
也许您的数据不可预测
https://machinelearning.org.cn/gentle-introduction-random-walk-times-series-forecasting-python/
也许您需要非线性方法或更多数据?
在查看 ACF/PACF 图时,我看到两者都在 0 处有显著滞后,并且我的网格搜索参数选择 (1,0,1) 作为最佳模型?
不确定是否应该取对数或对数差。
请告诉我。
谢谢!
你好 Kuber,
t=0 处的滞后可以忽略,它是观测值与自身的关联。
ACF 和 PACF 诊断为模型提供了一个很好的起点。您可以使用网格搜索来查看是否可以做得更好。
如果您的数据随时间变化,Box-Cox 变换可能很有用。试试看。
我只有有限的数据,所以获取更多数据不是一个选择。
网格搜索给我 (1,0,1) 作为最佳模型,R 中的 auto.arima() 函数也一样。
我不确定的是是否包含 trend=”c” 或 “nc”。我应该研究哪种非线性模型?
你好 Kuber,
尝试带趋势 (c 和 nc) 和不带趋势 (nc) 的方法,看看哪种效果最好。
尝试一系列方法,您无法知道哪种方法效果最好,请参阅这篇文章
https://machinelearning.org.cn/a-data-driven-approach-to-machine-learning/
嗨,Jason,
我又有同样的问题,因为我想做长期预测,比如未来 12 个月或未来 52 周,我使用 (p,1,q) 模型,我如何使用 predict 函数进行预测?它给我以下错误
“原始序列的起始索引 -1 已经被差分掉了”。
我的训练数据直到 2017 年 1 月 22 日都有值,我正在尝试从 2017 年 1 月 29 日到 2018 年 1 月 28 日进行预测,那么我的 predict 函数应该是什么样子?
predict(start=?, end= ?, typ=?, dynamic=?)
我如何使用 t+1 预测并将其用作输入(滞后变量)来预测 t+2?
如果您希望我更改我的训练/测试数据以适应相同的时间段,以便我可以摆脱差分错误,请告诉我。
您能用一些使用我的时间段的示例代码来解释一下吗?
你好 Kuber,
如果 d=1,则意味着您的数据集缩小了一个观测值。
这意味着你在设置开始和结束时需要考虑到这一点。
例如,当 d=0 时,你用 100 个样本(时间索引 0 到索引 99)拟合你的模型,一步预测将使用索引 100
当 d=1 时,我希望你用时间索引 0 到 98 拟合你的模型,一步预测将是
试试看,我说的对吗?
如果这一切都正确,你可以扩展到多步预测。
这说得通。“typ”和“dynamic”参数在 predict 函数中如何?
只是不确定当 d=0 和 d=1 且 trend='c' 和 'nc' 时,这些参数应该设置什么值?
如果你能填写下表,给出每种组合的 typ | dynamic 值,那就太好了。抱歉,但我非常困惑。
趋势 c nc
d=0 typ | dynamic typ | dynamic
d=1 typ | dynamic typ | dynamic
以上组合如何影响 predict 和 forecast 函数?
请告诉我。谢谢!
很好的问题。
你可以在 predict 函数中删除 typ 和 dynamic。它们是不需要的。
拟合模型时的 c 和 nc 指定是否在模型中使用趋势常数。用和不用它们都试试你的模型。
这有帮助吗?
很棒的内容。拜读过您的其他书籍。阅读您书籍中的主题内容真的很有趣,结构良好,是人们从零开始学习和实践的最佳方式。热切期待您的时间序列书籍发布。
谢谢 Debasish。
尊敬的Jason博士,
请问:
(1)根据我对模型的理解,你每次更新历史变量时都在进行一步预测。我理解这一点。
我也理解,如果不是循环,而是从未更新的历史版本中预测 10 步,那么预测的误差会随着时间的增加而增加。
在上面的列表中,如果你只打算预测一步,那么“减少”原始数据的大小并将其称为“训练”,其余的称为“测试”(大小为 10)的目的是什么?我是不是漏掉了什么?
(2)当你在 ARIMA 模型中使用积分变量 'i'=1 时,预测结果不是差异吗?对于一步预测,你难道不需要将 model.forecast()[0] 加到 history[-1] 中才能得到预测值吗?
谢谢你,
来自澳大利亚悉尼的 Anthony
嗨 Anthony,问题问得很好!
1. 我们的想法是模拟这样一种情况:我们有未知数据,并且新观测值是分段可用的。
2. 正确。forecast() 将反转任何差分操作,将预测值恢复到其原始规模。
亲爱的 Jason,
我查看了 5.4 节的箱线图。我一直在用 group = series['1885':'1944'].groupby(TimeGrouper('10AS')) 进行实验。我尝试了 TimeGrouper('10')、TimeGrouper('10A') 的变体,并获得了不同的结果。不要尝试 TimeGrouper('10SA'),否则 IDLE 程序可能会卡住。
我通常理解按 10 年为一组对数据进行分组的概念,但在 pandas 文档 TimeGrouper 中找不到任何系统和一致的参数可以放入 TimeGrouper。例如,TimeGrouper('10AS') 中的 'A' 和 'S' 是什么意思。
我喜欢“探索性数据分析”的概念,可以可视化地检查数据,分组的概念让我想起了太阳黑子数据。问题是:如果这是太阳黑子数据,TimeGrouper 会设置为 TimeGrouper('11') 还是其他什么?
谢谢你,
来自澳大利亚悉尼的 Anthony
你甚至可以通过调用 groups.describe() 获得分组的描述性统计。但是,我查看了 TimeGrouper 的文档,并且在那里
你可以在这里了解分组的别名
https://pandas.ac.cn/pandas-docs/stable/timeseries.html#offset-aliases
嗨,Jason,
你是否打算演示“外部变量”如何影响目标变量?例如,本例中的“用水量”,比如温度、人口数量等。更确切地说,是多个外部变量。
我见过 ARIMAX 和 SARIMAX,但没有像你写的那样详细的博客。
对于像我这样正在尝试不同模型以寻求知识的学生来说,这将非常有帮助。
谢谢你的建议 Nirikshith。希望将来有机会。
你好 Jason,
非常感谢您的精彩和信息丰富的教程,我在箱线图方面遇到了问题,我的数据框是空的,所以我无法将组值打包成十年,请帮帮我
听到这个消息我很难过。Bryan,教程示例对你有效吗?
我还没做完,我正在尝试数据分析来创建箱线图,但我一直收到错误。那
decades[name.year] = group.value
我似乎一直收到错误。我想我的 DataFrame 没有 value year。
注意:我正在使用 python 2.7,这会是原因吗?
这很奇怪,听到这个消息我很难过 Bryan。我已经在 Python 2 和 3 上测试过代码了。
也许可以确认原始数据文件是否正确,并且不包含页脚或额外的噪音。一个错误输入文件可能是我能想到的最好解释。
嗨,Jason,
我非常喜欢你解释一切的方式。期待从其他帖子中学习更多。
非常感谢您让我们的生活变得轻松。
您是否打算做一些关于算法统计方面的事情?基本上是如何解释各种东西,比如卡方、F 值等。
如果大家都很感兴趣,我将来可能会做。
嗨,Jason,好博客。请问,你能不能告诉我如何在第 7.3 节验证模型的图表中将日期放在 x 轴上?谢谢你
你可以在这里了解更多关于 matplotlib API 的信息
https://matplotlib.net.cn/index.html
谢谢您的回复,还有一件事,我尝试在非常大的数据集上运行第 6.2 节网格搜索 ARIMA 超参数,但它非常慢,有什么办法可以加快速度吗?非常感谢。
更大的机器,还是将网格搜索分摊到多台机器上?
啊,好的,我明白了,没有编程解决方案。非常感谢
也许是一种更有效的搜索过程,例如贝叶斯优化。
嗨 Jeson,抱歉打扰您!总的来说,我发现 SARIMAX 比 ARIMA 更快,我可以用 SARIMAX 替代 ARIMA 吗?非常感谢。
真的吗?我发现 SARIMAX 比 ARIMA 慢得多。
是的,你可以使用 SARIMAX 构建 ARIMA。只需将季节性参数设置为 0 即可。
使用你的示例,我得到了很好的结果。p,d,q (1,2,0)
这些是预测和预期值的摘录。
>预测值=11022046.043,预期值=11021346
>预测值=11379505.273,预期值=11376906
RMSE:3019.389
我的序列、数据集、验证集都是 Year, Series 格式。(YYYY, Series_value_in_int)
我的 validation.csv 中最后一年是 2018 年,我希望能够从我的验证集中预测并绘制更多 5 年或 10 年的值,即 (2019-2024 或 2019-2030)。
如果我的三个文件是以 YYYY-MM-DD 作为索引的格式呢?
我该如何编写我的代码?
假设你继续你的示例,你会如何编写代码来预测 1964-1974 年的值?
谢谢
也许这篇文章将有助于进行样本外预测
https://machinelearning.org.cn/make-sample-forecasts-arima-python/
你好,先生,
你能把数据集以 .csv 文件的形式发给我吗????请尽快回复
你可以从链接下载数据集。
此外,所有数据集都可以在这里找到
https://github.com/jbrownlee/Datasets
是的,在这里
https://raw.githubusercontent.com/jbrownlee/Datasets/master/yearly-water-usage.csv
我没听懂,你具体是什么意思?
本教程是关于年用水量的,我编写并运行了本教程。
你好,先生,
你是如何拆分 dataset.csv 和 validation.csv 的?
你可以根据特定的年份或月份进行拆分。
如果你需要使用 numpy 数组的帮助,也许可以从这里开始
https://machinelearning.org.cn/index-slice-reshape-numpy-arrays-machine-learning-python/
你好先生,
我尝试了您的 7.3 代码,但出现错误,提示无法将字符串转换为浮点数。我将 X = dataset.values.astype('float32') 修改为 X=float(dataset())。但我仍然收到错误,提示“Series”对象不可调用。请指导我。
谢谢并致以问候
Bindu TR
很抱歉听到这个消息,我在这里有一些建议。
https://machinelearning.org.cn/faq/single-faq/why-does-the-code-in-the-tutorial-not-work-for-me
你好,先生,
这个 7.3 代码能在 jupyter notebook 上运行吗?
如果可以,它显示错误“无法将字符串转换为浮点数”,请帮帮我
我怀疑它会,但我建议从命令行运行
https://machinelearning.org.cn/faq/single-faq/how-do-i-run-a-script-from-the-command-line
你好,先生,
正如您所说,我在 Windows 的命令提示符中运行了程序,得到了同样的错误“无法将字符串转换为浮点值”。请帮帮我
谢谢和问候
Bindu TR
可能你的数据文件有问题,也许试试这个数据文件
https://raw.githubusercontent.com/jbrownlee/Datasets/master/yearly-water-usage.csv
你好先生,
我检查了一切,我无法运行 7.3 代码。我认为 Series 支持列,而不接受行值。
谢谢及问候
Bindu TR
听到这个消息我很难过,但我相信代码是有效的。
也许可以仔细检查一下你的环境/库/Python 是否是最新的?
你好,先生,
我无法运行你的这个页面代码。但我尝试了你的 ARIMA 示例代码。它成功了。感谢你的这个教程。但现在如何根据水池和水箱中的水位预测用水量。我应该如何在 python 中编写它。
谢谢和问候
Bindu TR
这个可能会有帮助
https://machinelearning.org.cn/make-sample-forecasts-arima-python/
你好,这确实是一篇非常有帮助的文章。我很好奇时间序列模型在预测准确性方面是如何随时间演变的。它是会自动改进,还是像神经网络那样需要调优?你能解释一下吗,因为我找不到解决这个问题的指导。
谢谢,此致。
Tharika
如果预测误差开始增加,模型可能需要更新。
谢谢你,Jason 🙂
不客气。
嗨,Jason;
这真是一个很棒的教程,对建立 ARIMA 模型非常有帮助。
我有一个关于 7.3 节中滚动 ARIMA 模型最后十年最终图表的问题。
你说这个图表具有朴素模型的特征,这对我来说很明显。但这到底意味着什么?我们不能准确预测用水量吗?ARIMA 模型不应该比持久性模型表现得更明显吗?
那么,如果 ARIMA 和持久性模型在准确性方面几乎相同呢?
如果 ARIMA 无法比朴素预测做得更好,即使我们调整了模型,也表明 ARIMA 不适合这些数据。
如果我们从许多模型类型中得到相同的发现,并且我们所能做的最好就是持久性,这可能表明该系列是不可预测的(就目前而言)。
我明白了。非常感谢!
尊敬的 Jason 博士,非常感谢您分享您的文章。
我需要从气缸中预测气体的结束时间。提供时间值和气体消耗值。气体在一个特征中消耗或被废气取代。时间以分钟为单位给出
您能推荐一篇关于解决该问题的帖子吗?
也许你可以将其建模为时间序列分类任务?
这可能是一个很好的起点
https://machinelearning.org.cn/start-here/#deep_learning_time_series
你好!我得到的验证集上的 RMSE 远高于测试集。这意味着什么?
可能有几个原因
你是不是对训练集过拟合了?
验证集与训练集是否非常不同?
print('>Predicted=%.3f, Expected=%.3f' % (yhat, y[0]))
TypeError: only size-1 arrays can be converted to Python scalars
我该怎么做?请帮帮我。
你好 linfeng……你复制粘贴代码了吗?这可能是问题的一部分。
亲爱的 Jason,
我很好奇在 5.2 节下显示的线形图,它显示了(我相信)消费模式与年份值(在 x 轴上)。使用相同的代码我无法获得年份值。我只得到了 10、20... 70 的值。
我唯一能获得年份值的方法是在创建数据集时(在 3.1 节中)保留年份和消费量两列,然后将其绘制在“x”(年份)和“y”(用水量)坐标上。
有没有办法在 x 轴上显示年份值,而只使用单列的“数据集”中的“用水量”数据?
此致
我在控制台得到了打印结果,但是当脚本达到绘图阶段时,我收到了错误
“TypeError: 没有数字数据可绘制”在行
“stationary.plot()”
我使用了代码小部件中的“复制”菜单项复制了您的代码。
你能帮忙吗?