请问我这的段时间序列模型的diamante,最后怎么将最后的一阶差分预测数据进行还原。因为预测出来的数据差距有点大
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams
import statsmodels.api as sm
from statsmodels.graphics.tsaplots import plot_acf
from statsmodels.tsa.stattools import adfuller as ADF
from statsmodels.graphics.tsaplots import plot_pacf
from statsmodels.stats.diagnostic import acorr_ljungbox
from statsmodels.tsa.arima_model import ARIMA
from statsmodels.tsa.arima_model import ARMA
import warnings
# 导入数据
# 读取数据,指定年份列为指标,pandas自动将'日期'列识别为Datetime格式
data = pd.read_excel('E:\桌面\机器学习\时间序列数据分析\能源数据集.xlsx', sheet_name='Sheet1', index_col=u'年份', header=0)
# index_col:指定哪些列用作数据框的行索引(标签)
# header:是否需要将数据集的第一行用作表头,默认用作
# u'字符串':后面字符串以 Unicode 格式 进行编码,一般用在中文字符串前面,防止因为源码储存格
# 式问题,导致再次使用时出现乱码。
print(30 * '*' + '样本中的前五行的数据' + 30 * '*')
print(data.head()) # 输出前五行数据
print(30 * '*' + '*****************' + 30 * '*')
# 设置预测的年份
predict_year = 14 # 表示预测往后的14年的数据
# 获取最后一年
temp4 = data.to_dict()['能源产量']
list_1 = temp4.keys()
count = data.shape[0] - 1
date = list(list_1)[count]
# 设置字体大小,及格式
config = {
"font.family": 'sans-serif',
"font.size": 15, # 这只字体的大小
"mathtext.fontset": 'stix',
"font.serif": ['SimSun8'], # 宋体
'axes.unicode_minus': False # 处理负号
}
rcParams.update(config)
# 做时序图
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文的标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
data.plot()
plt.ylabel('能源产量')
plt.title(u'关于能源产量的时序图')
# 做自相关图
fig = plt.figure(figsize=(10, 5))
ax1 = fig.add_subplot(111)
fig = plot_acf(data['能源产量'], ax=ax1)
fig.gca().set_title('原始序列的自相关图')
fig.gca().set_xlabel('延迟阶数')
fig.gca().set_ylabel('自相关系数(ACF)')
# 平稳性检验
print(30 * '*' + '原始序列的ADF(单位根检验)检验结果为' + 30 * '*')
# print(u'原始序列的ADF检验结果为:', ADF(data[u'能源产量']))
# 返回值依次为adf、pvalue、usedlag、nobs、critical values、icbest、regresults、resstore
# 若P值明显大于0.05,则判断该序列为非平稳序列(一定不是白噪声序列)
temp = ADF(data[u'能源产量'])[4]
print(' cValue ', ' P值')
print('adf', ' ', '1%', ' ', '5%', ' ', '10%')
print(round(ADF(data[u'能源产量'])[0], 4), ' ', round(temp['1%'], 4), ' ', round(temp.get('5%'), 4), ' ',
round(temp['10%'], 4), ' ', round(ADF(data[u'能源产量'])[1], 4))
# 如果adf(单位根检验)的P值大于0.05,判断为非平稳序列,则进行一阶差分,之后继续做平稳性判断
if round(ADF(data[u'能源产量'])[1], 4) <= 0.05:
print('根据adf检验,判断该时间序列为平稳时间序列')
print(30 * '*' + '输出原序列的白噪声检验:' + 30 * '*')
#检验是否是白噪声序列
temp3 = acorr_ljungbox(data, lags=1, return_df=True) # lags 为滞后数,return_df设置为True以用于立即返回DataFrame
print(temp3) # lb_stat为统计量(stat),lb_pvalue为p值
# 将数据原类型转换为浮点类型
data[u'能源产量'] = data[u'能源产量'].astype(float)
# 定阶
pmax = int(len(data) / 10) # 一般阶数不超过length/10
qmax = int(len(data) / 10) # 一般阶数不超过length/10
bic_matrix = [] # bic矩阵
for p in range(pmax + 1):
tmp = []
for q in range(qmax + 1):
try: # 存在部分错误,所以用try来跳过报错
tmp.append(round(ARMA(data,order = (p, q)).fit().bic, 2))
warnings.filterwarnings('ignore') # 忽视异常提示
except:
tmp.append(None)
warnings.filterwarnings('ignore') # 忽视异常提示
bic_matrix.append(tmp)
print(30 * '*' + '输出序列的BIC矩阵:' + 30 * '*')
for p in range(pmax + 1):
print(bic_matrix[p])
bic_matrix = pd.DataFrame(bic_matrix) # 从中可以找出最小值
p, q = bic_matrix.stack().astype('float64').idxmin() # 先用stack展平,然后用idxmin找出最小值位置
print(u'BIC最小的p值和q值为:%s、%s' % (p, q))
print(30 * '*' + '输出ARMA模型矩阵:' + 30 * '*')
model = ARMA(data, order=(p, q)).fit() # 建立ARMA(p,q)模型
print(30 * '*' + '模型报告' + 30 * '*')
print(model.summary2()) # 给出一份模型报告
print(30 * '*' + 'ARMA模型预测结果' + 30 * '*')
temp3 = model.forecast(predict_year) # 做为期5天的预测,返回预测结果、标准误差、置信区间
predict_res = temp3[0]
standard_error = temp3[1]
confidence_interval = temp3[2]
print('预测结果', ' ', '标准误差', ' ', '置信区间')
for i in range(predict_year):
print(round(predict_res[i], 2), ' ' * 10, round(standard_error[i], 2), ' ' * 10, '[',
round(confidence_interval[i][0], 2), '~',
round(confidence_interval[i][1], 2), ']')
else:
print('根据adf检验,判断该时间序列为非平稳时间序列,需要进行一阶差分再次检验')
diff_data = data.diff().dropna() # dropna()函数是用来删除缺失值的
diff_data.columns = [u'能源产量的一阶差分']
print(30 * '*' + '输出差分后的前五行数据' + 30 * '*')
print(diff_data.head())
diff_data.plot()
plt.ylabel('差分后序列')
plt.title(u'关于一阶差分后能源产量的时序图')
print(30 * '*' + '进行一阶差分序列的ADF(单位根检验)检验结果为' + 30 * '*')
# 绘制一阶差分后的自相关图
fig2 = plt.figure(figsize=(10, 5))
ax2 = fig2.add_subplot(111)
fig2 = plot_acf(diff_data['能源产量的一阶差分'], ax=ax2)
fig2.gca().set_title('一阶差分后能源产量的自相关图')
fig2.gca().set_xlabel('延迟阶数')
fig2.gca().set_ylabel('自相关系数(ACF)')
# 绘制一阶差分后的偏自相关图
fig3 = plt.figure(figsize=(10, 5))
ax3 = fig3.add_subplot(111)
fig3 = plot_pacf(diff_data['能源产量的一阶差分'], ax=ax3)
fig3.gca().set_title('一阶差分后能源产量的偏相关图')
fig3.gca().set_xlabel('延迟阶数')
fig3.gca().set_ylabel('偏自相关系数(PACF)')
# 进行一阶差分后的ADF(单位根检验)检验结果为
temp_ADF = ADF(diff_data[u'能源产量的一阶差分'])
temp1 = temp_ADF[4]
print(' cValue ', ' P值')
print('adf', ' ', '1%', ' ', '5%', ' ', '10%')
print(round(temp_ADF[0], 4), ' ', round(temp1['1%'], 4), ' ', round(temp1.get('5%'), 4), ' ',
round(temp1['10%'], 4), ' ', round(temp_ADF[1], 4))
# 对差分后的序列进行白噪声检验
print(30 * '*' + '输出一阶差分后序列的白噪声检验:' + 30 * '*')
temp2 = acorr_ljungbox(diff_data, lags=1, return_df=True) # lags 为滞后数,return_df设置为True以用于立即返回DataFrame
print(temp2) # lb_stat为统计量(stat),lb_pvalue为p值
print(30 * '*' + '输出定阶的相关步骤:' + 30 * '*')
# 将数据原类型转换为浮点类型
data[u'能源产量'] = data[u'能源产量'].astype(float)
# 定阶
pmax = int(len(diff_data) / 10) # 一般阶数不超过length/10
qmax = int(len(diff_data) / 10) # 一般阶数不超过length/10
bic_matrix = [] # bic矩阵
for p in range(pmax + 1):
tmp = []
for q in range(qmax + 1):
try: # 存在部分错误,所以用try来跳过报错
tmp.append(round(ARIMA(data, order = (p, 1, q)).fit().bic, 2))
warnings.filterwarnings('ignore') # 忽视异常提示
except:
tmp.append(None)
warnings.filterwarnings('ignore') # 忽视异常提示
bic_matrix.append(tmp)
print(30 * '*' + '输出一阶差分序列的BIC矩阵:' + 30 * '*')
for p in range(pmax + 1):
print(bic_matrix[p])
bic_matrix = pd.DataFrame(bic_matrix) # 从中可以找出最小值
p, q = bic_matrix.stack().astype('float64').idxmin() # 先用stack展平,然后用idxmin找出最小值位置
print(u'BIC最小的p值和q值为:%s、%s' % (p, q))
print(30 * '*' + '输出ARIMA模型矩阵:' + 30 * '*')
#如果原始序列不平稳,那么一阶差分后,将调用ARIMA模型,1表示一阶差分
model = ARIMA(data, (p, 1, q)).fit() # 建立ARIMA(0,1,1)模型
print(30 * '*' + '模型报告' + 30 * '*')
print(model.summary2()) # 给出一份模型报告
print(30 * '*' + 'ARIMA模型预测结果' + 30 * '*')
temp3 = model.forecast(predict_year) # 做为期5天的预测,返回预测结果、标准误差、置信区间
#print(temp3)
df_shift = data['能源产量'].shift(1)
#print(df_shift)
#temp3[0] = temp3[0] + df_shift
# #还原数据
# predict_ts = model.predict()
# # 一阶差分还原
# diff_shift_ts = model.shift(1)
# diff_recover_1 = predict_ts.add(diff_shift_ts) # 再次一阶差分还原
# rol_shift_ts = model.shift(1)
# diff_recover = diff_recover_1.add(rol_shift_ts) # 移动平均还原
# rol_sum = model.rolling(window=11).sum()
# rol_recover = diff_recover * 12 - rol_sum.shift(1) # 对数还原
# log_recover = np.exp(rol_recover)
# log_recover.dropna(inplace=True)
predict_res = temp3[0]
print(predict_res)
standard_error = temp3[1]
confidence_interval = temp3[2]
print('预测结果', ' ', '标准误差', ' ', '置信区间')
for i in range(predict_year):
print(round(predict_res[i], 2), ' ' * 10, round(standard_error[i], 2), ' ' * 10, '[',
round(confidence_interval[i][0], 2), '~',
round(confidence_interval[i][1], 2), ']')
plt.show()
由此可知,我们只需要将差分后预测出来的数据,加上原数据往后搓一位即可。代码如下:
# 一阶差分还原
# tmpdata2:原数据
# pred:一阶差分后的预测数据
df_shift = tmpdata2['ecpm_tomorrow'].shift(1)
predict = pred.add(df_shift)
# predict = pred + df_shift
predict
对于使用一阶差分的时间序列模型,预测得到的结果是对原始数据的一阶差分进行预测,而不是直接对原始数据进行预测。所以需要对预测结果进行反差分,得到最后的预测值。
具体方法如下:
以下是一个示例代码:
import pandas as pd
from statsmodels.tsa.api import ARIMA
# 加载数据
data = pd.read_csv('data.csv', index_col=0, parse_dates=True)
# 将原始数据进行一阶差分
diff = data.diff().dropna()
# 构造ARIMA(0,1,1)模型并拟合数据
model = ARIMA(diff, order=(0,1,1))
model_fit = model.fit(disp=False)
# 预测当前时刻的一阶差分
predicted_diff = model_fit.forecast()[0]
# 获取原始数据的最后一个值
last_value = data.iloc[-1]['value']
# 将预测得到的一阶差分与last_value相加,得到还原后的预测值
predicted_value = predicted_diff + last_value
# 打印预测结果
print('Predicted value:', predicted_value)
在这个示例中,我们使用了pandas和ARIMA模型对数据进行了处理与拟合,并预测了当前时刻的一阶差分predicted_diff,然后通过获取原始数据的最后一个值last_value,将预测得到的一阶差分与last_value相加,得到了还原后的预测值predicted_value。
对于ARIMA模型进行一阶差分预测时,预测结果与实际数据差距较大,需要将差分预测数据还原到原始数据的尺度上,以获得更准确的预测结果。具体步骤如下:
获取原始数据,假设原始数据存储在一个名为"original_data"的DataFrame中。
对原始数据进行一阶差分处理,得到差分数据。可以使用pandas.DataFrame.diff()函数实现,代码如下:
diff_data = original_data.diff().dropna()
对差分数据进行ARIMA建模,并进行预测。假设得到的预测结果存储在一个名为"diff_pred"的Series中。
将差分预测数据还原到原始数据的尺度上。可以使用pandas.Series.cumsum()函数将差分数据进行累加还原。代码如下:
pred = original_data.iloc[0] + diff_pred.cumsum()
其中,original_data.iloc[0]
表示原始数据的第一个值,也就是差分数据的第一个值的原始值。
总的代码如下:
# 获取原始数据
original_data = get_data()
# 对原始数据进行一阶差分处理,得到差分数据
diff_data = original_data.diff().dropna()
# 对差分数据进行ARIMA建模,并进行预测
diff_model = ARIMA(diff_data, order=(p, 1, q))
diff_result = diff_model.fit()
diff_pred = diff_result.predict(start=len(diff_data), end=len(diff_data) + n-1)
# 将差分预测数据还原到原始数据的尺度上
pred = original_data.iloc[0] + diff_pred.cumsum()
# 对比预测结果和实际数据,评估预测效果
evaluate(original_data, pred)
其中,get_data()
、evaluate()
函数分别用于获取数据和评估预测效果,具体实现根据不同的数据集有所不同。
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
在ARIMA模型中,一阶差分后的预测数据需要进行还原操作才能得到真实的预测值。具体的还原方法分为两步。假设原始序列为$y_t$,一阶差分后序列为$dy_t$,预测的一阶差分序列为$\widehat{dy_t}$,预测的值序列为$\widehat{y_t}$。
第一步:将一阶差分后预测数据$\widehat{dy_t}$还原成预测值$\widehat{y_t}$。需要注意的是,还原时需要使用前一个时刻的真实值才能得到当前时刻的真实值。具体操作如下:
$$
\widehat{y_t}=y_{t-1} + \widehat{dy_t}
$$
第二步:将$\widehat{y_t}$做差分还原得到真实预测值。一阶差分序列是通过对原始序列进行差分得到的,所以还原预测值时需要对应进行逆差分操作,具体操作如下:
$$
\widehat{y_t}= \sum_{i=1}^{t}\widehat{dy_i} + y_0
$$
其中,$y_0$表示原始序列的第一个值。
在代码实现上,可以在ARIMA模型预测时将预测出的一阶差分序列进行还原。具体实现
如果我的回答解决了您的问题,请采纳!
以下答案由GPT-4.5Plus大模型(语音)与博主A努力中.......共同编写:
你好,我看了你的问题和代码,发现有几个需要注意的地方:
ARIMA模型预测的结果是基于差分序列预测的,要想得到原始数据的预测结果,需要对预测结果进行还原操作。你的代码中虽然调用了model.forecast()获取了预测结果,但是没有进行还原操作,所以得出的预测数据差距较大,这是正常的。
还原ARIMA模型预测结果的主要步骤是:
python
# ARIMA模型预测
temp3 = model.forecast(predict_year)
predict_res = temp3[0]
# 还原预测结果
diff_recover = predict_res # 初始化
for i in range(1, model.k_diff + 1): # model.k_diff为差分次数
diff_shift = model.shift(i)
diff_recover = diff_recover + diff_shift
# 对数还原
if model.k_diff > 0:
rol_recover = diff_recover * modle.k_diff
log_recover = np.exp(rol_recover)
else:
log_recover = diff_recover
另外,注意还原后的预测数据要与原始数据的维度一致,所以还原后可能需要使用.dropna()
或其他方法填补数据。
针对此问题,如果您有任何其他疑问,也请在此提出,我很乐意继续帮助您解答。