Python实现时序数据预测的三种方法详解
作者:detayun
去年110,去年100,今年预测多少?别急着选模型,先搞清楚你手里的数据到底是什么类型。
一、先回答你的核心问题:这算时序数据吗?
算。但要分情况。
你描述的场景:
| 时间 | 值 |
|---|---|
| 前年 | 110 |
| 去年 | 100 |
| 今年 | ? |
这是最简单的时序数据——有时间顺序,有数值变化,目的是往后推。
但你又说了一句关键的话:“可能一年有多个值”。
这就引出了三种完全不同的数据形态,对应三种不同的预测方法:
| 形态 | 举例 | 数据量 | 本质 |
|---|---|---|---|
| ① 一年一个值 | 2023→110, 2024→100, 2025→? | 极少(3~10个点) | 趋势外推,不是严格时序 |
| ② 一年多个值(等间隔) | 2024年1月→50, 2月→55, … 12月→48 | 中等(12~几百个点) | 标准时序数据 ✅ |
| ③ 一年多个值(不等间隔) | 3月→100, 7月→90, 11月→85 | 少且不规则 | 不规则时序,需要特殊处理 |
结论:只要数据带时间维度且你要往后推,就按时序思路做。但数据量决定了你能用多复杂的模型。
二、三种形态,三套Python方案
形态①:一年就一个值(数据极少)
比如:前年110,去年100,今年预测多少?
说实话,这种情况不要用ARIMA,不要用LSTM,杀鸡不用牛刀。
你只有2~3个点,复杂模型会过拟合到离谱。
最靠谱的三种方法:
| 方法 | 逻辑 | 适合场景 |
|---|---|---|
| 线性外推 | 画一条直线往后延 | 趋势稳定、变化均匀 |
| 移动平均 | 取最近N个值的平均 | 数据有波动但无明显趋势 |
| 简单增长率 | (100-110)/110 = -9.1%,今年≈91 | 变化比例相对稳定 |
Python实现(线性外推):
import numpy as np
# 你的数据:年份和对应值
years = np.array([2023, 2024])
values = np.array([110, 100])
# 线性拟合:y = ax + b
a, b = np.polyfit(years, values, 1)
# 预测2025年
pred_2025 = a * 2025 + b
print(f"2025年预测值:{pred_2025:.1f}")
# 输出:2025年预测值:90.0
趋势是每年降10,今年预测90。简单、可解释、不会翻车。
形态②:一年多个值,等间隔(最常见)
比如:2024年每个月的销售额,预测2025年每个月的值。
这是标准时序数据,模型选择最丰富:
| 模型 | 数据量要求 | 难度 | 推荐指数 |
|---|---|---|---|
| 移动平均 / 指数平滑 | ≥12个点 | ⭐ | ⭐⭐⭐⭐⭐ |
| Prophet | ≥24个点 | ⭐ | ⭐⭐⭐⭐⭐ |
| ARIMA | ≥30个点 | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| XGBoost(特征工程后) | ≥50个点 | ⭐⭐ | ⭐⭐⭐⭐ |
重点推荐Prophet——它就是为这种"一年多个值"的场景设计的。
from prophet import Prophet
import pandas as pd
# 假设你有月度数据
df = pd.DataFrame({
'ds': pd.date_range('2023-01-01', periods=24, freq='MS'), # 24个月
'y': [110, 108, 105, 103, 100, 98, 95, 97, 99, 102, 100, 98,
96, 94, 91, 89, 88, 90, 92, 95, 93, 91, 89, 87]
})
model = Prophet(yearly_seasonality=True, weekly_seasonality=False)
model.fit(df)
future = model.make_future_dataframe(periods=12, freq='MS') # 预测未来12个月
forecast = model.predict(future)
print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail(12))
model.plot(forecast)
输出类似:
| ds | yhat(预测值) | yhat_lower | yhat_upper |
|---|---|---|---|
| 2025-01 | 85.2 | 82.1 | 88.3 |
| 2025-02 | 84.8 | 81.5 | 88.1 |
| … | … | … | … |
Prophet会自动处理季节性(比如每年12月都高),而且对缺失值友好,实测最省心。
形态③:一年多个值,但不等间隔
比如:3月→100,7月→90,11月→85,没有固定频率。
这种叫不规则时序(Irregular Time Series)。
处理思路:先补成等间隔,再用标准方法。
import pandas as pd
import numpy as np
# 原始不规则数据
data = [
('2024-03-01', 100),
('2024-07-15', 90),
('2024-11-20', 85),
]
df = pd.DataFrame(data, columns=['date', 'value'])
df['date'] = pd.to_datetime(df['date'])
# 方法1:重采样为季度(最简单)
df_quarterly = df.set_index('date').resample('Q').mean()
print(df_quarterly)
# 方法2:线性插值补成月度
df_monthly = df.set_index('date').resample('MS').interpolate(method='linear')
print(df_monthly)
# 补完之后,就可以用Prophet或ARIMA了
核心原则:不规则 → 先规则化 → 再预测。
三、一张图帮你选方法
你有多少个数据点?
│
├─ ≤ 10个 ──→ 线性外推 / 移动平均(别用复杂模型)
│
├─ 10~50个 ──→ Prophet(首选)/ 指数平滑
│
└─ >50个 ──→ ARIMA / XGBoost + 特征工程
│
└─ 有明显季节性?──→ Prophet / SARIMA
└─ 多变量影响?──→ XGBoost(把时间拆成特征)
四、新手最容易犯的错
| 错误 | 为什么错 | 正确做法 |
|---|---|---|
| 3个点就上LSTM | 数据太少,模型在"编故事" | 先用线性外推打底 |
| 一年多个值但不处理季节 | 12月和1月差异被当噪声 | 用Prophet或手动加月份特征 |
| 把2024全年数据拿去训练,预测2024年 | 这是回测,不是预测 | 必须按时间切分,不能穿越 |
| 只看预测值,不看区间 | 点预测没有意义 | 一定看置信区间(yhat_lower ~ yhat_upper) |
五、知识扩展
数据准备与基本概念
在进行任何预测前,通常需要:
- 将数据转换为
pandas.DataFrame,时间列设为索引。 - 检查缺失值、异常值,必要时填充。
- 观察平稳性(ADF检验)、趋势、季节性。
- 划分训练集和测试集(注意:不能随机打乱,必须按时间顺序划分)。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
# 加载示例数据(如航空旅客数)
df = pd.read_csv('airline_passengers.csv', parse_dates=['Month'], index_col='Month')
series = df['Passengers']
# 平稳性检验
result = adfuller(series)
print(f'ADF Statistic: {result[0]}, p-value: {result[1]}') # p>0.05 非平稳
# 一阶差分
diff_series = series.diff().dropna()经典统计方法
1. ARIMA (自回归积分滑动平均模型)
ARIMA 是最常用的线性时间序列模型,适用于单变量、有平稳性要求的数据。参数 (p,d,q) 分别表示自回归阶数、差分次数、移动平均阶数。
步骤:
- 确定
d(差分次数,使序列平稳)。 - 通过 ACF/PACF 图选择
p和q。 - 训练模型并进行预测。
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_absolute_error
# 拆分训练/测试(前80%训练,后20%测试)
train = series[:int(0.8*len(series))]
test = series[int(0.8*len(series)):]
# 训练 ARIMA 模型 (示例参数,实际需调优)
model = ARIMA(train, order=(5,1,0))
fitted = model.fit()
# 预测
forecast = fitted.forecast(steps=len(test))
mae = mean_absolute_error(test, forecast)
print(f'MAE: {mae:.2f}')2. SARIMA (季节性 ARIMA)
当数据有明显周期性(如月度、季度)时,使用 SARIMA,加入季节性参数 (P,D,Q,s)。
from statsmodels.tsa.statespace.sarimax import SARIMAX # 季节性周期 s=12(月度数据) model = SARIMAX(train, order=(1,1,1), seasonal_order=(1,1,1,12)) fitted = model.fit() forecast = fitted.forecast(steps=len(test))
3. Exponential Smoothing (指数平滑)
简单且效果不错的平滑方法,包括 Holt-Winters 三参数模型(可处理趋势和季节)。
from statsmodels.tsa.holtwinters import ExponentialSmoothing model = ExponentialSmoothing(train, trend='add', seasonal='add', seasonal_periods=12) fitted = model.fit() forecast = fitted.forecast(len(test))
机器学习方法
机器学习方法通常需要构造特征,将时间序列转换为监督学习问题。常用特征包括:滞后值(lags)、滚动统计量(均值、标准差)、时间特征(年、月、日、星期几)、外部变量。
使用 XGBoost / LightGBM 进行预测
import xgboost as xgb
from sklearn.model_selection import train_test_split
# 构造特征:使用过去 12 个值作为特征
def create_features(data, lookback=12):
X, y = [], []
for i in range(lookback, len(data)):
X.append(data[i-lookback:i])
y.append(data[i])
return np.array(X), np.array(y)
values = series.values
X, y = create_features(values, lookback=12)
# 按时间顺序划分(不能打乱)
split = int(0.8 * len(X))
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]
# 训练 XGBoost 模型
model = xgb.XGBRegressor(n_estimators=100, learning_rate=0.01)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
# 评估
mae = mean_absolute_error(y_test, y_pred)
print(f'XGBoost MAE: {mae:.2f}')优点:可处理非线性、可加入外部特征(如天气、促销等)。
缺点:本身不能直接捕捉时间依赖性,需要手工构造滞后特征。
深度学习方法:LSTM (长短期记忆网络)
LSTM 专门用于处理序列数据,能自动学习长期依赖关系。通常需要将数据缩放至 [0,1] 区间,并构建 3D 输入 (samples, timesteps, features)。
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
# 数据归一化
scaler = MinMaxScaler()
scaled = scaler.fit_transform(series.values.reshape(-1,1))
# 构造监督学习样本 (lookback=12)
lookback = 12
X, y = [], []
for i in range(lookback, len(scaled)):
X.append(scaled[i-lookback:i, 0])
y.append(scaled[i, 0])
X, y = np.array(X), np.array(y)
# 重塑为 LSTM 输入格式 (样本数, 时间步长, 特征数)
X = X.reshape((X.shape[0], X.shape[1], 1))
# 划分训练/测试
split = int(0.8 * len(X))
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]
# 构建 LSTM 模型
model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(lookback, 1)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
# 训练
model.fit(X_train, y_train, epochs=50, batch_size=32, verbose=0)
# 预测并反归一化
y_pred_scaled = model.predict(X_test)
y_pred = scaler.inverse_transform(y_pred_scaled)
y_true = scaler.inverse_transform(y_test.reshape(-1,1))
mae = mean_absolute_error(y_true, y_pred)
print(f'LSTM MAE: {mae:.2f}')注意:LSTM 训练较慢,需要更多数据,且调参复杂。
六、总结
| 你的场景 | 属于什么 | 推荐方法 |
|---|---|---|
| 前年110,去年100,预测今年 | 趋势外推(极简时序) | np.polyfit 线性外推 |
| 每月一个值,连续2年+ | 标准时序 ✅ | Prophet(首选) |
| 时间点不固定,一年几个值 | 不规则时序 | 先resample补齐,再Prophet |
最后一句话:你的数据肯定是时序数据。区别只在于——你有多少个点,决定了你能用多复杂的模型。点数少,就用简单方法,反而更准。
如果你把实际数据(哪怕只是几行)发给我,我可以直接帮你判断属于哪种形态,并写出能跑的代码。
到此这篇关于Python实现时序数据预测的三种方法详解的文章就介绍到这了,更多相关Python时序数据预测内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
