数据分析之季节性差分预测天气

同步发布自本人博客:数据挖掘之天气预测

背景与目标

每天变化多端的天气让我们的生活从满了未知的可能,极大的影响了我们的生活
天气预测在许多领域中发挥着至关重要的作用,从农业到交通运输再到灾害管理,准确的天气预报能够帮助各行业提前应对可能的天气变化,减少损失,优化资源分配。随着数据科学和机器学习技术的发展,基于历史天气数据的预测模型已经成为现代天气预报的重要工具。通过利用大量的历史气象数据,构建和训练机器学习模型,可以更精确地预测未来的天气情况。

本项目的目标是构建和评估多种机器学习模型,以预测某些地点是否会在第二天降雨(RainTomorrow)。我们使用了一系列气象特征数据,例如最高气温、最低气温、降雨量、风速、湿度、气压等,通过不同的机器学习算法进行训练和测试。具体目标包括:

  1. 数据预处理与标准化:清洗和规范化气象数据,以确保模型训练的有效性。
  2. 模型构建与训练:使用多种机器学习算法,包括决策树、随机森林、逻辑回归、K近邻、支持向量机和神经网络,构建预测模型。
  3. 模型评估与比较:通过多种评估指标(如准确率、精确率、召回率、F1值和AUC值)评估各模型的性能,找出最优的预测模型。
  4. 结果可视化:使用图表展示各地点的模型性能,以便直观地比较不同模型在不同地点的预测效果。
  5. 进一步优化与改进:根据评估结果,对模型进行优化,以提高预测的准确性和可靠性。
    通过实现上述目标,我们希望能够构建出一个高效、可靠的天气预测系统,为相关领域提供有价值的参考。

数据说明

列名含义
Date日期
Location地点
MinTemp最低气温(摄氏度)
MaxTemp最高气温(摄氏度)
Rainfall降雨量(毫米)
Evaporation蒸发量(毫米)
Sunshine日照时数(小时)
WindGustDir最大阵风的风向
WindGustSpeed最大阵风的风速(公里/小时)
WindDir9am上午9点的风向
WindDir3pm下午3点的风向
WindSpeed9am上午9点的风速(公里/小时)
WindSpeed3pm下午3点的风速(公里/小时)
Humidity9am上午9点的湿度(百分比)
Humidity3pm下午3点的湿度(百分比)
Pressure9am上午9点的气压(百帕)
Pressure3pm下午3点的气压(百帕)
Cloud9am上午9点的云量(八分制)
Cloud3pm下午3点的云量(八分制)
Temp9am上午9点的温度(摄氏度)
Temp3pm下午3点的温度(摄氏度)
RainToday是否在今天下雨(是/否)
RISK_MM明天降雨的风险量(毫米)
RainTomorrow是否在明天下雨(是/否)

预处理

首先我们对数据进行读取以及预处理

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
from statsmodels.tsa.stattools import adfuller, acf, pacf
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_squared_error
from statsmodels.graphics.tsaplots import plot_acf
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
# 读取数据
df = pd.read_csv('weatherAUS.csv')

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号

# 按日期排序
# df = df.sort_values(by='Date')
df['Date'] = pd.to_datetime(df['Date'])
# 设置日期为索引
df.set_index('Date', inplace=True)

显而易见的,我要预测一个数据的最高温度的数据,以及地点,因为每个地点对应的时间是唯一的 ,如果不分类地点的话
就会出现一个时间有很多数据最高温度的 情况
之前没分类 就走错了很多弯路 导致步骤对了反而没有成功的数据

# 只保留需要的列
df = df[['Location', 'MaxTemp']]

# 去除缺失值
df = df.dropna()

# 选择一个地点进行分析,比如 "Albury"
location = 'Albury'
location_data = df[df['Location'] == location]['MaxTemp']

# 确保时间序列数据具有频率
location_data = location_data.asfreq('D')

# 使用插值法填补缺失值
location_data = location_data.interpolate(method='linear')

# 删除依然存在的缺失值
location_data = location_data.dropna()

# 绘制时间序列图
plt.figure(figsize=(10, 6))
plt.plot(location_data)
plt.title(f'{location} 的最高温度时间序列')
plt.show()

请添加图片描述

显示最高温度的时间序列,我们发现时间序列图中对于这个时间序列跨度很大,,序列是按照以年份来周期循环
很平稳且有规律进行周期在一定的范围内稳定的波动,并不是在某个常量值附近波动,根据时序图检验平稳性的原理来判断,该序列属于非平稳的随机序列

# ADF平稳性检验
adf_result = adfuller(location_data)
print('ADF 检验结果:', adf_result)

# 分解时间序列,指定周期,比如一年365天
decomposition = sm.tsa.seasonal_decompose(location_data, model='additive', period=365)
fig = decomposition.plot()
plt.show()
ADF 检验结果: (-3.3666814947988617, 0.012148512496123455, 12, 3116, {'1%': -3.432450351481275, '5%': -2.862468004787272, '10%': -2.567263999190068}, 15487.167404620237)

请添加图片描述

# ADF平稳性检验
adf_result = adfuller(location_data)
print('ADF 检验结果:', adf_result)
print(f'ADF统计量: {adf_result[0]}')
print(f'p值: {adf_result[1]}')
print(f'使用的滞后数: {adf_result[2]}')
print(f'样本量: {adf_result[3]}')
print('临界值:')
for key, value in adf_result[4].items():
    print(f'    {key}: {value}')

if adf_result[1] < 0.05:
    print("时间序列是平稳的")
else:
    print("时间序列不是平稳的")

# 绘制自相关函数(ACF)图
plt.figure(figsize=(10, 6))
plot_acf(location_data, lags=50)
plt.title(f'{location} 的自相关函数(ACF)')
plt.show()

ADF 检验结果: (-3.3666814947988617, 0.012148512496123455, 12, 3116, {'1%': -3.432450351481275, '5%': -2.862468004787272, '10%': -2.567263999190068}, 15487.167404620237)
ADF统计量: -3.3666814947988617
p值: 0.012148512496123455
使用的滞后数: 12
样本量: 3116
临界值:
    1%: -3.432450351481275
    5%: -2.862468004787272
    10%: -2.567263999190068
时间序列是平稳的

请添加图片描述

从自相关图看出,自相关系数在X轴 的上方 ,并不是在x轴上下波动,是单调趋势序列的典型特征,具有持久的正自相关性,且数值基本无变化,意味着时间序列中存在某种周期性或趋势。

这个序列是有规律的以年为周期进行波动

根据ADF检验结果,p值为0.0121,小于0.05,因此时间序列是平稳的。即使ACF图显示自相关系数从1.0慢慢降低到0.6,这也可能表示该时间序列中存在一些长期依赖性或季节性。

尽管ADF检验表明时间序列是平稳的,但是ACF图的结果可以提供更多信息。ACF图显示自相关系数从1.0逐渐降低到0.6,表明存在一些长期依赖性,这可能是由于季节性或其他长期趋势引起的。

解释与处理建议
长期依赖性:ACF图显示的长期依赖性表明时间序列中存在长期趋势或周期性成分。即使时间序列整体上是平稳的,但这些成分可能需要进一步的处理或建模。

季节性:如果时间序列中存在季节性成分,可以考虑使用季节性差分来去除季节性。例如,对于月度数据,可以进行12期差分。

模型选择:在进行时间序列建模时,可以考虑使用带有季节性成分的模型,如SARIMA模型。

所以我们要进行差分来处理数据,由于数据是一年循环波动,那么属于季节周期性
所以使用季节差分,以一年365为参数进行降维

# 进行季节性差分
seasonal_diff = location_data.diff(365).dropna()

# 绘制差分后的时间序列图
plt.figure(figsize=(10, 6))
plt.plot(seasonal_diff)
plt.title(f'{location} 的最高温度季节性差分时间序列')
plt.show()

# 绘制差分后的自相关函数(ACF)图
plt.figure(figsize=(18, 10))
plot_acf(seasonal_diff, lags=50)
plt.title(f'{location} 的最高温度季节性差分自相关函数(ACF)')
plt.show()

# 绘制差分后的偏自相关函数(PACF)图
plt.figure(figsize=(10, 6))
plot_pacf(seasonal_diff, lags=50)
plt.title(f'{location} 的最高温度季节性差分偏自相关函数(PACF)')
plt.show()

请添加图片描述

请添加图片描述

请添加图片描述



# 季节性差分后的ADF检验
result = adfuller(seasonal_diff.dropna())
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))

# 结果解读
if result[1] > 0.05:
    print("季节性差分后的数据仍然是非平稳的")
else:
    print("季节性差分后的数据是平稳的")
ADF Statistic: -11.476252
p-value: 0.000000
Critical Values:
	1%: -3.433
	5%: -2.863
	10%: -2.567
季节性差分后的数据是平稳的
from statsmodels.stats.diagnostic import acorr_ljungbox
# 去除NaN值
max_temp_diff = seasonal_diff.dropna()


# 白噪声检验
print("差分序列的白噪声检验结果:\n" , acorr_ljungbox(max_temp_diff, lags=1))
差分序列的白噪声检验结果:
        lb_stat      lb_pvalue
1  1056.822391  8.006870e-232

模型预测

找出最佳参数

# 选择ARIMA模型参数
# max_temp_diff = location_data.dropna()



max_temp_diff  = seasonal_diff.dropna()


order_select = sm.tsa.arma_order_select_ic(max_temp_diff, ic=['bic'], trend='n', max_ar=5, max_ma=5)
print('BIC选择的最佳参数:', order_select.bic_min_order)
BIC选择的最佳参数: (1, 4)

BIC选择的最佳参数: (1, 4)

# 拟合ARIMA模型
model = ARIMA(df['MaxTemp'], order=(order_select.bic_min_order[0], 0, order_select.bic_min_order[1]))
model_fit = model.fit()
print(model_fit.summary())
                               SARIMAX Results                                
==============================================================================
Dep. Variable:                MaxTemp   No. Observations:               141871
Model:                 ARIMA(1, 0, 4)   Log Likelihood             -366137.686
Date:                Tue, 02 Jul 2024   AIC                         732289.372
Time:                        04:42:15   BIC                         732358.411
Sample:                             0   HQIC                        732310.000
                             - 141871                                         
Covariance Type:                  opg                                         
==============================================================================
                 coef    std err          z      P>|z|      [0.025      0.975]
------------------------------------------------------------------------------
const         23.2269      0.377     61.576      0.000      22.488      23.966
ar.L1          0.9950      0.000   3094.406      0.000       0.994       0.996
ma.L1         -0.3711      0.002   -178.084      0.000      -0.375      -0.367
ma.L2         -0.3006      0.002   -127.512      0.000      -0.305      -0.296
ma.L3         -0.1166      0.002    -48.575      0.000      -0.121      -0.112
ma.L4         -0.0158      0.002     -7.138      0.000      -0.020      -0.011
sigma2        10.2129      0.028    369.185      0.000      10.159      10.267
===================================================================================
Ljung-Box (L1) (Q):                   0.03   Jarque-Bera (JB):             30952.95
Prob(Q):                              0.87   Prob(JB):                         0.00
Heteroskedasticity (H):               1.04   Skew:                            -0.15
Prob(H) (two-sided):                  0.00   Kurtosis:                         5.27
===================================================================================

Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).
# 拆分训练集和测试集
train_data = seasonal_diff[:-365]
test_data = seasonal_diff[-365:]

# 训练ARIMA模型
model = ARIMA(train_data, order=(2, 0, 5))
model_fit = model.fit()

# 预测
forecast_result = model_fit.get_forecast(steps=len(test_data))
forecast = forecast_result.predicted_mean
conf_int = forecast_result.conf_int()

# 打印预测结果
print(f'预测未来30天的最高温度: {forecast}')
print(f'预测的置信区间: {conf_int}')

# 绘制预测结果
plt.figure(figsize=(10, 6))
plt.plot(train_data.index, train_data, label='训练数据')
plt.plot(test_data.index, test_data, label='实际值')
plt.plot(test_data.index, forecast, label='预测值')
plt.fill_between(test_data.index, conf_int.iloc[:, 0], conf_int.iloc[:, 1], color='pink', alpha=0.3)
plt.legend()
plt.show()
预测未来30天的最高温度: 2016-06-26   -1.574331
2016-06-27   -0.481513
2016-06-28    0.067825
2016-06-29    0.390562
2016-06-30    0.363980
                ...   
2017-06-21    0.144490
2017-06-22    0.144482
2017-06-23    0.144474
2017-06-24    0.144466
2017-06-25    0.144458
Freq: D, Name: predicted_mean, Length: 365, dtype: float64
预测的置信区间:             lower MaxTemp  upper MaxTemp
2016-06-26      -9.334773       6.186111
2016-06-27      -9.752366       8.789340
2016-06-28      -9.567745       9.703394
2016-06-29      -9.345149      10.126273
2016-06-30      -9.393319      10.121280
...                   ...            ...
2017-06-21      -9.795905      10.084886
2017-06-22      -9.795913      10.084877
2017-06-23      -9.795922      10.084869
2017-06-24      -9.795930      10.084861
2017-06-25      -9.795938      10.084853

[365 rows x 2 columns]

请添加图片描述

# 只显示最后90天的数据
last_360_days = seasonal_diff[-700:]

# 绘制预测结果
plt.figure(figsize=(10, 6))
plt.plot(last_360_days.index, last_360_days, label='实际值', color='blue')
plt.plot(test_data.index, forecast, label='预测值', color='red')
plt.fill_between(test_data.index, conf_int.iloc[:, 0], conf_int.iloc[:, 1], color='pink', alpha=0.3)
plt.title(f'{location} 的最高温度预测 (最后360天)')
plt.legend()
plt.show()

请添加图片描述

返回原本的值

# 提取原始的最高温度数据
original_data = df[df['Location'] == location]['MaxTemp']

# 确保时间序列数据具有频率
original_data = original_data.asfreq('D')

# 使用插值法填补缺失值
original_data = original_data.interpolate(method='linear')

# 删除依然存在的缺失值
original_data = original_data.dropna()

# 获取季节性差分的基础值
seasonal_base = original_data.shift(365).dropna()

# 将差分后的预测值还原为原始的时间序列数据
restored_forecast = forecast + seasonal_base[-len(forecast):]

# 绘制原始数据和还原后的预测值的对比图
plt.figure(figsize=(12, 8))
plt.plot(original_data.index, original_data, label='原始数据', color='blue')
plt.plot(restored_forecast.index, restored_forecast, label='还原后的预测值', color='red')
plt.fill_between(test_data.index, conf_int.iloc[:, 0] + seasonal_base[-len(forecast):],
                 conf_int.iloc[:, 1] + seasonal_base[-len(forecast):], color='pink', alpha=0.3)
plt.title(f'{location} 的最高温度原始数据与还原后的预测值对比')
plt.legend()
plt.show()

# 打印还原后的预测值
print(f'还原后的预测值: {restored_forecast}')
print(f'预测的置信区间: {conf_int}')

请添加图片描述

还原后的预测值: 2016-06-26    11.625669
2016-06-27    11.918487
2016-06-28    15.067825
2016-06-29     8.990562
2016-06-30    10.963980
                ...    
2017-06-21    11.744490
2017-06-22    13.844482
2017-06-23    13.344474
2017-06-24     8.344466
2017-06-25    10.644458
Freq: D, Length: 365, dtype: float64
预测的置信区间:             lower MaxTemp  upper MaxTemp
2016-06-26      -9.334773       6.186111
2016-06-27      -9.752366       8.789340
2016-06-28      -9.567745       9.703394
2016-06-29      -9.345149      10.126273
2016-06-30      -9.393319      10.121280
...                   ...            ...
2017-06-21      -9.795905      10.084886
2017-06-22      -9.795913      10.084877
2017-06-23      -9.795922      10.084869
2017-06-24      -9.795930      10.084861
2017-06-25      -9.795938      10.084853

[365 rows x 2 columns]

发现测试结果和 实际结果相差不大

# 提取原始的最高温度数据
original_data = df[df['Location'] == location]['MaxTemp']

# 确保时间序列数据具有频率
original_data = original_data.asfreq('D')

# 使用插值法填补缺失值
original_data = original_data.interpolate(method='linear')

# 删除依然存在的缺失值
original_data = original_data.dropna()

# 获取季节性差分的基础值
seasonal_base = original_data.shift(365).dropna()

# 将差分后的预测值还原为原始的时间序列数据
restored_forecast = forecast + seasonal_base[-len(forecast):]

# 设置时间范围,显示测试集的最后一段时间
last_days = 365 # 可以根据需要调整
time_range = original_data.index[-last_days:]

# 绘制原始数据和还原后的预测值的详细对比图
plt.figure(figsize=(14, 10))
plt.plot(original_data[time_range], label='原始数据', color='blue', marker='o', markersize=3)
plt.plot(restored_forecast[time_range], label='还原后的预测值', color='red', linestyle='--', marker='x', markersize=3)
plt.fill_between(time_range, conf_int.iloc[:, 0][time_range] + seasonal_base[-len(forecast):][time_range],
                 conf_int.iloc[:, 1][time_range] + seasonal_base[-len(forecast):][time_range], color='pink', alpha=0.3)
plt.title(f'{location} 的最高温度原始数据与还原后的预测值对比 (详细)')
plt.xlabel('日期')
plt.ylabel('最高温度')
plt.grid(True)
plt.legend()
plt.show()

# 打印还原后的预测值
print(f'还原后的预测值: {restored_forecast}')
print(f'预测的置信区间: {conf_int}')

请添加图片描述

还原后的预测值: 2016-06-26    11.625669
2016-06-27    11.918487
2016-06-28    15.067825
2016-06-29     8.990562
2016-06-30    10.963980
                ...    
2017-06-21    11.744490
2017-06-22    13.844482
2017-06-23    13.344474
2017-06-24     8.344466
2017-06-25    10.644458
Freq: D, Length: 365, dtype: float64
预测的置信区间:             lower MaxTemp  upper MaxTemp
2016-06-26      -9.334773       6.186111
2016-06-27      -9.752366       8.789340
2016-06-28      -9.567745       9.703394
2016-06-29      -9.345149      10.126273
2016-06-30      -9.393319      10.121280
...                   ...            ...
2017-06-21      -9.795905      10.084886
2017-06-22      -9.795913      10.084877
2017-06-23      -9.795922      10.084869
2017-06-24      -9.795930      10.084861
2017-06-25      -9.795938      10.084853

[365 rows x 2 columns]

查看更详细的图

# 提取原始的最高温度数据
original_data = df[df['Location'] == location]['MaxTemp']

# 确保时间序列数据具有频率
original_data = original_data.asfreq('D')

# 使用插值法填补缺失值
original_data = original_data.interpolate(method='linear')

# 删除依然存在的缺失值
original_data = original_data.dropna()

# 获取季节性差分的基础值
seasonal_base = original_data.shift(365).dropna()

# 将差分后的预测值还原为原始的时间序列数据
restored_forecast = forecast + seasonal_base[-len(forecast):]

# 设置时间范围,显示测试集的最后一段时间
last_days = 30 # 可以根据需要调整
time_range = original_data.index[-last_days:]

# 绘制原始数据和还原后的预测值的详细对比图
plt.figure(figsize=(14, 10))
plt.plot(original_data[time_range], label='原始数据', color='blue', marker='o', markersize=3)
plt.plot(restored_forecast[time_range], label='还原后的预测值', color='red', linestyle='--', marker='x', markersize=3)
plt.fill_between(time_range, conf_int.iloc[:, 0][time_range] + seasonal_base[-len(forecast):][time_range],
                 conf_int.iloc[:, 1][time_range] + seasonal_base[-len(forecast):][time_range], color='pink', alpha=0.3)
plt.title(f'{location} 的最高温度原始数据与还原后的预测值对比 (详细)')
plt.xlabel('日期')
plt.ylabel('最高温度')
plt.grid(True)
plt.legend()
plt.show()

# 打印还原后的预测值
print(f'还原后的预测值: {restored_forecast}')
print(f'预测的置信区间: {conf_int}')

请添加图片描述

还原后的预测值: 2016-06-26    11.625669
2016-06-27    11.918487
2016-06-28    15.067825
2016-06-29     8.990562
2016-06-30    10.963980
                ...    
2017-06-21    11.744490
2017-06-22    13.844482
2017-06-23    13.344474
2017-06-24     8.344466
2017-06-25    10.644458
Freq: D, Length: 365, dtype: float64
预测的置信区间:             lower MaxTemp  upper MaxTemp
2016-06-26      -9.334773       6.186111
2016-06-27      -9.752366       8.789340
2016-06-28      -9.567745       9.703394
2016-06-29      -9.345149      10.126273
2016-06-30      -9.393319      10.121280
...                   ...            ...
2017-06-21      -9.795905      10.084886
2017-06-22      -9.795913      10.084877
2017-06-23      -9.795922      10.084869
2017-06-24      -9.795930      10.084861
2017-06-25      -9.795938      10.084853

[365 rows x 2 columns]

2所有地区

全部模型预测&详细信息

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
from statsmodels.tsa.stattools import adfuller, acf, pacf
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_squared_error
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.stats.diagnostic import acorr_ljungbox

# 读取数据
df = pd.read_csv('weatherAUS.csv')

# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei']  # 使用黑体
plt.rcParams['axes.unicode_minus'] = False  # 正常显示负号

# 按日期排序
df['Date'] = pd.to_datetime(df['Date'])
df.set_index('Date', inplace=True)

# 去除缺失值
df = df.dropna(subset=['MaxTemp'])

# 获取所有地点的列表
locations = df['Location'].unique()

# 创建一个字典来存储预测结果
forecasts = {}

# 遍历每个地点
for location in locations:
    print(f"正在处理地点: {location}")
    
    # 获取特定地点的数据
    location_data = df[df['Location'] == location]['MaxTemp']
    
    # 确保时间序列数据具有频率
    location_data = location_data.asfreq('D')
    
    # 使用插值法填补缺失值
    location_data = location_data.interpolate(method='linear')
    
    # 删除依然存在的缺失值
    location_data = location_data.dropna()
    
    # 绘制时间序列图
    plt.figure(figsize=(14, 6))
    plt.plot(location_data)
    plt.title(f'{location} 的最高温度时间序列')
    plt.xlabel('日期')
    plt.ylabel('最高温度')
    plt.grid(True)
    plt.show()
    
    # ADF平稳性检验
    adf_result = adfuller(location_data)
    print('ADF 检验结果:', adf_result)
    print(f'ADF统计量: {adf_result[0]}')
    print(f'p值: {adf_result[1]}')
    print(f'使用的滞后数: {adf_result[2]}')
    print(f'样本量: {adf_result[3]}')
    print('临界值:')
    for key, value in adf_result[4].items():
        print(f'    {key}: {value}')
    
    if adf_result[1] < 0.05:
        print("时间序列是平稳的")
    else:
        print("时间序列不是平稳的")
    
    # 分解时间序列,指定周期,比如一年365天
    decomposition = sm.tsa.seasonal_decompose(location_data, model='additive', period=365)
    fig = decomposition.plot()
    plt.show()
    
    # 绘制自相关函数(ACF)图
    plt.figure(figsize=(14, 6))
    plot_acf(location_data, lags=50)
    plt.title(f'{location} 的自相关函数(ACF)')
    plt.xlabel('滞后数')
    plt.ylabel('自相关')
    plt.grid(True)
    plt.show()
    
    # 进行季节性差分
    seasonal_diff = location_data.diff(365).dropna()
    
    # 绘制差分后的时间序列图
    plt.figure(figsize=(14, 6))
    plt.plot(seasonal_diff)
    plt.title(f'{location} 的最高温度季节性差分时间序列')
    plt.xlabel('日期')
    plt.ylabel('差分后的最高温度')
    plt.grid(True)
    plt.show()
    
    # 绘制差分后的自相关函数(ACF)图
    plt.figure(figsize=(14, 6))
    plot_acf(seasonal_diff, lags=50)
    plt.title(f'{location} 的最高温度季节性差分自相关函数(ACF)')
    plt.xlabel('滞后数')
    plt.ylabel('自相关')
    plt.grid(True)
    plt.show()
    
    # 绘制差分后的偏自相关函数(PACF)图
    plt.figure(figsize=(14, 6))
    plot_pacf(seasonal_diff, lags=50)
    plt.title(f'{location} 的最高温度季节性差分偏自相关函数(PACF)')
    plt.xlabel('滞后数')
    plt.ylabel('偏自相关')
    plt.grid(True)
    plt.show()
    
    # 季节性差分后的ADF检验
    result = adfuller(seasonal_diff.dropna())
    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))
    
    # 结果解读
    if result[1] > 0.05:
        print("季节性差分后的数据仍然是非平稳的")
    else:
        print("季节性差分后的数据是平稳的")
    
    # 白噪声检验
    print("差分序列的白噪声检验结果:\n", acorr_ljungbox(seasonal_diff.dropna(), lags=1))
    
    # 选择ARIMA模型参数
    order_select = sm.tsa.arma_order_select_ic(seasonal_diff.dropna(), ic=['bic'], trend='n', max_ar=5, max_ma=5)
    print('BIC选择的最佳参数:', order_select.bic_min_order)
    
    # 拆分训练集和测试集
    train_data = seasonal_diff[:-365]
    test_data = seasonal_diff[-365:]
    
    # 训练ARIMA模型
    model = ARIMA(train_data, order=(order_select.bic_min_order[0], 0, order_select.bic_min_order[1]))
    model_fit = model.fit()
    
    # 预测
    forecast_result = model_fit.get_forecast(steps=len(test_data))
    forecast = forecast_result.predicted_mean
    conf_int = forecast_result.conf_int()
    
    # 获取季节性差分的基础值
    seasonal_base = location_data.shift(365).dropna()
    
    # 将差分后的预测值还原为原始的时间序列数据
    restored_forecast = forecast + seasonal_base[-len(forecast):]
    
    # 存储预测结果
    forecasts[location] = {
        'forecast': restored_forecast,
        'conf_int': conf_int,
        'train_data': train_data,
        'test_data': test_data,
        'original_data': location_data
    }
    
    # 绘制原始数据和还原后的预测值的对比图(所有数据)
    plt.figure(figsize=(14, 10))
    plt.plot(location_data.index, location_data, label='原始数据', color='blue', marker='o', markersize=3)
    plt.plot(restored_forecast.index, restored_forecast, label='还原后的预测值', color='red', linestyle='--', marker='x', markersize=3)
    plt.fill_between(test_data.index, conf_int.iloc[:, 0] + seasonal_base[-len(forecast):],
                     conf_int.iloc[:, 1] + seasonal_base[-len(forecast):], color='pink', alpha=0.3)
    plt.title(f'{location} 的最高温度原始数据与还原后的预测值对比(所有数据)')
    plt.xlabel('日期')
    plt.ylabel('最高温度')
    plt.grid(True)
    plt.legend()
    plt.show()
    
    # 绘制原始数据和还原后的预测值的对比图(最后700天的数据)
    plt.figure(figsize=(14, 10))
    plt.plot(location_data.index[-700:], location_data[-700:], label='原始数据', color='blue', marker='o', markersize=3)
    plt.plot(restored_forecast.index[-365:], restored_forecast, label='还原后的预测值', color='red', linestyle='--', marker='x', markersize=3)
    plt.fill_between(test_data.index[-365:], conf_int.iloc[:, 0] + seasonal_base[-365:],
                     conf_int.iloc[:, 1] + seasonal_base[-365:], color='pink', alpha=0.3)
    plt.title(f'{location} 的最高温度原始数据与还原后的预测值对比(最后700天)')
    plt.xlabel('日期')
    plt.ylabel('最高温度')
    plt.grid(True)
    plt.legend()
    plt.show()
    
    plt.figure(figsize=(14, 10))
    plt.plot(location_data.index[-30:], location_data[-30:], label='原始数据', color='blue', marker='o', markersize=3)
    plt.plot(restored_forecast.index[-30:], restored_forecast[-30:], label='还原后的预测值', color='red', linestyle='--', marker='x', markersize=3)
    plt.fill_between(test_data.index[-30:], conf_int.iloc[:, 0].iloc[-30:] + seasonal_base.iloc[-30:],
                     conf_int.iloc[:, 1].iloc[-30:] + seasonal_base.iloc[-30:], color='pink', alpha=0.3)
    plt.title(f'{location} 的最高温度原始数据与还原后的预测值对比(最后30天)')
    plt.xlabel('日期')
    plt.ylabel('最高温度')
    plt.grid(True)
    plt.legend()
    plt.show()
    
    
    
    # 打印还原后的预测值
    print(f'还原后的预测值: {restored_forecast}')
    print(f'预测的置信区间: {conf_int}')

# 打印所有地点的预测结果
for location, result in forecasts.items():
    print(f"地点: {location}")
    print(f"还原后的预测值: {result['forecast']}")
    print(f"预测的置信区间: {result['conf_int']}")
    print("\n")

全部地区图片太多不舍得流量钱和COS存储详细请看github (暂未上传…


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值