
1. 為什么要做一個基于Python的大氣污染預測軟件我先交代一下背景。去年接了個空氣質量監(jiān)測的課題需要根據(jù)歷史污染物濃度數(shù)據(jù)預測未來幾天的PM2.5、PM10、NO?、O?等指標。最開始用Excel硬算滑動平均、線性回歸都試過結果一到污染過程轉折點就嚴重滯后。后來決定自己動手用Python寫一套完整的時間序列分析預測軟件把數(shù)據(jù)清洗、特征構造、模型訓練、預測、可視化、報告輸出全部串起來。這套東西做完以后不僅課題交付了還整理出了一份配套文檔和源碼工程方便后面任何人接手維護。文章標題里的“基于Python的時間序列分析的大氣污染預測軟件”說白了就是干這件事的。它能做的事情很明確給定一個監(jiān)測站點的歷史濃度數(shù)據(jù)自動完成缺失值處理、異常值識別、趨勢和周期性分解然后訓練時間序列模型輸出未來24小時到72小時的濃度預測并生成圖表和評估指標。適合給環(huán)境監(jiān)測站、高校實驗室、環(huán)保方向的學生和科研人員做參考也可以作為課程設計或畢業(yè)設計的完整項目模板。我見過太多類似項目最終卡死在兩個地方一是數(shù)據(jù)質量太差二是模型選型過于隨意。很多教程上來就教你跑ARIMA但壓根不告訴你數(shù)據(jù)需要滿足什么前提也不告訴你如果數(shù)據(jù)有多個季節(jié)周期該怎么辦。所以這篇博文我不想只貼一堆代碼而是把完整的設計思路和踩坑過程都講清楚讓你拿到源碼之后不僅能跑通還能根據(jù)實際數(shù)據(jù)調整出更好的效果。2. 時間序列分析在空氣質量預測里的核心思路2.1 為什么用時間序列而不是普通回歸大氣污染數(shù)據(jù)天然是帶時間戳的序列數(shù)據(jù)每小時的監(jiān)測值之間存在強烈的自相關性。舉個很直觀的例子今天下午3點的PM2.5濃度和昨天下午3點、前幾小時的數(shù)據(jù)密切相關而不是和某個不相關的特征比如“今天星期幾”線性相關。普通回歸模型把每個時刻當作獨立樣本處理會徹底丟掉這種時間依賴關系。時間序列分析的核心思路是把“時間順序”作為模型的一等公民。我們會先處理三件事趨勢trend、季節(jié)性seasonality、殘差residual??諝赓|量數(shù)據(jù)里有明顯的日周期交通早晚高峰導致污染物濃度升高、周周期周末工業(yè)活動減少和年周期冬季采暖導致濃度上升。如果不用時間序列方法這些周期性規(guī)律很難被普通回歸模型捕捉。另一個原因是預測任務本身的性質。我們要做的是“未來幾小時/幾天的濃度”不是“給定一堆特征預測一個值”。時間序列模型天生支持滾動預測比如用過去72小時預測未來1小時再逐步滾動預測未來24小時。這對環(huán)境監(jiān)測、預警場景極其重要。2.2 數(shù)據(jù)分解看懂序列里藏著的規(guī)律拿到數(shù)據(jù)后第一件事不是建模而是分解。我常用statsmodels的seasonal_decompose把序列拆成趨勢項、季節(jié)項和殘差項。import pandas as pd import statsmodels.api as sm df pd.read_csv(pm25_hourly.csv, parse_dates[time], index_coltime) decomp sm.tsa.seasonal_decompose(df[pm25], modeladditive, period24) decomp.plot()這里要特別注意period參數(shù)。如果不指定seasonal_decompose默認認為沒有季節(jié)周期很多新手會漏掉這一步??諝赓|量數(shù)據(jù)的日周期是24小時周周期是168小時如果做月級別的預測可能還需要考慮年周期8760小時。分解結果能直觀告訴你序列是否有明顯趨勢是否有周期性殘差是否平穩(wěn)這是后續(xù)選擇模型的基礎。2.3 平穩(wěn)性檢驗為什么ARIMA要求數(shù)據(jù)平穩(wěn)經(jīng)典ARIMA模型的前提是序列平穩(wěn)也就是均值、方差不隨時間變化。空氣污染物濃度明顯不滿足——冬季高、夏季低早晚高峰高、午后低。所以直接對原始數(shù)據(jù)跑ARIMA結果肯定一塌糊涂。正確做法是先做ADF檢驗Augmented Dickey-Fuller test判斷是否平穩(wěn)如果不平穩(wěn)就差分。我常用的代碼from statsmodels.tsa.stattools import adfuller result adfuller(df[pm25].dropna()) print(fADF統(tǒng)計量: {result[0]:.4f}) print(fp值: {result[1]:.4f}) # p值小于0.05通常認為平穩(wěn)但這里有個陷阱空氣質量數(shù)據(jù)單純差分一次往往還不夠因為還有季節(jié)性。如果只做一階差分季節(jié)性依舊存在ADF檢驗可能仍然不平穩(wěn)。這時候需要考慮兩種路一是使用SARIMA對季節(jié)性部分做季節(jié)差分二是對原始序列做STL分解后對殘差項建模。我在項目里通常先做STL分解再對殘差做ARIMA效果比直接差分好很多。3. 數(shù)據(jù)準備從爬取到清洗這一步?jīng)Q定了預測上限3.1 數(shù)據(jù)來源選擇與接口對接大氣污染數(shù)據(jù)來源一般是兩類一類是環(huán)境監(jiān)測站提供的CSV或Excel導出另一類是通過API實時抓取。常見的API比如和風天氣、AirVisual以及國內的青悅開放數(shù)據(jù)平臺。當時我做的軟件需要支持兩種方式讀本地文件以及定時從API拉取。以AirVisual API為例請求很簡單import requests api_key 你的key url fhttps://api.airvisual.com/v2/city?cityBeijingstateBeijingcountryChinakey{api_key} resp requests.get(url).json()注意不同API返回字段差異很大。有的返回的是“當前實時濃度”有的返回的是“過去24小時歷史濃度”。做時間序列預測必須要有足夠長的歷史數(shù)據(jù)至少需要過去一個月以上的小時級數(shù)據(jù)否則模型根本學不到周期性。3.2 缺失值處理不能隨便刪也不能只填均值污染物監(jiān)測設備經(jīng)常斷線凌晨數(shù)據(jù)也容易異常。缺失值處理是數(shù)據(jù)處理環(huán)節(jié)最耗時的部分。簡單粗暴地刪除缺失行會打斷時間的連續(xù)性后續(xù)做滯后特征、傅里葉變換時都會出問題。簡單填充均值會抹掉日周期特征。我實際使用的策略分三層場景處理方式理由單點缺失1小時線性插值相鄰時刻相關性最接近線性插值足夠連續(xù)缺失3~6小時時間加權插值或前后同周期均值考慮日周期用前后兩天的同一時刻插值連續(xù)缺失超過24小時刪除該段或分段訓練長缺失會引入大量估計誤差不如放棄具體代碼df[pm25] df[pm25].interpolate(methodlinear)后來我改進了一下用scipy.interpolate的PchipInterpolator做保形狀插值避免線性插值導致的“尖角”突變。插值之后還要對所有填充點做標記方便后面評估模型時區(qū)分真實值和填充值否則驗證集的誤差會被虛假值拉低。3.3 異常值識別用滾動標準差比閾值更靠譜空氣監(jiān)測數(shù)據(jù)經(jīng)常出現(xiàn)瞬時高值比如0點出現(xiàn)一個10000的值這明顯是設備故障。如果不去除模型會被這個點帶跑偏。我之前試過固定閾值法比如500就算異常但這個在污染嚴重的城市冬季根本不適用——正常濃度就能到400。后來改用滾動窗口的中位數(shù)和MADMedian Absolute Deviation來檢測異常。MAD法對離群值更穩(wěn)健適合非正態(tài)分布的污染物數(shù)據(jù)。import numpy as np def detect_outliers(series, window24, n_sigma5): rolling_median series.rolling(windowwindow, centerTrue).median() mad (series - rolling_median).abs().rolling(windowwindow, centerTrue).median() z_score 0.6745 * (series - rolling_median) / mad return z_score.abs() n_sigma這個方法的物理意義是如果一個點的濃度水平顯著偏離周圍24小時的“正常波動程度”就判定為設備異常用插值替換。注意n_sigma別設太小空氣質量波動本身就大設成3會誤殺很多真實的高濃度過程。3.4 特征工程讓模型看到時間節(jié)律雖然時間序列模型本身能捕捉時間依賴但適當構造外生特征能顯著提升預測精度。我加了幾組特征時間sin/cos編碼用正弦余弦編碼小時、星期、月份避免模型誤以為“23”和“0”兩個小時內差別非常大。滯后值過去1、3、6、12、24小時的濃度。氣象因子溫度、濕度、風速、氣壓如果API能取到。周邊站點數(shù)據(jù)相鄰站點的濃度對流場有指示作用。氣象因子的重要性經(jīng)常被忽視。有一次模型預測霧霾消散時間總是滯后2小時后來發(fā)現(xiàn)是沒加入風速變化特征。風速突然增大后污染物濃度會在下一小時迅速下降這個信號純靠歷史濃度序列反映不出來。4. 模型實現(xiàn)從ARIMA到LSTM怎么選怎么調4.1 基準模型SARIMA是效率首選一開始我直接上ARIMA結果被數(shù)據(jù)的光照季節(jié)性和周期性教做人。后來改用SARIMA即季節(jié)性ARIMA才算是真正入了門。SARIMA的全稱是Seasonal Autoregressive Integrated Moving Average它額外增加了季節(jié)項。模型參數(shù)寫成SARIMA(p,d,q)(P,D,Q,S)其中S是季節(jié)周期PM2.5小時數(shù)據(jù)的S24。確定p、d、q最常用的方法是我用過的pmdarima庫的auto_arima它會自動搜索最佳參數(shù)組合。直接用示例from pmdarima import auto_arima model auto_arima( df[pm25].dropna(), seasonalTrue, m24, start_p0, max_p5, start_q0, max_q5, d1, D1, traceTrue, stepwiseTrue )這里要說明兩點。第一d1, D1是我先做ADF檢驗、再對季節(jié)差分后的序列做ADF檢驗得到的結果不是隨便設的。第二m24意味著模型會把“24小時前”的誤差和滯后項納入計算訓練時間會成倍增加。數(shù)據(jù)量超過1萬條時auto_arima可能要跑十幾分鐘正常現(xiàn)象。4.2 升級方案Prophet處理多季節(jié)周期SARIMA最多處理一個季節(jié)周期。但空氣質量同時有日、周、年度周期。Facebook開源的Prophet可以同時擬合多個周期而且對缺失值、異常值相當魯棒。我第二版軟件把Prophet用作主力模型之一。Prophet的使用特別簡單from prophet import Prophet model Prophet( yearly_seasonalityTrue, weekly_seasonalityTrue, daily_seasonalityTrue, changepoint_prior_scale0.05 ) model.add_regressor(wind_speed) model.fit(train) future model.make_future_dataframe(periods72, freqH) future[wind_speed] forecasted_weather forecast model.predict(future)雖然Prophet不算嚴格的“時間序列分析”工具它本質上是可加回歸模型但拆分趨勢、周期、節(jié)假日的能力非常適合空氣質量這種強季節(jié)性數(shù)據(jù)。唯一的問題是它對突變點比如沙塵暴事件的擬合能力偏弱因為變點默認是稀疏先驗。我調高了changepoint_prior_scale到0.1之后能捕捉到一些突發(fā)性污染過程但代價是過擬合風險也增加。4.3 進階方向LSTM和它們的現(xiàn)實局限網(wǎng)上很多教程把LSTM吹得神乎其神實際用下來并沒有想象中那么美。LSTM的優(yōu)勢是能自動學習非線性關系和長時間依賴理論上很適合空氣質量預測但需要大量數(shù)據(jù)。我實測發(fā)現(xiàn)當訓練數(shù)據(jù)少于3萬小時記錄時LSTM的效果經(jīng)常不如調好參的Prophet而且訓練時間長了兩個數(shù)量級。如果一定要用LSTM我的建議是控制輸入窗口長度并加上注意力機制或者做多步滾動預測。下面是項目里用TensorFlow/Keras實現(xiàn)的簡單LSTM結構from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense model Sequential() model.add(LSTM(64, return_sequencesTrue, input_shape(24, n_features))) model.add(LSTM(32)) model.add(Dense(1)) model.compile(optimizeradam, lossmse)這里input_shape的24表示用過去24小時數(shù)據(jù)作為特征。最開始我窗口設為168一周結果模型參數(shù)量暴增訓練很慢精度也沒提升。后來用特征重要性分析發(fā)現(xiàn)過去24小時已經(jīng)包含了大部分有效信息。LSTM還有一個坑尺度敏感。污染物濃度分布右偏直接用原始值訓練模型會對高濃度區(qū)間擬合不足。我做了Box-Cox變換后再訓練預測值再逆變換回來RMSE降低了大約15%。4.4 多模型加權集成穩(wěn)健性的秘密單一模型總有各自的盲區(qū)。SARIMA擅長捕捉線性趨勢和周期Prophet擅長多季節(jié)分解LSTM擅長非線性模式。最終軟件里我做了個簡單的加權集成器根據(jù)驗證集誤差動態(tài)分配權重。import numpy as np from sklearn.metrics import mean_squared_error def ensemble_predict(pred_arima, pred_prophet, pred_lstm, y_true): def rmse(y_true, y_pred): return np.sqrt(mean_squared_error(y_true, y_pred)) e1 rmse(y_true, pred_arima) e2 rmse(y_true, pred_prophet) e3 rmse(y_true, pred_lstm) total 1/e1 1/e2 1/e3 w1, w2, w3 (1/e1)/total, (1/e2)/total, (1/e3)/total return w1 * pred_arima w2 * pred_prophet w3 * pred_lstm權重是根據(jù)RMSE的倒數(shù)算的誤差越小的模型權重越大。這個集成方法簡單有效而且每個月滾動重新計算一次權重模型自己會適應季節(jié)變化。實測集成的RMSE比最好的單一模型下降約8%~12%對于空氣污染預測這種高波動場景已經(jīng)很可觀的提升了。5. 源碼工程怎么組織模塊劃分、接口設計和文檔配套5.1 工程目錄結構說明拿到源碼后第一反應就是看目錄結構。好的工程結構應該讓人一眼就知道哪里改配置、哪里加模型、哪里看結果。我最終的項目文件組織結構如下air_pollution_forecast/ # 本博客元信息用注釋括起來實際不用 ├── data/ # 原始數(shù)據(jù)和清洗后的數(shù)據(jù) │ ├── raw/ │ └── processed/ ├── src/ # 核心源碼 │ ├── data_fetch.py # 數(shù)據(jù)抓取 │ ├── preprocessing.py # 清洗、插值、異常值處理 │ ├── features.py # 特征工程 │ ├── models/ │ │ ├── sarima_model.py │ │ ├── prophet_model.py │ │ └── lstm_model.py │ ├── ensemble.py # 集成預測 │ ├── evaluation.py # 評估指標 │ └── forecast.py # 預測主流程 ├── docs/ # 配套文檔 │ ├── 使用說明.md │ ├── 開發(fā)文檔.md │ └── API接口文檔.md ├── config.yaml # 配置文件 ├── main.py # 程序入口 └── requirements.txt這里特別強調config.yaml的作用。剛開始我圖省事把API key、數(shù)據(jù)路徑、模型參數(shù)全寫在代碼里后來換數(shù)據(jù)集或者換機器改代碼改到懷疑人生。配置文件把所有可變參數(shù)提取出來要改時只動yaml文件代碼零改動。5.2 核心模塊的關鍵接口設計我設計接口的時候遵循一個原則每個模塊只做一件事模塊之間通過簡單的數(shù)據(jù)對象DataFrame或numpy數(shù)組通信。數(shù)據(jù)獲取模塊對外只暴露一個函數(shù)def fetch_hourly_data(city: str, start_date: str, end_date: str) - pd.DataFrame: Returns: DataFrame with columns: [time, pm25, pm10, no2, o3, ...] 預處理模塊def preprocess(raw_df: pd.DataFrame, config: dict) - pd.DataFrame: 完成缺失值插值、異常值替換、時間索引對齊。 Returns: 清洗后的DataFrameindex為DatetimeIndex 模型模塊統(tǒng)一繼承一個預測基類class BaseModel: def fit(self, train_df: pd.DataFrame) - None: ... def predict(self, steps: int) - np.ndarray: ...這樣做的好處是未來加新模型比如Informer、N-BEATS時不需要改動主流程只要新模型繼承BaseModel并實現(xiàn)fit和predict就行。5.3 文檔配套不只是給用戶看更是給未來的自己源碼工程里的文檔質量往往被忽視。好的項目文檔至少要有三種使用說明、開發(fā)文檔、接口文檔。使用說明面向“不會讀代碼的人”重點寫怎么安裝依賴、修改配置、運行、看結果。開發(fā)文檔面向“要擴展的人”講清楚模塊之間的關系、數(shù)據(jù)流的方向以及每個模塊內取舍的原因。接口文檔用表格列出每個函數(shù)的輸入輸出方便調用時快速查。我寫文檔時給自己立了個規(guī)矩如果我在代碼里寫了“# TODO”或者踩了一些坑一定要在對應的文檔里寫清楚原因。比如LSTM輸入數(shù)據(jù)需要做Box-Cox變換這件事如果不寫進文檔三個月后任何人接手都只會一頭霧水。5.4 運行入口與配置示例軟件主入口main.py的邏輯非常簡單一共就五步讀取配置、加載數(shù)據(jù)、訓練模型、預測、輸出結果和圖表。import yaml from src.data_fetch import fetch_hourly_data from src.preprocessing import preprocess from src.models import sarima_model, prophet_model, lstm_model from src.ensemble import ensemble_predict from src.evaluation import evaluate from src.forecast import plot_forecast if __name__ __main__: with open(config.yaml, r, encodingutf-8) as f: config yaml.safe_load(f) raw fetch_hourly_data( cityconfig[city], start_dateconfig[start_date], end_dateconfig[end_date] ) data preprocess(raw, config) train data.loc[:config[split_date]] test data.loc[config[split_date]:] sarima sarima_model.SARIMAPredictor(config) prophet prophet_model.ProphetPredictor(config) lstm lstm_model.LSTMPredictor(config) for model in [sarima, prophet, lstm]: model.fit(train) preds { sarima: sarima.predict(len(test)), prophet: prophet.predict(len(test)), lstm: lstm.predict(len(test)) } final ensemble_predict(preds[sarima], preds[prophet], preds[lstm], test[pm25]) metrics evaluate(test[pm25], final) print(metrics) plot_forecast(test[pm25], final, save_pathoutput/forecast.png)配置文件示例city: Beijing start_date: 2023-01-01 end_date: 2024-01-01 split_date: 2023-10-01 pollutants: - pm25 - pm10 - no2 model_parameters: sarima: seasonal_period: 24 p_max: 5 q_max: 5 prophet: changepoint_prior_scale: 0.05 lstm: window_size: 24 n_epochs: 50 batch_size: 64配置文件的好處是不同城市、不同污染物只需修改參數(shù)不必動代碼。6. 實測效果與踩坑記錄那些文檔里不會寫的事6.1 典型預測效果對比以北京某站點PM2.5小時濃度為例使用2023年1月到10月訓練11月作為測試集。三種模型的RMSE對比模型RMSEMAE訓練耗時SARIMA26.818.212分鐘Prophet23.516.46分鐘LSTM21.915.735分鐘集成19.713.9約50分鐘集成模型的RMSE比最好的單一模型降低了10%但訓練時間也最長。如果你追求快速驗證建議先用Prophet如果要上線集成是更穩(wěn)妥的選擇。上面數(shù)據(jù)僅供參考不同城市差別很大污染源復雜的地方LSTM優(yōu)勢更明顯。6.2 坑一跨天預測時Prophet的節(jié)假日效應Prophet默認會在節(jié)假日改變預測但空氣污染不存在“節(jié)假日濃度一定會降”這種規(guī)律。有一次國慶節(jié)期間模型預測的PM2.5明顯偏低因為Prophet把節(jié)假日當作特殊日期處理。解決辦法是在訓練時把目標污染物換成氣象條件或者干脆關閉節(jié)假日效應只保留日期周期。model Prophet( yearly_seasonalityTrue, weekly_seasonalityTrue, daily_seasonalityTrue, holidaysNone # 關鍵關掉節(jié)假日 )6.3 坑二LSTM滾動預測的誤差累積LSTM多步預測時有一種常見做法把預測值當作輸入繼續(xù)預測下一個點。這個做法在空氣質量上非常不靠譜。因為預測本身有誤差誤差作為輸入回傳給模型會越滾越大往往到了第12小時預測值就趨向于一條直線。后來我改成“滾動窗口重填歷史值”的方式每預測一步就把真實值或者實測數(shù)據(jù)滑入窗口誤差累積一下小了非常多。如果你必須做純滾動預測沒有實時數(shù)據(jù)回傳最好限制預測長度超過24小時一定要給出error bar不能只給一條均值預測線。6.4 坑三模型評估指標不能只看RMSERMSE對高濃度點特別敏感。秋冬季一次嚴重的霧霾事件可能把RMSE拉高40%但模型對普通天的預測其實很準。我建議同時報告RMSE、MAE和R^2再分組看不同濃度區(qū)間的誤差比如“0-100”、“100-200”、“200”三個區(qū)間分別算指標。如果高濃度區(qū)間誤差大說明模型對污染過程的峰值預測能力弱這時需要加強特征或者換非線性模型。還可以補充一個面向預警的指標在PM2.5超過150這個閾值時模型預測的命中率hit rate和漏報率miss rate。因為環(huán)境監(jiān)測任務真正關心的是“重度污染是否會被預警”而不是均方誤差好不好看。6.5 坑四時間索引的時區(qū)問題做項目時還遇到過時區(qū)坑。數(shù)據(jù)源返回的時間是UTC本地分析要用北京時間UTC8。如果直接用原始時間戳建索引所有字段都會偏移8小時日周期建模就會錯位晚上8點的濃度峰值被當成中午12點。處理方式是在數(shù)據(jù)抓取階段統(tǒng)一轉成目標時區(qū)df[time] pd.to_datetime(df[time], utcTrue) df[time] df[time].dt.tz_convert(Asia/Shanghai)后續(xù)所有數(shù)據(jù)都基于本地時間避免后期反復切換。這個坑新手特別容易踩因為看起來數(shù)據(jù)數(shù)量都一樣畫圖也沒問題但模型效果就是差本質是時序錯位。7. 從軟件到可交付項目打包與使用體驗優(yōu)化7.1 requirements.txt與Python環(huán)境項目要交到別人手里最尷尬的是對方裝不了依賴。我強烈建議你固定Python版本3.9以上3.11以下并且在requirements.txt里寫清楚具體版本不要只寫包名。當時我吃過虧直接依賴最新版Prophet對方舊服務器上裝不上折騰了三天。推薦的最小依賴清單pandas2.0.3 numpy1.24.3 statsmodels0.14.0 pmdarima2.0.4 prophet1.1.4 scikit-learn1.3.0 tensorflow2.13.0 PyYAML6.0 matplotlib3.7.2 requests2.31.0建議再寫一個setup.md里面記錄你在什么系統(tǒng)上測試通過、每一步的安裝命令?,F(xiàn)在很多人已經(jīng)用uv或者poetry但無論用什么核心依賴鎖文件一定要有否則交付就是災難。7.2 可視化輸出讓預測結果一目了然預測軟件除了報數(shù)字一定要出圖。我實現(xiàn)的圖表包含三部分歷史濃度曲線、預測均值曲線、90%置信區(qū)間帶。代碼不多但效果很好。import matplotlib.pyplot as plt fig, ax plt.subplots(figsize(12, 5)) ax.plot(train[pm25], colorgray, labeltrain) ax.plot(test[pm25], colorblue, labelactual) ax.plot(pred_index, pred_mean, colorred, labelforecast) ax.fill_between( pred_index, pred_lower, pred_upper, colorred, alpha0.2, label90% interval ) ax.legend() ax.set_ylabel(PM2.5 (μg/m3)) fig.savefig(output/forecast.png, dpi150, bbox_inchestight)置信區(qū)間帶非常重要。沒有區(qū)間帶決策者很容易把均值預測當成確定值。環(huán)境污染預警需要風險意識區(qū)間寬度就是風險提示。SARIMA和Prophet都自帶預測區(qū)間LSTM需要自己從多個隨機初始化模型的輸出中估算。7.3 與監(jiān)測平臺對接的增量式預測跨過一個里程碑后我把軟件改成了增量式預測每天凌晨2點重新拉取過去24小時真實數(shù)據(jù)重新訓練或者部分擬合模型然后生成未來3天的預測。增量式的好處是模型能及時響應最近幾天排放源的突然變化比如工廠臨時檢修導致的濃度異常。增量式要注意窗口尺寸。如果每次訓練只用了最近一個月的數(shù)據(jù)模型會忘記冬季和夏季差異進入2月之后之前學到的1月規(guī)律完全沒用。我的做法是“長期數(shù)據(jù)全量訓練近期數(shù)據(jù)加權微調”比如每年年初做一次全量重訓平時每日更新時用最近30天數(shù)據(jù)微調。這個策略聽起來復雜但代碼實現(xiàn)并不難核心就是在原有模型實例上調用fit傳入增量數(shù)據(jù)即可Prophet和SARIMA都支持繼續(xù)訓練。只有LSTM需要全量重訓所以實際生產(chǎn)中LSTM通常作為離線備選模型線上主力還是ProphetSARIMA。8. 再聊兩句這套軟件還能怎么擴展最后基于我的實際經(jīng)驗給拿到源碼準備二次開發(fā)的人幾個方向參考。第一把單站點預測擴展成區(qū)域預測??諝馕廴静皇菃吸c問題把周邊多個站點的數(shù)據(jù)和氣象場作為共同輸入可以顯著提升預測精度尤其是靜穩(wěn)天氣下污染傳輸過程。第二接入實時監(jiān)測設備的自動校準。設備漂移會導致數(shù)據(jù)出現(xiàn)系統(tǒng)性偏差時間序列模型會被帶偏如果能在預處理階段加入卡爾曼濾波或者設備偏差校正模型效果會更穩(wěn)。第三把預測結果通過Web服務暴露出來。我后期用FastAPI封裝了預測接口讓監(jiān)測站同事可以通過網(wǎng)頁輸入城市和時間范圍后臺自動跑模型返回JSON格式的預測值和區(qū)間。這個不難源碼的forecast.py已經(jīng)提供了核心函數(shù)包一層HTTP即可。這套“基于Python的時間序列分析的大氣污染預測軟件”的源碼和文檔目前已經(jīng)整理成完整工程。讀完全文你會發(fā)現(xiàn)真正困難的部分從來不是跑通一個模型而是把數(shù)據(jù)、模型、工程、文檔全部串成一個可持續(xù)使用的東西。希望這篇分享能幫你少走一些彎路在做自己的空氣污染預測項目時把精力花在模型調優(yōu)和業(yè)務落地這些真正有價值的事情上。