儘管人工智慧(AI)引起了很多關注,許多科技公司仍然依賴機器學習來驅動重要的應用程式,從個性化推薦到詐騙檢測。
我親眼見證了未被發現的模型漂移會導致重大損失——錯過詐騙檢測、收入損失,以及不理想的商業結果等等。因此,如果你的公司已經部署或計劃部署機器學習模型到生產環境中,建立穩健的監控系統是非常重要的。
未檢測的模型漂移可能導致重大的財務損失、運營效率低下,甚至損害公司的聲譽。為了減少這些風險,擁有有效的模型監控是重要的,這包括:
- 追蹤模型性能
- 監控特徵分佈
- 檢測單變量和多變量漂移
一個良好實施的監控系統可以幫助及早識別問題,節省大量時間、金錢和資源。
在這篇全面的指南中,我將提供一個框架,幫助你思考和實施有效的模型監控,讓你能夠提前預見潛在問題,確保你的模型在生產環境中的穩定性和可靠性。
特徵漂移和分數漂移有什麼不同?
分數漂移是指模型分數分佈的逐漸變化。如果不加以控制,這可能導致模型性能下降,使模型隨著時間變得不準確。
另一方面,特徵漂移發生在一個或多個特徵的分佈發生變化時。這些特徵值的變化可能影響模型所學到的基本關係,最終導致模型預測不準確。
模擬分數變化
為了模擬現實中的詐騙檢測挑戰,我創建了一個合成數據集,包含五個金融交易特徵。
參考數據集代表原始分佈,而生產數據集則引入變化,以模擬在新帳戶上未經PIN驗證的高價值交易增加,這表明詐騙的增加。
每個特徵有不同的基本分佈:
- 交易金額:對數正態分佈(右偏,有長尾)
- 帳戶年齡(月份):在0到60之間的截斷正態分佈(假設是一家5年的公司)
- 自上次交易以來的時間:指數分佈
- 交易次數:泊松分佈
- 輸入的PIN:二項分佈。
為了近似模型分數,我隨機分配了這些特徵的權重,並應用sigmoid函數將預測限制在0到1之間。這模擬了邏輯回歸詐騙模型生成風險分數的方式。
如下面的圖所示:
- 漂移的特徵:交易金額、帳戶年齡、交易次數和輸入的PIN都經歷了分佈、規模或關係的變化。
- 穩定特徵:自上次交易以來的時間保持不變。

- 漂移的分數:由於漂移的特徵,模型分數的分佈也發生了變化。

這個設置讓我們能夠分析特徵漂移如何影響生產中的模型分數。
使用PSI檢測模型分數漂移
為了監控模型分數,我使用了人口穩定性指數(PSI)來測量模型分數分佈隨時間的變化。
PSI的工作原理是將連續的模型分數分組,並比較參考數據集和生產數據集中每個組的分數比例。它比較比例的差異及其對數比率,以計算一個單一的摘要統計量來量化漂移。
Python實現:
# 定義函數以計算給定兩個數據集的PSI
def calculate_psi(reference, production, bins=10):
# 將分數離散化為組
min_val, max_val = 0, 1
bin_edges = np.linspace(min_val, max_val, bins + 1)
# 計算每個組中的比例
ref_counts, _ = np.histogram(reference, bins=bin_edges)
prod_counts, _ = np.histogram(production, bins=bin_edges)
ref_proportions = ref_counts / len(reference)
prod_proportions = prod_counts / len(production)
# 避免除以零
ref_proportions = np.clip(ref_proportions, 1e-8, 1)
prod_proportions = np.clip(prod_proportions, 1e-8, 1)
# 計算每個組的PSI
psi = np.sum((ref_proportions - prod_proportions) * np.log(ref_proportions / prod_proportions))
return psi
# 計算PSI
psi_value = calculate_psi(ref_data['model_score'], prod_data['model_score'], bins=10)
print(f"PSI值: {psi_value}")
以下是如何解釋PSI值的摘要:
- PSI < 0.1:沒有漂移,或非常輕微的漂移(分佈幾乎相同)。
- 0.1 ≤ PSI < 0.25:有一些漂移。分佈有些不同。
- 0.25 ≤ PSI < 0.5:中等漂移。參考和生產分佈之間有明顯的變化。
- PSI ≥ 0.5:顯著漂移。表明生產中的分佈與參考數據有很大變化。

PSI值0.6374表明我們的參考和生產數據集之間存在顯著的漂移。這與模型分數分佈的直方圖一致,視覺上確認了生產中向更高分數的變化——這表明高風險交易的增加。
檢測特徵漂移
科爾莫哥羅夫-史密爾諾夫(K-S)檢驗用於數值特徵
科爾莫哥羅夫-史密爾諾夫(K-S)檢驗是我檢測數值特徵漂移的首選方法,因為它是非參數的,這意味著它不假設正態分佈。
該檢驗通過測量參考和生產數據集中一個特徵的經驗累積分佈函數(ECDF)之間的最大差異來比較特徵的分佈。結果的K-S統計量範圍從0到1:
- 0表示兩個分佈之間沒有差異。
- 接近1的值表示變化更大。
Python實現:
# 創建一個空的數據框
ks_results = pd.DataFrame(columns=['特徵', 'K-S統計量', 'p值', '檢測到漂移'])
# 遍歷所有特徵並執行K-S檢驗
for col in numeric_cols:
ks_stat, p_value = ks_2samp(ref_data[col], prod_data[col])
drift_detected = p_value < 0.05
# 將結果存儲在數據框中
ks_results = pd.concat([
ks_results,
pd.DataFrame({
'特徵': [col],
'K-S統計量': [ks_stat],
'p值': [p_value],
'檢測到漂移': [drift_detected]
})
], ignore_index=True)
以下是我們數據集中四個數值特徵的ECDF圖表:

讓我們以帳戶年齡特徵為例:x軸表示帳戶年齡(0-50個月),y軸顯示參考和生產數據集的ECDF。生產數據集偏向於較新的帳戶,因為它具有更高比例的低帳戶年齡觀察值。
卡方檢驗用於類別特徵
為了檢測類別和布林特徵的變化,我喜歡使用卡方檢驗。
這個檢驗比較參考和生產數據集中類別特徵的頻率分佈,並返回兩個值:
- 卡方統計量:較高的值表示參考和生產數據集之間的變化更大。
- p值:p值低於0.05表明參考和生產數據集之間的差異在統計上是顯著的,表示可能存在特徵漂移。
Python實現:
# 創建具有相應列名的空數據框
chi2_results = pd.DataFrame(columns=['特徵', '卡方統計量', 'p值', '檢測到漂移'])
for col in categorical_cols:
# 獲取參考和生產數據集的標準化值計數
ref_counts = ref_data[col].value_counts(normalize=True)
prod_counts = prod_data[col].value_counts(normalize=True)
# 確保所有類別在兩者中都有表示
all_categories = set(ref_counts.index).union(set(prod_counts.index))
ref_counts = ref_counts.reindex(all_categories, fill_value=0)
prod_counts = prod_counts.reindex(all_categories, fill_value=0)
# 創建列聯表
contingency_table = np.array([ref_counts * len(ref_data), prod_counts * len(prod_data)])
# 執行卡方檢驗
chi2_stat, p_value, _, _ = chi2_contingency(contingency_table)
drift_detected = p_value < 0.05
# 將結果存儲在chi2_results數據框中
chi2_results = pd.concat([
chi2_results,
pd.DataFrame({
'特徵': [col],
'卡方統計量': [chi2_stat],
'p值': [p_value],
'檢測到漂移': [drift_detected]
})
], ignore_index=True)
卡方統計量57.31,p值3.72e-14確認了我們的類別特徵“輸入的PIN”發生了重大變化。這一發現與下面的直方圖一致,該直方圖直觀地顯示了變化:

檢測多變量變化
斯皮爾曼相關性檢測成對交互的變化
除了監控單個特徵的變化,追蹤特徵之間的關係或交互的變化(稱為多變量變化)也是很重要的。即使單個特徵的分佈保持穩定,多變量變化也可能表明數據中的重要差異。
默認情況下,Pandas的.corr()函數計算皮爾森相關性,這僅捕捉變量之間的線性關係。然而,特徵之間的關係通常是非線性的,但仍然遵循一致的趨勢。
為了捕捉這一點,我們使用斯皮爾曼相關性來測量特徵之間的單調關係。它捕捉特徵是否以一致的方向一起變化,即使它們的關係不是嚴格線性的。
為了評估特徵關係的變化,我們比較:
- 參考相關性(ref_corr):捕捉參考數據集中歷史特徵關係。
- 生產相關性(prod_corr):捕捉生產中的新特徵關係。
- 相關性絕對差異:測量參考和生產數據集之間特徵關係的變化。較高的值表示更顯著的變化。
Python實現:
# 計算相關性矩陣
ref_corr = ref_data.corr(method='spearman')
prod_corr = prod_data.corr(method='spearman')
# 計算相關性差異
corr_diff = abs(ref_corr - prod_corr)
示例:相關性變化
現在,讓我們看看交易金額和帳戶年齡(以月為單位)之間的相關性:
- 在ref_corr中,相關性為0.00095,表示這兩個特徵之間的關係很弱。
- 在prod_corr中,相關性為-0.0325,表示弱的負相關。
- 斯皮爾曼相關性的絕對差異為0.0335,這是一個小但明顯的變化。
相關性的絕對差異表明交易金額和帳戶年齡之間的關係發生了變化。
這兩個特徵之間曾經沒有關係,但生產數據集表明現在有一個弱的負相關,這意味著較新的帳戶有更高的交易金額。這是正確的!
自編碼器用於複雜的高維多變量變化
除了監控成對交互,我們還可以尋找數據中多維的變化。
自編碼器是檢測高維多變量變化的強大工具,當多個特徵共同以不明顯的方式變化時,這可能無法從單個特徵分佈或成對相關性中看出。
自編碼器是一種神經網絡,通過兩個組件學習數據的壓縮表示:
- 編碼器:將輸入數據壓縮為低維表示。
- 解碼器:從壓縮表示中重建原始輸入。
為了檢測變化,我們比較重建的輸出和原始輸入,並計算重建損失。
- 低重建損失→自編碼器成功重建數據,這意味著新觀察值與其所見和學到的相似。
- 高重建損失→生產數據與學到的模式有顯著偏差,表明可能存在漂移。
與傳統的漂移指標專注於單個特徵或成對關係不同,自編碼器同時捕捉多個變量之間的複雜非線性依賴。
Python實現:
ref_features = ref_data[numeric_cols + categorical_cols]
prod_features = prod_data[numeric_cols + categorical_cols]
# 正規化數據
scaler = StandardScaler()
ref_scaled = scaler.fit_transform(ref_features)
prod_scaled = scaler.transform(prod_features)
# 將參考數據分為訓練和驗證
np.random.shuffle(ref_scaled)
train_size = int(0.8 * len(ref_scaled))
train_data = ref_scaled[:train_size]
val_data = ref_scaled[train_size:]
# 構建自編碼器
input_dim = ref_features.shape[1]
encoding_dim = 3
# 輸入層
input_layer = Input(shape=(input_dim, ))
# 編碼器
encoded = Dense(8, activation="relu")(input_layer)
encoded = Dense(encoding_dim, activation="relu")(encoded)
# 解碼器
decoded = Dense(8, activation="relu")(encoded)
decoded = Dense(input_dim, activation="linear")(decoded)
# 自編碼器
autoencoder = Model(input_layer, decoded)
autoencoder.compile(optimizer="adam", loss="mse")
# 訓練自編碼器
history = autoencoder.fit(
train_data, train_data,
epochs=50,
batch_size=64,
shuffle=True,
validation_data=(val_data, val_data),
verbose=0
)
# 計算重建誤差
ref_pred = autoencoder.predict(ref_scaled, verbose=0)
prod_pred = autoencoder.predict(prod_scaled, verbose=0)
ref_mse = np.mean(np.power(ref_scaled - ref_pred, 2), axis=1)
prod_mse = np.mean(np.power(prod_scaled - prod_pred, 2), axis=1)
以下圖表顯示了兩個數據集之間重建損失的分佈。

生產數據集的平均重建誤差高於參考數據集,這表明整體數據發生了變化。這與生產數據集中較新帳戶和高價值交易的增加一致。
總結
模型監控是數據科學家和機器學習工程師的重要責任,但往往被忽視。
所有統計方法都得出了相同的結論,這與觀察到的數據變化一致:它們檢測到生產中較新帳戶進行高價值交易的趨勢。這一變化導致模型分數提高,預示著潛在詐騙的增加。
在這篇文章中,我介紹了檢測漂移的三種不同層次的技術:
- 模型分數漂移:使用人口穩定性指數(PSI)
- 單個特徵漂移:使用科爾莫哥羅夫-史密爾諾夫檢驗檢測數值特徵和卡方檢驗檢測類別特徵
- 多變量漂移:使用斯皮爾曼相關性檢測成對交互和自編碼器檢測高維多變量變化。
這些只是我依賴於全面監控的一些技術——還有許多其他同樣有效的統計方法也能有效檢測漂移。
檢測到的變化通常指向需要進一步調查的潛在問題。根本原因可能是數據收集錯誤,也可能是像夏令時間調整這樣的小變化。
還有一些很棒的Python套件,比如evidently.ai,可以自動化許多這些比較。然而,我認為深入理解漂移檢測背後的統計技術比僅僅依賴這些工具更有價值。
你在工作過的地方的模型監控過程是什麼樣的?
想要提升你的AI技能嗎?
👉🏻 我運營AI周末活動,並每週撰寫有關數據科學、AI周末項目和數據專業人士職業建議的博客文章。
資源
本文由 AI 台灣 運用 AI 技術編撰,內容僅供參考,請自行核實相關資訊。
歡迎加入我們的 AI TAIWAN 台灣人工智慧中心 FB 社團,
隨時掌握最新 AI 動態與實用資訊!