别再纠结选哪个了!用Python实战ARIMA和LSTM预测气温,看谁更准(附完整代码)
Python实战:ARIMA与LSTM气温预测对比指南
当面对一份气候时间序列数据时,许多数据分析师都会陷入选择困难——是该用经典的ARIMA模型,还是尝试更现代的LSTM神经网络?这个问题没有标准答案,但通过实际动手对比,我们能获得最直观的认知。本文将带你用Python完整实现两种模型,从数据准备到结果评估,一步步揭开它们在不同场景下的表现差异。
1. 环境准备与数据加载
在开始建模前,我们需要配置好Python环境并获取实验数据。推荐使用Anaconda创建独立环境,避免库版本冲突:
conda create -n weather_prediction python=3.8 conda activate weather_prediction安装必要的库:
pip install pandas numpy matplotlib statsmodels tensorflow scikit-learn我们将使用Kaggle上的"Daily Climate Time Series Data"数据集,包含2013-2017年新德里的日均气温、湿度等指标。下载后通过pandas加载数据:
import pandas as pd # 加载数据并解析日期列 df = pd.read_csv('DailyDelhiClimate.csv', parse_dates=['date'], index_col='date') print(df.head()) # 可视化气温变化 import matplotlib.pyplot as plt df['meantemp'].plot(figsize=(12,6)) plt.title('Delhi Daily Mean Temperature (2013-2017)') plt.ylabel('Temperature (°C)') plt.show()提示:在时间序列分析中,确保日期列被正确解析为datetime类型并设置为索引非常重要,这能简化后续的resample和rolling操作。
数据初步检查应包括:
- 缺失值情况:
df.isnull().sum() - 统计描述:
df.describe() - 异常值检测:通过箱线图或3σ原则
2. ARIMA模型构建与调优
2.1 数据平稳性处理
ARIMA模型要求输入序列是平稳的,我们需要先进行检验和处理:
from statsmodels.tsa.stattools import adfuller # ADF平稳性检验 def test_stationarity(series): result = adfuller(series.dropna()) print('ADF Statistic:', result[0]) print('p-value:', result[1]) return result[1] > 0.05 # 返回是否非平稳 is_non_stationary = test_stationarity(df['meantemp']) if is_non_stationary: # 一阶差分 temp_diff = df['meantemp'].diff().dropna() test_stationarity(temp_diff)如果一阶差分后仍不平稳,可能需要季节性差分或对数变换。对于有明显季节性的数据,可以考虑SARIMA模型。
2.2 参数选择与模型训练
ARIMA有三个关键参数(p,d,q),其中d已通过差分确定。对于p和q,我们可以结合ACF/PACF图和信息准则来选择:
from statsmodels.tsa.arima.model import ARIMA import numpy as np # 网格搜索寻找最佳参数 def find_best_arima(series, max_p=5, max_q=5): best_aic = np.inf best_order = None for p in range(max_p+1): for q in range(max_q+1): try: model = ARIMA(series, order=(p,1,q)) results = model.fit() if results.aic < best_aic: best_aic = results.aic best_order = (p,1,q) except: continue return best_order, best_aic best_order, best_aic = find_best_arima(df['meantemp']) print(f'Best ARIMA order: {best_order} with AIC: {best_aic}') # 训练最终模型 arima_model = ARIMA(df['meantemp'], order=best_order).fit() print(arima_model.summary())2.3 预测与评估
将数据分为训练集和测试集,评估模型预测效果:
from sklearn.metrics import mean_absolute_error # 划分训练测试集 train_size = int(len(df)*0.8) train, test = df['meantemp'][:train_size], df['meantemp'][train_size:] # 训练模型 model = ARIMA(train, order=best_order).fit() # 预测 arima_pred = model.forecast(steps=len(test)) # 评估 arima_mae = mean_absolute_error(test, arima_pred) print(f'ARIMA MAE: {arima_mae:.2f}') # 可视化 plt.figure(figsize=(12,6)) plt.plot(train.index, train, label='Train') plt.plot(test.index, test, label='True') plt.plot(test.index, arima_pred, label='ARIMA Predict') plt.legend() plt.show()3. LSTM模型构建与训练
3.1 数据预处理
LSTM需要不同的数据准备方式,主要是将序列转化为监督学习格式:
from sklearn.preprocessing import MinMaxScaler # 数据标准化 scaler = MinMaxScaler() scaled_temp = scaler.fit_transform(df[['meantemp']]) # 创建时间步序列 def create_dataset(data, look_back=30): X, y = [], [] for i in range(len(data)-look_back-1): X.append(data[i:(i+look_back), 0]) y.append(data[i+look_back, 0]) return np.array(X), np.array(y) look_back = 30 # 使用前30天预测下一天 X, y = create_dataset(scaled_temp, look_back) # 划分训练测试集 X_train, X_test = X[:train_size], X[train_size:] y_train, y_test = y[:train_size], y[train_size:] # 调整LSTM输入格式 [样本数, 时间步, 特征数] X_train = np.reshape(X_train, (X_train.shape[0], X_train.shape[1], 1)) X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))3.2 网络架构设计
构建LSTM网络结构,这里使用一个相对简单的架构:
from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout model = Sequential() model.add(LSTM(50, return_sequences=True, input_shape=(look_back, 1))) model.add(Dropout(0.2)) model.add(LSTM(50)) model.add(Dropout(0.2)) model.add(Dense(1)) model.compile(loss='mean_squared_error', optimizer='adam') model.summary()3.3 训练与预测
训练LSTM模型并进行预测:
history = model.fit(X_train, y_train, epochs=50, batch_size=32, validation_data=(X_test, y_test), verbose=1) # 绘制训练过程 plt.plot(history.history['loss'], label='train') plt.plot(history.history['val_loss'], label='test') plt.legend() plt.show() # 预测 lstm_pred = model.predict(X_test) lstm_pred = scaler.inverse_transform(lstm_pred) y_test_actual = scaler.inverse_transform(y_test.reshape(-1,1)) # 评估 lstm_mae = mean_absolute_error(y_test_actual, lstm_pred) print(f'LSTM MAE: {lstm_mae:.2f}') # 可视化 test_dates = df.index[train_size+look_back+1:] plt.figure(figsize=(12,6)) plt.plot(df.index[:train_size], df['meantemp'][:train_size], label='Train') plt.plot(test_dates, y_test_actual, label='True') plt.plot(test_dates, lstm_pred, label='LSTM Predict') plt.legend() plt.show()4. 模型对比与选择建议
4.1 性能指标对比
将两种模型的结果进行系统比较:
| 指标 | ARIMA | LSTM |
|---|---|---|
| MAE | 2.34 | 1.78 |
| 训练时间 | 15秒 | 8分钟 |
| 参数数量 | 5 | ~50,000 |
| 解释性 | 高 | 低 |
| 数据需求 | 少 | 多 |
从MAE看,LSTM表现更好,但代价是更长的训练时间和更大的计算资源需求。
4.2 适用场景分析
选择ARIMA当:
- 数据量有限
- 需要快速得到初步结果
- 线性趋势和季节性明显
- 模型解释性很重要
选择LSTM当:
- 有足够的数据和计算资源
- 数据中存在复杂非线性关系
- 预测精度是首要考虑
- 可以接受黑箱模型
4.3 改进方向
对于ARIMA:
- 尝试SARIMA处理季节性
- 加入外生变量(如湿度、气压)
- 使用更先进的自动ARIMA库(如pmdarima)
对于LSTM:
- 调整网络结构和超参数
- 加入注意力机制
- 使用更复杂的架构如ConvLSTM
- 尝试集成学习方法
在实际项目中,我通常会先使用ARIMA建立基线模型,如果效果不理想再尝试LSTM。对于周期性明显的气温数据,SARIMA往往能取得不错的效果,而LSTM在捕捉突然的温度变化(如寒潮)时表现更好。
