
簡介這套基于 Python 深度學習的多特征電力負荷預測項目面向課程設計與期末大作業場景適合希望掌握 LSTM 建模與實際預測流程的學生項目以真實電力負荷數據為輸入融合溫度、濕度等多維特征利用長短時記憶網絡捕捉時序規律適用于教學演示與實際場景訓練。壓縮包共 8 個文件包含 3 個 Python 腳本、2 個 CSV 數據文件、xlsx 原始數據表以及 README 和使用說明整體僅 831KB結構簡潔清晰其中 py 文件分別負責數據清洗、模型訓練與結果繪圖csv 提供訓練集與待預測數據md 文檔則記錄復現步驟。已有 479 人學習下載作為高分課設項目提供數據預處理、LSTM 負荷預測、結果可視化等完整模塊下載后無需修改即可運行可直接用于答辯展示。通過閱讀源碼與注釋可以快速理解多特征電力負荷預測的實現思路并在此基礎上擴展調參或更換數據集。1. 多特征電力負荷預測項目的真實難點數據比模型更花時間拿到“基于python深度學習的多特征電力負荷預測項目源碼數據課程設計.zip”這個標題先別急著解壓跑模型。電力負荷預測是典型的時序回歸問題但讓它難的不是LSTM本身而是“多特征”三個字。只看歷史負荷曲線做預測節假日和極端天氣一來就崩把溫度、濕度、星期類型、峰谷時段全部塞進模型又容易陷入特征噪聲和維度災難。課程設計階段最常見的失敗不是模型不收斂而是數據處理和特征對齊根本沒做對。你缺的不是源碼而是把源碼拆開、改特征、調參數、換數據后還能跑通的能力。這篇文章不評價任何特定項目包只講此類項目最通用、最經得起答辯追問的實現套路特征工程怎么建、LSTM怎么搭、訓練參數怎么調、結果怎么對比。2. 電力負荷預測里的多特征工程先搞清滑動窗口與特征對齊2.1 單序列預測的局限與多特征的價值很多課程設計最初版本只用歷史負荷去預測未來負荷輸入是[t-24, t-23, ..., t-1]輸出是t時刻的負荷值。這個結構在負荷規律穩定的工作日表現尚可但遇到以下情況會明顯失靈周一早高峰負荷模式與周日完全不同純負荷序列無法感知“今天是周幾”夏季高溫日空調負荷激增歷史負荷序列中看不到“今天35度”這個信號法定節假日負荷腰斬模型只知道昨天和前幾天都高不知道今天放假所以“多特征”的第一層含義是補上負荷序列之外的外生變量。第二層含義是這些外生變量必須與負荷序列在時間軸上嚴格對齊并且按相同的步長滑窗。2.2 輸入特征矩陣的構建代碼以小時級負荷數據為例我一般會把原始表設計成下面這樣每行代表一個小時特征字段示例處理方式load532.6 MW目標值做滯后特征temperature28.4 ℃數值型直接入模humidity76 %數值型直接入模hour14周期編碼為sin/cosweekday3周期編碼為sin/cosis_holiday00/1二值峰谷時段峰one-hot或LabelEncoder代碼上核心切成兩步第一步制作滯后特征lag features第二步將原始表切成[樣本數, 時間步長, 特征數]的三維張量。import pandas as pd import numpy as np df pd.read_csv(load_data.csv, parse_dates[date]) df df.sort_values(date).reset_index(dropTrue) # 特征列與目標列分離 feature_cols [temperature, humidity, hour_sin, hour_cos, weekday_sin, weekday_cos, is_holiday, peak_type] target_col load # 滯后特征過去24小時負荷 for lag in [1, 2, 3, 24, 168]: df[fload_lag_{lag}] df[load].shift(lag) feature_cols [load_lag_1, load_lag_2, load_lag_3, load_lag_24, load_lag_168] # 刪除前168行滯后168小時產生的NaN df df.dropna().reset_index(dropTrue)這里對滯后特征做三點說明load_lag_1捕捉短期慣性load_lag_24捕捉日周期load_lag_168捕捉周周期。滯后階數的選擇依據是電力負荷存在明顯的“日周期性”和“周周期性”不相關的滯后項只會增加噪聲。溫度、濕度是否做滯后取決于數據表是否包含預測時刻的天氣預報值如果沒有常見做法是用預測日的氣象預報數據替代這也是為什么很多課程設計項目把溫度特征直接對齊到預測時刻。2.3 滑動窗口切分與歸一化順序有了完整的特征寬表后需要把它切成LSTM輸入需要的三維結構。窗口長度通常取24或48即用過去24/48小時的所有特征預測下一個小時。def create_sequences(data, feature_cols, target_col, window24): X, y [], [] for i in range(len(data) - window): X.append(data[feature_cols].iloc[i:iwindow].values) y.append(data[target_col].iloc[iwindow]) return np.array(X), np.array(y) X, y create_sequences(df, feature_cols, target_col, window24) print(X.shape) # (樣本數, 24, 特征數)歸一化必須先在訓練集上fit再transform驗證集與測試集。機器學習中一個經典的錯誤是拿全量數據做歸一化導致驗證集信息泄漏到訓練過程里模型表現虛高答辯時被問幾句就會露餡。from sklearn.preprocessing import MinMaxScaler # 將三維X還原為二維做歸一化再還原回三維 X_2d X.reshape(-1, X.shape[-1]) scaler_X MinMaxScaler() X_2d_scaled scaler_X.fit_transform(X_2d) X_scaled X_2d_scaled.reshape(X.shape) # 目標值單獨歸一化 scaler_y MinMaxScaler() y_scaled scaler_y.fit_transform(y.reshape(-1, 1)).flatten()3. 基于PyTorch的LSTM多變量負荷預測模型從Dataset到前向傳播3.1 模型選型為什么課程設計首選LSTM電力負荷預測的模型選項很多ARIMA、XGBoost、LSTM、GRU、Transformer。課程設計場景下LSTM是綜合性價比最高的選擇。ARIMA對多特征外生變量的支持較弱XGBoost需要手動構造時序特征才能模擬時間依賴Transformer在小數據集上容易過擬合調參成本高。LSTM的結構天然適合序列建模而且PyTorch封裝完善手寫一個LSTM模型只需要幾十行代碼。多特征LSTM和單特征LSTM在模型結構上的區別只在輸入維度input_size。輸入維度等于特征矩陣的列數每個時間步輸入一個包含溫度、濕度、時刻、滯后負荷等所有特征的向量。下面給出一個可運行的多層LSTM回歸模型。import torch import torch.nn as nn class MultiFeatureLSTM(nn.Module): def __init__(self, input_size, hidden_size64, num_layers2, dropout0.2): super().__init__() self.lstm nn.LSTM( input_sizeinput_size, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue, dropoutdropout ) self.regressor nn.Sequential( nn.Linear(hidden_size, 32), nn.ReLU(), nn.Dropout(dropout), nn.Linear(32, 1) ) def forward(self, x): # x: (batch, seq_len, input_size) lstm_out, _ self.lstm(x) # 取最后一個時間步的輸出 last_out lstm_out[:, -1, :] return self.regressor(last_out).squeeze(-1)模型的關鍵設計點batch_firstTrue讓輸入張量的形狀更符合直覺第一維是batch。num_layers2堆疊兩層LSTM以增強非線性表達能力但層數不是越多越好后面會講為什么課程設計里3層以上收益很小。regressor是回歸頭將LSTM最后一個時間步的隱含狀態映射成標量負荷值。取lstm_out[:, -1, :]是時序預測的標準做法它表示用整個窗口的信息匯總后做預測。3.2 Dataset封裝與數據加載器光有模型還不夠PyTorch要求數據經過Dataset和DataLoader封裝才能進入訓練循環。封裝的核心價值在于打亂樣本順序、按batch迭代、支持多線程讀取。from torch.utils.data import Dataset, DataLoader class LoadDataset(Dataset): def __init__(self, X, y): self.X torch.tensor(X, dtypetorch.float32) self.y torch.tensor(y, dtypetorch.float32) def __len__(self): return len(self.X) def __getitem__(self, idx): return self.X[idx], self.y[idx] # 按時間順序切分前70%訓練后30%測試不打亂時序 train_size int(len(X_scaled) * 0.7) X_train, X_test X_scaled[:train_size], X_scaled[train_size:] y_train, y_test y_scaled[:train_size], y_scaled[train_size:] train_dataset LoadDataset(X_train, y_train) test_dataset LoadDataset(X_test, y_test) train_loader DataLoader(train_dataset, batch_size64, shuffleTrue) test_loader DataLoader(test_dataset, batch_size64, shuffleFalse)shuffleTrue只作用于訓練集打亂的是樣本間的順序不會破壞單個樣本內的時間步順序。測試集必須shuffleFalse否則預測結果和真實值對不上時間軸后續畫圖會錯位。batch_size和窗口長度是兩個容易混淆的概念窗口長度是單個樣本包含多少歷史時間步batch_size是每次迭代同時處理多少個樣本。4. 深度學習訓練參數解析學習率、早停與損失函數選擇4.1 訓練循環模板與早停機制數據準備好了模型也定義了接下來是訓練循環。課程設計階段不推薦直接抄開源訓練腳本而要理解每個關鍵環節在做什么。下面這個訓練函數包含學習率衰減和早停是訓練LSTM最實用的組合。import torch.optim as optim model MultiFeatureLSTM( input_sizeX_train.shape[-1], hidden_size64, num_layers2, dropout0.2 ) optimizer optim.Adam(model.parameters(), lr1e-3) scheduler optim.lr_scheduler.ReduceLROnPlateau( optimizer, modemin, factor0.5, patience8 ) criterion nn.MSELoss() epochs 100 best_loss float(inf) patience_counter 0 for epoch in range(epochs): model.train() train_loss 0 for X_batch, y_batch in train_loader: optimizer.zero_grad() y_pred model(X_batch) loss criterion(y_pred, y_batch) loss.backward() # 梯度裁剪防止LSTM梯度爆炸 torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0) optimizer.step() train_loss loss.item() * len(X_batch) # 驗證集上評估決定是否早停 model.eval() val_loss 0 with torch.no_grad(): for X_batch, y_batch in test_loader: y_pred model(X_batch) val_loss criterion(y_pred, y_batch).item() * len(X_batch) val_loss / len(X_test) scheduler.step(val_loss) if val_loss best_loss: best_loss val_loss patience_counter 0 torch.save(model.state_dict(), best_model.pth) else: patience_counter 1 if patience_counter 15: print(fearly stop at epoch {epoch 1}) break損失函數用MSE是負荷預測任務中的默認選擇因為它對大幅偏差懲罰更重。但需要知道MSE的缺點是量綱是平方不能直觀表示誤差百分比所以后面評估時還要計算MAE和MAPE。梯度裁剪clip_grad_norm_對LSTM很重要梯度范數超過1.0時會被壓縮防止RNN類模型常見的梯度爆炸。ReduceLROnPlateau每8輪驗證損失不下降就把學習率減半比固定學習率600輪更穩。4.2 關鍵超參數推薦范圍與調整邏輯課程設計里超參數調優不用做網格搜索按經驗區間給幾組對照實驗就夠了。下表是常見參數的經驗范圍參數名推薦范圍調整方向window_size24~72負荷波動周期越長窗口越要拉長hidden_size32~128特征多、數據量大時上調num_layers1~3超過3層收益極小且訓練更慢dropout0.1~0.3過擬合時增大欠擬合時減小或關閉batch_size32~128數據量小時用小batchlearning_rate5e-4~1e-3loss震蕩時下調下降太慢可上調patience10~20早停輪數配合ReduceLROnPlateauwindow_size24表示用過去24小時預測下一個小時適合以天為周期的負荷數據。如果數據是按15分鐘采樣的同樣的日周期需要96個時間步窗口取96附近。hidden_size在64是個安全起點特征維度低時32足夠加入更多天氣特征后可試128。num_layers2是多數課程設計項目的甜點1層欠擬合3層以上在小數據量下表現為驗證損失不降反升不是模型能力不夠而是過擬合。4.3 訓練過程常見異常排查訓練LSTM最常見的異常有四種。第一種是loss曲線完全不動此時優先檢查學習率是否過小、歸一化是否完成、數據里是否有NaN。第二種是loss爆炸到inf大概率是梯度爆炸先調clip_grad_norm_的max_norm到0.5或1.0。第三種是訓練集loss持續下降而驗證集loss升高這是過擬合信號調整dropout和早停參數。第四種是測試集整體偏移一個常數檢查y歸一化后預測是否反歸一化時用了錯誤的scaler。反歸一化漏了是課程設計項目里最常見的“模型分很高但圖不對”的原因。5. 多特征負荷預測的評估與課程設計結果呈現不只跑出數字5.1 回歸指標的計算與選擇課程設計答辯時老師最常問的問題之一是“你這個模型效果怎么衡量”。只用loss曲線沒有說服力需要用回歸指標給出量化結論。負荷預測的通用指標是MAE、RMSE、MAPE三個一起給才有意義。def evaluate_metrics(y_true, y_pred): mae np.mean(np.abs(y_true - y_pred)) rmse np.sqrt(np.mean((y_true - y_pred) ** 2)) mape np.mean(np.abs((y_true - y_pred) / y_true)) * 100 return {MAE: mae, RMSE: rmse, MAPE: mape} # 反歸一化后再算指標 model.eval() with torch.no_grad(): X_tensor torch.tensor(X_test, dtypetorch.float32) y_pred_scaled model(X_tensor).numpy() y_pred scaler_y.inverse_transform(y_pred_scaled.reshape(-1, 1)).flatten() y_true scaler_y.inverse_transform(y_test.reshape(-1, 1)).flatten() metrics evaluate_metrics(y_true, y_pred) print(metrics)三個指標各有偏向。RMSE對大幅偏差敏感負荷預測中高峰時段的預測偏差會被RMSE放大MAPE是相對百分比誤差答辯時最好解釋MAE是最直觀的平均偏差。電力負荷預測領域論文里經常同時報告這三個值是因為單一指標無法描述模型在不同誤差分布下的表現。MAPE有一個需要警惕的坑當真實負荷接近0時MAPE會異常大。電力負荷一般不會為0但如果測試集中包含深夜低負荷時段分母小而分子正常會導致單點MAPE值偏大。答辯被追問時可以說“我們額外計算了MAE和RMSE來規避MAPE在低負荷時段的不穩定性”這是非常標準的回答。5.2 預測曲線可視化與誤差區間圖是課程設計報告里最能直接體現工作量的一環。預測曲線和真實曲線畫在同一張圖上比如連續畫7天或30天。import matplotlib.pyplot as plt # 取最后7天作為展示區間 days 7 hours days * 24 plt.figure(figsize(12, 5)) plt.plot(y_true[-hours:], label真實負荷, linewidth1.5) plt.plot(y_pred[-hours:], label預測負荷, linewidth1.5, alpha0.8) plt.legend() plt.xlabel(時間(h)) plt.ylabel(負荷(MW)) plt.title(LSTM多特征負荷預測結果最后7天) plt.grid(alpha0.3) plt.savefig(prediction_result.png, dpi150)盯住圖上兩類差異容易在答辯時形成有效分析一是每天“峰”的位置是否對齊二是在負荷劇烈爬升或下降段預測是否有明顯滯后。LSTM預測常見的滯后效應表現為預測曲線比真實曲線晚1到2個小時到達峰值這是因為模型過度依賴最近的歷史負荷對突變的響應天然有延遲。這個現象不是bug是RNN結構的固有特性能用這個現象解釋模型行為比假裝模型完美更能體現理解深度。5.3 消融對比多特征有效性論證課程設計報告里“多特征”必須用對比實驗證明其價值。最簡單的做法是訓練兩個模型一個只用load_lag特征另一個加入全部特征在相同測試集上對比指標。這個對比表是報告里最硬的結論。模型輸入windowMAERMSEMAPE僅歷史負荷(7維)2446.263.88.2%歷史負荷氣象時間(13維)2438.955.46.7%消融實驗不用做特別多次兩組就夠了。一組是基線只用歷史負荷一組是完整多特征。如果完整特征組沒有明顯優勢就要檢查特征列是否真正進入模型、是否被歸一化、是否有大量缺失值。特征維度增加后指標變差的情況也真實存在說明新特征攜帶的是噪聲這時需要在feature_cols里刪減特征而不是繼續疊加。6. 提升預測穩定性的滑動驗證法把單次預測變成滾動預測6.1 滾動預測的實現前面的測試過程是一步預測用歷史窗口預測下一個時刻然后滑動窗口繼續用真實值作為輸入。實際應用中要預測未來24小時初始窗口之后只有預測值可用誤差會隨時間累積。課程設計里把“多步預測”做好能明顯拉開與同組同學的差距。常見的做法是循環預測每預測一個時刻就把預測值拼接到歷史序列末尾同時丟棄窗口最前面的一個時刻保持窗口長度不變。def recursive_forecast(model, initial_window, predict_steps, feature_scaler): model.eval() current_window initial_window.copy() # shape: (window, feature_dim) results [] for _ in range(predict_steps): with torch.no_grad(): X_input torch.tensor( current_window.reshape(1, current_window.shape[0], -1), dtypetorch.float32 ) y_pred model(X_input).item() results.append(y_pred) # 構造下一時刻的輸入行 next_row current_window[-1].copy() # 將歷史負荷列整體平移 next_row[:-1] next_row[1:] # 按實際特征順序調整 next_row[-1] y_pred current_window np.vstack( [current_window[1:], next_row.reshape(1, -1)] ) results feature_scaler.inverse_transform( np.array(results).reshape(-1, 1) ).flatten() return results這個實現的要點是“滾動”動作本身窗口最舊的時刻被移除預測值進入窗口末尾繼續作為下一次預測的輸入。注意實際項目里特征順序不是固定的需要根據特征表調整平移的列。多步預測的誤差累積程度可以作為另一個答辯分析點與單步預測的指標對比通常會讓性能看起來差一些但更貼近實際。6.2 針對節假日與極端天氣的應急策略負荷預測里最難的不是常規日而是節假日和極端天氣。多特征模型的優勢在這里體現最明顯如果特征包含is_holiday、temperature_forecast模型至少有機會學習到這類日期的特殊模式。如果數據集中節假日樣本過少建議單獨收集最近兩年的節假日數據做二次微調而不是讓模型在少量樣本上硬學。另一種實用技巧是給時間特征做“距離節假日天數”的連續特征。比如days_to_holiday表示當前時間距離最近節假日的天數負值表示已過去的節假日。這個特征在GEFCom2014這類比賽中被反復證明有效。實現很簡單df[days_to_holiday] df[date].apply( lambda d: min(abs((d - h).days) for h in holiday_list) )這樣模型不需要單獨記住每個節假日的日期只需學習“距離節假日越近負荷模式越偏離常規”的規律。6.3 報告呈現建議課程設計報告里除了訓練曲線、預測對比圖、消融表之外建議再加一張“不同時段的誤差表”比如按峰、平、谷三個時段分別計算MAPE。這會讓結果呈現更完整通常谷時段MAPE偏高但絕對誤差低峰時段MAPE偏低但絕對誤差高。這個現象反映了負荷預測誤差的典型分布也能證明你不是只跑了別人的代碼而是對結果做過系統性分析。表格之外保證源碼里的數據加載路徑、特征順序、歸一化邏輯三處一致是讓項目可復現的底線。本文還有配套的精品資源點擊獲取