Python實現(xiàn)時序數(shù)據(jù)預(yù)測的三種方法詳解
去年110,去年100,今年預(yù)測多少?別急著選模型,先搞清楚你手里的數(shù)據(jù)到底是什么類型。
一、先回答你的核心問題:這算時序數(shù)據(jù)嗎?
算。但要分情況。
你描述的場景:
| 時間 | 值 |
|---|---|
| 前年 | 110 |
| 去年 | 100 |
| 今年 | ? |
這是最簡單的時序數(shù)據(jù)——有時間順序,有數(shù)值變化,目的是往后推。
但你又說了一句關(guān)鍵的話:“可能一年有多個值”。
這就引出了三種完全不同的數(shù)據(jù)形態(tài),對應(yīng)三種不同的預(yù)測方法:
| 形態(tài) | 舉例 | 數(shù)據(jù)量 | 本質(zhì) |
|---|---|---|---|
| ① 一年一個值 | 2023→110, 2024→100, 2025→? | 極少(3~10個點) | 趨勢外推,不是嚴(yán)格時序 |
| ② 一年多個值(等間隔) | 2024年1月→50, 2月→55, … 12月→48 | 中等(12~幾百個點) | 標(biāo)準(zhǔn)時序數(shù)據(jù) ? |
| ③ 一年多個值(不等間隔) | 3月→100, 7月→90, 11月→85 | 少且不規(guī)則 | 不規(guī)則時序,需要特殊處理 |
結(jié)論:只要數(shù)據(jù)帶時間維度且你要往后推,就按時序思路做。但數(shù)據(jù)量決定了你能用多復(fù)雜的模型。
二、三種形態(tài),三套Python方案
形態(tài)①:一年就一個值(數(shù)據(jù)極少)
比如:前年110,去年100,今年預(yù)測多少?
說實話,這種情況不要用ARIMA,不要用LSTM,殺雞不用牛刀。
你只有2~3個點,復(fù)雜模型會過擬合到離譜。
最靠譜的三種方法:
| 方法 | 邏輯 | 適合場景 |
|---|---|---|
| 線性外推 | 畫一條直線往后延 | 趨勢穩(wěn)定、變化均勻 |
| 移動平均 | 取最近N個值的平均 | 數(shù)據(jù)有波動但無明顯趨勢 |
| 簡單增長率 | (100-110)/110 = -9.1%,今年≈91 | 變化比例相對穩(wěn)定 |
Python實現(xiàn)(線性外推):
import numpy as np
# 你的數(shù)據(jù):年份和對應(yīng)值
years = np.array([2023, 2024])
values = np.array([110, 100])
# 線性擬合:y = ax + b
a, b = np.polyfit(years, values, 1)
# 預(yù)測2025年
pred_2025 = a * 2025 + b
print(f"2025年預(yù)測值:{pred_2025:.1f}")
# 輸出:2025年預(yù)測值:90.0
趨勢是每年降10,今年預(yù)測90。簡單、可解釋、不會翻車。
形態(tài)②:一年多個值,等間隔(最常見)
比如:2024年每個月的銷售額,預(yù)測2025年每個月的值。
這是標(biāo)準(zhǔn)時序數(shù)據(jù),模型選擇最豐富:
| 模型 | 數(shù)據(jù)量要求 | 難度 | 推薦指數(shù) |
|---|---|---|---|
| 移動平均 / 指數(shù)平滑 | ≥12個點 | ? | ????? |
| Prophet | ≥24個點 | ? | ????? |
| ARIMA | ≥30個點 | ??? | ???? |
| XGBoost(特征工程后) | ≥50個點 | ?? | ???? |
重點推薦Prophet——它就是為這種"一年多個值"的場景設(shè)計的。
from prophet import Prophet
import pandas as pd
# 假設(shè)你有月度數(shù)據(jù)
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') # 預(yù)測未來12個月
forecast = model.predict(future)
print(forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail(12))
model.plot(forecast)
輸出類似:
| ds | yhat(預(yù)測值) | yhat_lower | yhat_upper |
|---|---|---|---|
| 2025-01 | 85.2 | 82.1 | 88.3 |
| 2025-02 | 84.8 | 81.5 | 88.1 |
| … | … | … | … |
Prophet會自動處理季節(jié)性(比如每年12月都高),而且對缺失值友好,實測最省心。
形態(tài)③:一年多個值,但不等間隔
比如:3月→100,7月→90,11月→85,沒有固定頻率。
這種叫不規(guī)則時序(Irregular Time Series)。
處理思路:先補(bǔ)成等間隔,再用標(biāo)準(zhǔn)方法。
import pandas as pd
import numpy as np
# 原始不規(guī)則數(shù)據(jù)
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:線性插值補(bǔ)成月度
df_monthly = df.set_index('date').resample('MS').interpolate(method='linear')
print(df_monthly)
# 補(bǔ)完之后,就可以用Prophet或ARIMA了
核心原則:不規(guī)則 → 先規(guī)則化 → 再預(yù)測。
三、一張圖幫你選方法
你有多少個數(shù)據(jù)點?
│
├─ ≤ 10個 ──→ 線性外推 / 移動平均(別用復(fù)雜模型)
│
├─ 10~50個 ──→ Prophet(首選)/ 指數(shù)平滑
│
└─ >50個 ──→ ARIMA / XGBoost + 特征工程
│
└─ 有明顯季節(jié)性?──→ Prophet / SARIMA
└─ 多變量影響?──→ XGBoost(把時間拆成特征)
四、新手最容易犯的錯
| 錯誤 | 為什么錯 | 正確做法 |
|---|---|---|
| 3個點就上LSTM | 數(shù)據(jù)太少,模型在"編故事" | 先用線性外推打底 |
| 一年多個值但不處理季節(jié) | 12月和1月差異被當(dāng)噪聲 | 用Prophet或手動加月份特征 |
| 把2024全年數(shù)據(jù)拿去訓(xùn)練,預(yù)測2024年 | 這是回測,不是預(yù)測 | 必須按時間切分,不能穿越 |
| 只看預(yù)測值,不看區(qū)間 | 點預(yù)測沒有意義 | 一定看置信區(qū)間(yhat_lower ~ yhat_upper) |
五、知識擴(kuò)展
數(shù)據(jù)準(zhǔn)備與基本概念
在進(jìn)行任何預(yù)測前,通常需要:
- 將數(shù)據(jù)轉(zhuǎn)換為
pandas.DataFrame,時間列設(shè)為索引。 - 檢查缺失值、異常值,必要時填充。
- 觀察平穩(wěn)性(ADF檢驗)、趨勢、季節(jié)性。
- 劃分訓(xùn)練集和測試集(注意:不能隨機(jī)打亂,必須按時間順序劃分)。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
# 加載示例數(shù)據(jù)(如航空旅客數(shù))
df = pd.read_csv('airline_passengers.csv', parse_dates=['Month'], index_col='Month')
series = df['Passengers']
# 平穩(wěn)性檢驗
result = adfuller(series)
print(f'ADF Statistic: {result[0]}, p-value: {result[1]}') # p>0.05 非平穩(wěn)
# 一階差分
diff_series = series.diff().dropna()經(jīng)典統(tǒng)計方法
1. ARIMA (自回歸積分滑動平均模型)
ARIMA 是最常用的線性時間序列模型,適用于單變量、有平穩(wěn)性要求的數(shù)據(jù)。參數(shù) (p,d,q) 分別表示自回歸階數(shù)、差分次數(shù)、移動平均階數(shù)。
步驟:
- 確定
d(差分次數(shù),使序列平穩(wěn))。 - 通過 ACF/PACF 圖選擇
p和q。 - 訓(xùn)練模型并進(jìn)行預(yù)測。
from statsmodels.tsa.arima.model import ARIMA
from sklearn.metrics import mean_absolute_error
# 拆分訓(xùn)練/測試(前80%訓(xùn)練,后20%測試)
train = series[:int(0.8*len(series))]
test = series[int(0.8*len(series)):]
# 訓(xùn)練 ARIMA 模型 (示例參數(shù),實際需調(diào)優(yōu))
model = ARIMA(train, order=(5,1,0))
fitted = model.fit()
# 預(yù)測
forecast = fitted.forecast(steps=len(test))
mae = mean_absolute_error(test, forecast)
print(f'MAE: {mae:.2f}')2. SARIMA (季節(jié)性 ARIMA)
當(dāng)數(shù)據(jù)有明顯周期性(如月度、季度)時,使用 SARIMA,加入季節(jié)性參數(shù) (P,D,Q,s)。
from statsmodels.tsa.statespace.sarimax import SARIMAX # 季節(jié)性周期 s=12(月度數(shù)據(jù)) 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 (指數(shù)平滑)
簡單且效果不錯的平滑方法,包括 Holt-Winters 三參數(shù)模型(可處理趨勢和季節(jié))。
from statsmodels.tsa.holtwinters import ExponentialSmoothing model = ExponentialSmoothing(train, trend='add', seasonal='add', seasonal_periods=12) fitted = model.fit() forecast = fitted.forecast(len(test))
機(jī)器學(xué)習(xí)方法
機(jī)器學(xué)習(xí)方法通常需要構(gòu)造特征,將時間序列轉(zhuǎn)換為監(jiān)督學(xué)習(xí)問題。常用特征包括:滯后值(lags)、滾動統(tǒng)計量(均值、標(biāo)準(zhǔn)差)、時間特征(年、月、日、星期幾)、外部變量。
使用 XGBoost / LightGBM 進(jìn)行預(yù)測
import xgboost as xgb
from sklearn.model_selection import train_test_split
# 構(gòu)造特征:使用過去 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:]
# 訓(xùn)練 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}')優(yōu)點:可處理非線性、可加入外部特征(如天氣、促銷等)。
缺點:本身不能直接捕捉時間依賴性,需要手工構(gòu)造滯后特征。
深度學(xué)習(xí)方法:LSTM (長短期記憶網(wǎng)絡(luò))
LSTM 專門用于處理序列數(shù)據(jù),能自動學(xué)習(xí)長期依賴關(guān)系。通常需要將數(shù)據(jù)縮放至 [0,1] 區(qū)間,并構(gòu)建 3D 輸入 (samples, timesteps, features)。
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
# 數(shù)據(jù)歸一化
scaler = MinMaxScaler()
scaled = scaler.fit_transform(series.values.reshape(-1,1))
# 構(gòu)造監(jiān)督學(xué)習(xí)樣本 (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 輸入格式 (樣本數(shù), 時間步長, 特征數(shù))
X = X.reshape((X.shape[0], X.shape[1], 1))
# 劃分訓(xùn)練/測試
split = int(0.8 * len(X))
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]
# 構(gòu)建 LSTM 模型
model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(lookback, 1)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
# 訓(xùn)練
model.fit(X_train, y_train, epochs=50, batch_size=32, verbose=0)
# 預(yù)測并反歸一化
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 訓(xùn)練較慢,需要更多數(shù)據(jù),且調(diào)參復(fù)雜。
六、總結(jié)
| 你的場景 | 屬于什么 | 推薦方法 |
|---|---|---|
| 前年110,去年100,預(yù)測今年 | 趨勢外推(極簡時序) | np.polyfit 線性外推 |
| 每月一個值,連續(xù)2年+ | 標(biāo)準(zhǔn)時序 ? | Prophet(首選) |
| 時間點不固定,一年幾個值 | 不規(guī)則時序 | 先resample補(bǔ)齊,再Prophet |
最后一句話:你的數(shù)據(jù)肯定是時序數(shù)據(jù)。區(qū)別只在于——你有多少個點,決定了你能用多復(fù)雜的模型。點數(shù)少,就用簡單方法,反而更準(zhǔn)。
如果你把實際數(shù)據(jù)(哪怕只是幾行)發(fā)給我,我可以直接幫你判斷屬于哪種形態(tài),并寫出能跑的代碼。
到此這篇關(guān)于Python實現(xiàn)時序數(shù)據(jù)預(yù)測的三種方法詳解的文章就介紹到這了,更多相關(guān)Python時序數(shù)據(jù)預(yù)測內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Pandas實現(xiàn)Excel文件讀取,增刪,打開,保存操作
Pandas?是一種基于?NumPy?的開源數(shù)據(jù)分析工具,用于處理和分析大量數(shù)據(jù)。本文將通過Pandas實現(xiàn)對Excel文件進(jìn)行讀取、增刪、打開、保存等操作,需要的可以參考一下2023-04-04
pycharm社區(qū)版安裝node.js插件運行js代碼方法
PyCharm可以說是當(dāng)今最流行的一款Python IDE了,下面這篇文章主要給大家介紹了關(guān)于pycharm社區(qū)版安裝node.js插件運行js代碼的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10

