動的互聯(lián)網(wǎng)貸款客戶聚類與風(fēng)險預(yù)警實戰(zhàn))
這兩天幫一位27屆的學(xué)弟整理計算機(jī)畢設(shè)源碼題目正好是《基于多維特征融合的互聯(lián)網(wǎng)貸款客戶聚類與風(fēng)險預(yù)警研究》和配套的《基于數(shù)據(jù)挖掘的互聯(lián)網(wǎng)貸款用途與風(fēng)險定價可視化研究》。乍一看像是兩個題目實際是一個完整的風(fēng)控數(shù)據(jù)挖掘閉環(huán)先把客戶按照多維特征聚成不同群體再做風(fēng)險預(yù)警最后把貸款用途、利率、逾期率之間的關(guān)系用可視化大屏呈現(xiàn)出來。拿到這類題目容易發(fā)懵范圍太大不知道該先做什么。我把從數(shù)據(jù)清洗到出具整套源碼的全過程拆一遍包括選型思路、參數(shù)調(diào)優(yōu)、踩過的坑盡量把能直接復(fù)現(xiàn)的細(xì)節(jié)都交代清楚。做過金融風(fēng)控類畢設(shè)的人都知道這類項目最容易被卡住的不是模型而是“業(yè)務(wù)邏輯與數(shù)據(jù)特征對不對得上”。比如為什么要把聚類和風(fēng)險預(yù)警放一起為什么貸款用途要和風(fēng)險定價關(guān)聯(lián)。先把這個題目的設(shè)計思路講明白后續(xù)每一步才走得順。1. 項目整體設(shè)計與拆解1.1 題目到底在考什么“多維特征融合”這個詞聽起來很高端其實就是把客戶畫像里分散的信息整合起來形成一個能同時反映還款能力、還款意愿、資金需求緊急度的特征集。傳統(tǒng)做法可能只盯著收入、負(fù)債或者歷史逾期某一個字段效果往往不穩(wěn)定。一個用戶可能在單一維度上表現(xiàn)正常但把收入負(fù)債比、近3個月征信查詢次數(shù)、當(dāng)前逾期天數(shù)放在一起看風(fēng)險特征立刻暴露出來。客戶聚類解決的是“客群分層”問題。不同客群的風(fēng)險驅(qū)動因素不一樣比如剛畢業(yè)的學(xué)生群體負(fù)債低但收入穩(wěn)定性差經(jīng)營類客群收入高但資金周轉(zhuǎn)波動大把這些人混在一起訓(xùn)練模型預(yù)警準(zhǔn)頭會大打折扣。所以題目先要求聚類再要求預(yù)警本質(zhì)上是希望用無監(jiān)督方法先找出結(jié)構(gòu)性差異再針對不同分群搭建有監(jiān)督的風(fēng)險判斷。風(fēng)險定價可視化的核心邏輯也很簡單風(fēng)險越高的客戶貸款利率理應(yīng)越高。但這還不夠還需要回答“貸款用途對違約風(fēng)險有沒有顯著影響”這個問題。買房裝修、日常消費(fèi)、生意周轉(zhuǎn)、教育醫(yī)療不同用途背后的資金去向和真實還款來源不同定價策略也應(yīng)該有差異。把這個差異通過散點(diǎn)圖、漏斗圖、熱力圖展示出來就是可視化研究的價值。1.2 整體技術(shù)架構(gòu)與代碼組織我的技術(shù)選型以Python為主原因很簡單數(shù)據(jù)挖掘生態(tài)最成熟sklearn直接提供聚類和分類模型pandas處理表格數(shù)據(jù)非常順手可視化用ECharts做前端展示后端用Flask暴露接口。整份源碼分成四個模塊data_process/原始數(shù)據(jù)導(dǎo)入、缺失值處理、異常值截斷、特征工程最終輸出標(biāo)準(zhǔn)化后的建模寬表。cluster_model/PCA降維、K-Means聚類、層次聚類輔助驗證、輪廓系數(shù)評估、分群畫像輸出。risk_model/預(yù)警標(biāo)簽構(gòu)造、訓(xùn)練集/測試集劃分、邏輯回歸與隨機(jī)森林對比、AUC與KS指標(biāo)計算。visualization/Flask后端接口ECharts前端大屏包括聚類散點(diǎn)圖、風(fēng)險漏斗圖、用途利率散點(diǎn)圖。這個組織方式不是隨便拍的而是按照“數(shù)據(jù) - 人群 - 風(fēng)險 - 表達(dá)”的順序來安排。每個模塊的產(chǎn)物會成為下一個模塊的輸入。比如聚類結(jié)果作為一個新字段喂給風(fēng)控模型風(fēng)控模型的輸出結(jié)果再作為可視化大屏的數(shù)據(jù)源。這樣各模塊之間耦合度低論文里也容易畫出層次清晰的架構(gòu)圖。選擇Flask而不直接用Django是因為畢設(shè)場景下不需要用戶登錄、后臺管理這些偏工程的能力Flask輕量、接口邏輯簡單前端用原生HTMLECharts就能跑。如果你已經(jīng)裝了Anaconda直接跑pip install flask pandas scikit-learn matplotlib就能把環(huán)境湊齊不需要額外折騰數(shù)據(jù)庫。數(shù)據(jù)量在十萬級以下時CSV文件配合pandas足夠支撐整個項目了。2. 數(shù)據(jù)預(yù)處理與多維特征融合2.1 數(shù)據(jù)來源與核心字段梳理這個題目沒有公開的標(biāo)準(zhǔn)數(shù)據(jù)集需要自己構(gòu)造或合拼。常見的做法是參考Lending Club的公開字段結(jié)構(gòu)自己構(gòu)造一份包含客戶基本信息、歷史行為、貸款字段的模擬數(shù)據(jù)。字段設(shè)計要貼合國內(nèi)互聯(lián)網(wǎng)貸款的業(yè)務(wù)習(xí)慣至少要覆蓋下面幾類特征類別代表字段用途說明客戶基本盤年齡、性別、收入、學(xué)歷、職業(yè)類型刻畫還款能力的基礎(chǔ)信息負(fù)債與需求負(fù)債總額、貸款金額、貸款期限、申請用途判斷資金壓力與資金去向歷史行為征信查詢次數(shù)、歷史逾期次數(shù)、當(dāng)前逾期天數(shù)、歷史貸款筆數(shù)判斷還款意愿與信用歷史行為融合特征收入負(fù)債比、近6個月平均查詢次數(shù)、額度使用率、收入穩(wěn)定性多維特征融合后的核心變量我在做數(shù)據(jù)準(zhǔn)備時特別注意“貸款用途”字段題目里專門提到用途與風(fēng)險定價可視化所以這個字段必須保留而且不能只做成啞變量還要在后續(xù)聚類和預(yù)警里作為分群的特征之一。用途一般包含經(jīng)營周轉(zhuǎn)、日常消費(fèi)、裝修、教育、醫(yī)療、購車、旅游等建議統(tǒng)一編碼成類別再結(jié)合數(shù)值特征做Embedding式融合。如果你用的是自己爬來的數(shù)據(jù)格式肯定很亂。清洗的第一步是把所有字段統(tǒng)一命名、統(tǒng)一單位金額統(tǒng)一換算為元時間字段統(tǒng)一為YYYY-MM-DD。第二步是檢查取值范圍比如年齡不可能超過100歲貸款金額不能為負(fù)數(shù)征信查詢次數(shù)必須是整數(shù)這些約束都要寫進(jìn)清洗函數(shù)里而不是靠肉眼核對。2.2 清洗、標(biāo)準(zhǔn)化與特征構(gòu)造數(shù)據(jù)清洗這一塊最容易出問題是缺失值比例高的時候。貸款數(shù)據(jù)里收入字段經(jīng)常缺失直接刪除會損失大量樣本。我的做法是先用缺失比例排序低于5%的字段用中位數(shù)填充高于30%的字段直接丟棄中間的字段用“是否缺失”作為一個二值特征加入模型。這樣既保住了樣本量又把缺失信息本身變成了特征。異常值不能只靠describe()看一眼就完事。收入字段的99分位可能高達(dá)幾十萬直接參與聚類會讓K-Means的重心計算被極值帶偏。穩(wěn)妥的截斷方法是取1%到99%分位小于下分位或大于上分位的值統(tǒng)一壓到邊界。實際操作里可以這樣寫def winsorize_series(s, lower0.01, upper0.99): q_low s.quantile(lower) q_high s.quantile(upper) return s.clip(q_low, q_high)特征工程是提高模型效果最劃算的一步。原始字段只能提供單點(diǎn)信息真正的風(fēng)險信號往往藏在比值、頻次、趨勢里。我做過的項目中下面這幾個手工衍生特征對聚類和預(yù)警的幫助最大debt_to_income 總負(fù)債 / 年收入直接衡量還款壓力數(shù)值越高風(fēng)險越大。recent_query_6m 近6個月征信查詢次數(shù)查詢次數(shù)暴增通常代表多頭借貸。overdue_ratio 歷史逾期次數(shù) / 歷史貸款筆數(shù)衡量用戶還款習(xí)慣的穩(wěn)定性。usage_rate 貸款金額 / 信用卡額度代表資金緊張程度。income_stability 近6個月收入標(biāo)準(zhǔn)差 / 平均收入收入波動越大越可能斷供。這些衍生特征加進(jìn)去之后你會明顯感覺到客戶之間的差異性被拉出來了。后面K-Means分出來的人群不再只是“年齡大的人”和“年齡小的人”而是“高負(fù)債、高查詢、經(jīng)營周轉(zhuǎn)型”和“低負(fù)債、穩(wěn)定收入、日常消費(fèi)型”業(yè)務(wù)解釋性強(qiáng)得多。2.3 多維特征融合策略特征融合在工程上的常見做法不是把變量隨便拼在一起而是區(qū)分不同類型采用不同策略。數(shù)值特征用標(biāo)準(zhǔn)化類別特征用獨(dú)熱編碼或目標(biāo)編碼時間特征拆成年、月、是否工作日等周期項再把這些處理后的特征一起拼成寬表。拼接之后通常會有幾十維如果直接拿去聚類稀疏性和噪聲會干擾距離計算。這時就需要降維。最常用的方案是PCA但PCA本身是無監(jiān)督方法它只保留方差最大的方向不一定對業(yè)務(wù)解釋友好。我會同時保留兩個層面的結(jié)果聚類散點(diǎn)圖用PCA的前兩個主成分做展示建模數(shù)據(jù)用用標(biāo)準(zhǔn)化后的全量特征不強(qiáng)行壓到極低維度。這樣既照顧了可視化需求又不損失建模信息。真正意義上的多維融合我還會做一步“特征選擇”。通過隨機(jī)森林的特征重要性排序把重要性低于閾值的字段剔除只保留對風(fēng)險區(qū)分度最高的二十個左右特征。這樣做的好處是防止聚類被無關(guān)變量帶偏比如“客戶姓名長度”這種字段如果存在一定會干擾距離計算但它和風(fēng)險沒有關(guān)系。把所有特征無腦拼進(jìn)去是新手最常見的錯誤。3. 客戶聚類從K值選擇到分群畫像3.1 為什么先聚類再做風(fēng)險預(yù)警一個很容易被忽視的問題是既然我們已經(jīng)有監(jiān)督模型可以做預(yù)警為什么還要先花力氣聚類我的理解是互聯(lián)網(wǎng)貸款客戶天生就是異質(zhì)的不同人群的風(fēng)險驅(qū)動因素完全不同。單一模型用一個全局閾值判斷所有客戶會犧牲不同群體的差異。舉個例子一個年收入50萬的個體戶偶爾逾期5天但貸款用途是備貨周轉(zhuǎn)還款來源清晰一個剛?cè)肼氃率杖?000元的白領(lǐng)從未逾期但貸款用途是分期買手機(jī)負(fù)債率已經(jīng)超過60%。如果用全局模型打分很可能個體戶被標(biāo)記為風(fēng)險更高但實際爆雷概率也許低于那個負(fù)債已經(jīng)到頂?shù)陌最I(lǐng)。聚類能幫我們先識別出這種結(jié)構(gòu)性差異再在每個客群內(nèi)部分別評估風(fēng)險。同時聚類結(jié)果本身就是很好的業(yè)務(wù)標(biāo)簽。銀行和消金公司非??粗乜腿悍謱硬煌瑢蛹売貌煌瑺I銷策略、不同利率、不同額度。畢設(shè)里能把這層意思講透評委通常會覺得你對業(yè)務(wù)有理解而不是只會調(diào)包。3.2 K-Means與層次聚類的實踐聚類算法我用的是K-Means主方案原因是它在樣本量幾萬到幾十萬時效率高結(jié)果也相對好解釋。但K-Means對初始中心敏感對離群點(diǎn)敏感所以前面提到的異常值截斷和標(biāo)準(zhǔn)化必須做干凈。為了避免隨機(jī)種子帶來的不穩(wěn)定性我固定了random_state42并且跑了多組K值取輪廓系數(shù)的平均值再選K。K值的選擇我同時用了兩種方法。第一種是肘部法則畫出簇內(nèi)誤差平方和SSE隨K值變化的曲線找拐點(diǎn)第二種是輪廓系數(shù)直接計算不同K下的平均輪廓系數(shù)選最高的K。兩者結(jié)論不一致時優(yōu)先參考輪廓系數(shù)因為SSE曲線很多時候沒有明顯拐點(diǎn)。from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score scores [] for k in range(2, 9): model KMeans(n_clustersk, random_state42, n_init10) labels model.fit_predict(X_scaled) scores.append(silhouette_score(X_scaled, labels)) best_k range(2, 9)[scores.index(max(scores))]除了K-Means我還會跑一次層次聚類作為交叉驗證。層次聚類可以畫出樹狀圖直觀看出每個簇的分裂過程特別適合在論文里展示聚類邏輯。但層次聚類的計算復(fù)雜度偏高樣本超過五萬就慢得難受所以只用它在一個小規(guī)模抽樣子集上驗證。兩個算法得出的簇數(shù)一致時結(jié)論會更有說服力。聚類散點(diǎn)圖一定是用PCA降維后畫的不然高維空間只能看兩兩組合無法呈現(xiàn)群體邊界。實操中可以先PCA降到二維再以散點(diǎn)圖著色展示聚類結(jié)果。每個簇的中心點(diǎn)可以用紅色X標(biāo)記這樣即使客戶樣本點(diǎn)重疊嚴(yán)重也能看出分群重心的大致位置。3.3 聚類結(jié)果畫像與業(yè)務(wù)解讀聚類完成后我習(xí)慣做一張“分群畫像表”把每個簇在各個特征上的均值列出來然后根據(jù)均值特征給簇起一個有業(yè)務(wù)含義的名字。這一步很關(guān)鍵論文里的分析深度全靠這里體現(xiàn)。比如做出來的結(jié)果可能是這樣分群收入均值負(fù)債率均值近6月查詢次數(shù)逾期率主要用途業(yè)務(wù)標(biāo)簽01.2萬18%2.10.8%裝修、購車優(yōu)質(zhì)穩(wěn)健型1800055%6.84.2%日常消費(fèi)、教育資金緊張型22.5萬65%9.37.5%經(jīng)營周轉(zhuǎn)高杠桿經(jīng)營型“優(yōu)質(zhì)穩(wěn)健型”客戶收入不低、負(fù)債不高逾期率極低適合推低息大額產(chǎn)品“資金緊張型”客戶收入偏低但查詢次數(shù)多存在多頭借貸跡象應(yīng)該控制額度并提高利率“高杠桿經(jīng)營型”客戶收入高但負(fù)債率也高風(fēng)險缺口在于現(xiàn)金流波動需要結(jié)合經(jīng)營流水?dāng)?shù)據(jù)做二次核驗。這些畫像結(jié)論看起來不復(fù)雜但需要你真的去統(tǒng)計均值并觀察差異。我通常會把每個簇的特征均值做成橫向柱狀對比圖再用雷達(dá)圖展示三四個核心特征的相對水平。這些圖放在畢設(shè)里比一堆數(shù)字直觀得多評委掃一眼就知道聚類是有效的。4. 風(fēng)險預(yù)警與風(fēng)險定價模型4.1 預(yù)警標(biāo)簽怎么打風(fēng)險預(yù)警屬于有監(jiān)督學(xué)習(xí)第一步是確定“什么是壞用戶”。公開數(shù)據(jù)不會直接給你一個違約標(biāo)簽所以需要自己根據(jù)業(yè)務(wù)含義定義。我的定義規(guī)則是當(dāng)前逾期天數(shù)30天標(biāo)記為高風(fēng)險同時結(jié)合未來三個月的還款表現(xiàn)如果用戶后續(xù)逾期超過60天也標(biāo)記為壞樣本。這句話聽起來簡單但要注意標(biāo)簽泄漏。如果直接用“當(dāng)前是否逾期”作為標(biāo)簽再把“當(dāng)前逾期天數(shù)”作為特征模型會學(xué)到一個恒等映射看起來AUC接近1.0實際毫無意義。正確做法是刪除“當(dāng)前逾期天數(shù)”這個字段只保留歷史行為特征比如過去12個月的逾期次數(shù)、查詢次數(shù)、負(fù)債變化等。對于沒有未來還款表現(xiàn)的數(shù)據(jù)也可以用無監(jiān)督的異常檢測思路來輔助打標(biāo)簽。把異常分?jǐn)?shù)排名前10%的用戶視為潛在風(fēng)險客戶再結(jié)合規(guī)則標(biāo)簽獲得一個半監(jiān)督訓(xùn)練集。但畢設(shè)場景下我更推薦直接構(gòu)造模擬壞客戶在正常客戶中隨機(jī)注入高逾期特征再標(biāo)記為高風(fēng)險。這樣模型學(xué)的是特征之間的組合關(guān)系而不是某一列的復(fù)制粘貼。4.2 預(yù)警模型的選擇與訓(xùn)練我同時跑了邏輯回歸和隨機(jī)森林原因是兩者各有優(yōu)勢論文里可以做對比。邏輯回歸是風(fēng)控場景的基準(zhǔn)模型系數(shù)正負(fù)和大小能直接解釋為“特征每增加一個單位風(fēng)險對數(shù)幾率的變化”可解釋性強(qiáng)隨機(jī)森林能自動捕捉非線性關(guān)系A(chǔ)UC通常更高但黑盒感強(qiáng)。訓(xùn)練時要特別注意類別不平衡。正常情況下好客戶可能占90%以上壞客戶不到10%。如果直接訓(xùn)練模型會傾向于把所有樣本預(yù)測為好客戶雖然準(zhǔn)確率很高AUC卻并不一定差但壞客戶一個也撈不上來。解決思路有三個一是用class_weightbalanced讓模型自動調(diào)整類別權(quán)重二是對訓(xùn)練集做SMOTE過采樣三是預(yù)測時把閾值從0.5下調(diào)到0.3或0.2按業(yè)務(wù)需求在召回率與精確率之間找平衡。評估指標(biāo)不要只看準(zhǔn)確率風(fēng)控場景看AUC、KS、混淆矩陣。KS值能刻畫模型區(qū)分好壞樣本的能力大于0.3就基本可用了AUC和KS一起看比單看準(zhǔn)確率靠譜得多。額外多說一句做特征重要性分析時隨機(jī)森林能直接輸出Gini importance邏輯回歸可以用系數(shù)絕對值排序如果兩邊的top特征高度重合那說明特征工程做得很扎實。4.3 風(fēng)險定價與貸款用途的關(guān)系風(fēng)險定價這塊很多人不知道怎么做量化。我的處理方式是把預(yù)警概率映射為風(fēng)險溢價再與利率建立線性關(guān)系。假設(shè)基準(zhǔn)資金成本是5%客戶的違約概率是p預(yù)期損失率約等于p乘以一個固定損失回收系數(shù)那么風(fēng)險定價利率可以近似為base_rate 0.05 loss_given_default 0.7 pred_prob model.predict_proba(X_test)[:, 1] risk_premium pred_prob * loss_given_default loan_rate base_rate risk_premium operation_cost這里面的loss_given_default設(shè)為0.7表示一旦違約本金損失七成這個數(shù)字可以按業(yè)務(wù)場景調(diào)整。最終算出的利率會自然地按預(yù)警概率高低排序高風(fēng)險客戶利率更高。為了可視化我們用貸款用途分組統(tǒng)計每組客戶的平均預(yù)警概率、平均利率、實際逾期率然后畫散點(diǎn)圖和柱狀圖。從業(yè)務(wù)角度看經(jīng)營周轉(zhuǎn)類客戶的金額通常較大、期限較短但利率跨度也比較大日常消費(fèi)類客戶金額小、利率相對穩(wěn)定。如果發(fā)現(xiàn)某個用途組的實際逾期率和模型預(yù)測概率差距過大就說明該組客戶的還款行為特殊需要單獨(dú)調(diào)整定價策略。這種“用途-利率-逾期率”的三角關(guān)系正好是題目副標(biāo)題要求研究的內(nèi)容。5. 可視化大屏與數(shù)據(jù)呈現(xiàn)5.1 可視化指標(biāo)框架與頁面結(jié)構(gòu)可視化部分不是隨便扔幾張統(tǒng)計圖就完事而是要有清晰的看板邏輯。我的大屏分四個核心區(qū)域頂部放整體業(yè)務(wù)概覽包括客戶總數(shù)、貸款總額、整體風(fēng)險等級占比、平均利率中間區(qū)域放聚類結(jié)果散點(diǎn)圖和每個簇的用戶畫像指標(biāo)右側(cè)放風(fēng)險預(yù)警概覽包括高風(fēng)險客戶占比、風(fēng)險等級漏斗圖、逾期率走勢底部區(qū)域放貸款用途與利率、逾期率的關(guān)系圖。頁面結(jié)構(gòu)上我參考了現(xiàn)在的企業(yè)級數(shù)據(jù)可視化大屏風(fēng)格以深色科技風(fēng)為主用ECharts自帶的深色主題配合紅黃綠三色做風(fēng)險等級提示。背景用深藍(lán)灰色卡片標(biāo)題統(tǒng)一左上角基礎(chǔ)單位統(tǒng)一顯示避免圖表數(shù)據(jù)量綱不同導(dǎo)致誤讀。也可以用現(xiàn)有的大屏框架類項目作為模板但自己寫HTML布局其實不復(fù)雜四張卡片加四個圖表容器就夠了。一屏放不下所有內(nèi)容就采用“總覽篩選同頁切換”的方式。頂部放一個貸款用途的下拉篩選器選擇不同用途時下面的聚類散點(diǎn)圖、風(fēng)險漏斗、利率分布全部聯(lián)動刷新。交互式分析能體現(xiàn)你做了前端聯(lián)動方案在評審時也是加分項。5.2 用ECharts實現(xiàn)核心圖表ECharts的圖形渲染質(zhì)量高社區(qū)資料多出圖效果非常適合畢設(shè)。我在項目里用了三種核心圖PCA聚類散點(diǎn)圖、風(fēng)險等級漏斗圖、用途-利率-逾期率散點(diǎn)圖。聚類散點(diǎn)圖的實現(xiàn)邏輯是把后端返回的每個樣本的x、y、cluster三個字段拿出來遍歷成ECharts的scatter數(shù)據(jù)。每個簇單獨(dú)一個series顏色用調(diào)好的色板區(qū)分symbolSize按樣本量做縮放避免太多點(diǎn)重疊成一團(tuán)糊。這樣的圖放在大屏中間一眼就能看出人群分裂的邊界。用途-利率-逾期率散點(diǎn)圖更講究一點(diǎn)橫軸是平均利率縱軸是實際逾期率點(diǎn)的大小代表貸款金額顏色代表用途類型。這張圖最直觀地回應(yīng)了“風(fēng)險定價可視化研究”這個題目當(dāng)看到某一個用途的點(diǎn)在右上方說明利率高、逾期率也高定價是合理的如果某個用途的點(diǎn)在左上方說明利率不高但逾期率不低就存在定價偏低的嫌疑。前端調(diào)用后端接口時我的Flask路由統(tǒng)一返回jsonify({status: 200, data: list_dict})前端用fetch拉數(shù)據(jù)后直接setOption。需要注意ECharts實例要在數(shù)據(jù)返回后再初始化否則容器寬度還沒穩(wěn)定很容易出現(xiàn)圖表發(fā)虛的毛病。5.3 大屏的交互與部署注意交互設(shè)計方面我會給每個圖表加上tooltip提示框、legend圖例、dataZoom縮放條。尤其聚類散點(diǎn)圖樣本量大不帶縮放條的話局部細(xì)節(jié)完全看不清楚。篩選器不只是裝飾要真的綁定到后端的查詢參數(shù)上比如選擇“經(jīng)營周轉(zhuǎn)”后接口返回的數(shù)據(jù)全部按該用途過濾前端圖表刷新。部署時我把Flask服務(wù)跑在本地9100端口大屏頁面通過相對路徑訪問避免跨域問題。如果你要把項目打包交給老師不要給MySQL依賴最好把處理好的數(shù)據(jù)緩存在pickle或JSON文件里前端直接讀靜態(tài)JSON。這樣免去老師配數(shù)據(jù)庫的麻煩項目打開即用。數(shù)據(jù)口徑的一致性是可視化最容易翻車的地方。很多人在后端寫統(tǒng)計SQL時只寫了客戶總數(shù)到前端圖表又是另一個總數(shù)兩張圖對不上答辯時會被一眼看穿。我的經(jīng)驗是全局只保留一份匯總好的JSON數(shù)據(jù)所有圖表都從這份數(shù)據(jù)里取值不再各自計算。6. 實操過程遇到的高頻坑6.1 標(biāo)簽泄漏預(yù)警模型看起來效果爆表的原因我一開始直接把“當(dāng)前逾期天數(shù)”當(dāng)作特征保留了結(jié)果邏輯回歸AUC直接沖到0.97心里還挺高興。后來用特征重要性一看排名第一的特征就是當(dāng)前逾期天數(shù)這明顯不對。因為“當(dāng)前逾期天數(shù)”和標(biāo)簽的定義本就是一回事模型根本不需要學(xué)習(xí)直接記住這個字段就能預(yù)測。解決辦法是把標(biāo)簽相關(guān)的字段從特征里全部剔除包括當(dāng)前逾期天數(shù)、是否逾期這些直接變量。保留的只能是與歷史行為有關(guān)的時間滯后特征比如過去6個月內(nèi)的逾期次數(shù)、過去12個月的最高逾期天數(shù)。我反復(fù)提醒自己凡是“到了今天才能知道”的信息都不能用來預(yù)測“今天是否會發(fā)生風(fēng)險”。6.2 K-Means結(jié)果不穩(wěn)定換了幾次數(shù)據(jù)都不一樣K-Means對初始中心敏感換一套數(shù)據(jù)或者換一個隨機(jī)種子聚類結(jié)果可能面目全非。哪怕邏輯上沒有錯答辯時老師讓你復(fù)現(xiàn)一遍結(jié)果對不上就很尷尬。我做了兩件事第一固定所有隨機(jī)種子包括train_test_split、KMeans、模型初始化全部傳random_state42第二增加n_init參數(shù)讓KMeans跑十次取最優(yōu)結(jié)果。再加上前面說的異常值截斷和標(biāo)準(zhǔn)化聚類結(jié)果基本穩(wěn)定。如果樣本量大還可以對數(shù)據(jù)做mini-batch K-Means但畢設(shè)數(shù)據(jù)量一般不大直接跑標(biāo)準(zhǔn)版就行層次聚類驗證也夠用了。6.3 類別不平衡讓預(yù)警模型變成“全好客戶分類器”這個問題在訓(xùn)練初期折磨了我很久。當(dāng)時模型預(yù)測的結(jié)果幾乎全是“好客戶”因為好客戶占了92%哪怕全部預(yù)測為好準(zhǔn)確率也有92%。但風(fēng)險預(yù)警完全失效。后面我改用class_weightbalanced并把決策閾值下調(diào)才讓壞客戶召回率從不到10%升到65%左右。閾值調(diào)節(jié)時需要同時看混淆矩陣不能只看AUC。AUC只反映排序能力閾值決定實際判斷結(jié)果這兩個不是一回事。我還試過用SMOTE過采樣效果也不錯但對高維稀疏數(shù)據(jù)容易生成一些離群樣本。偶爾遇到數(shù)據(jù)和模型沒問題的場景加上SMOTE反而不如調(diào)閾值穩(wěn)。所以我現(xiàn)在默認(rèn)先用class_weight再調(diào)閾值過采樣只是備選方案。6.4 可視化大屏圖表錯位和數(shù)據(jù)對不上圖表容器在小屏端容易擠壓變形我是在setOption之前等容器完成布局并且在初始化時給每個圖表設(shè)置固定寬高百分比不寫死像素。數(shù)據(jù)對不上的問題核心是統(tǒng)一數(shù)據(jù)源。我的方案是后端只生成一份dashboard_data.json前端四個圖表引用同一個對象個別圖表需要聚合數(shù)據(jù)就在前端臨時計算不做兩次后端查詢。還有一個低級的坑ECharts的formatter里拼接變量時如果數(shù)值是None或者NaN整個tooltip會顯示undefined。我一度以為自己數(shù)據(jù)有問題排查半天才發(fā)現(xiàn)是字符串模板里沒做類型轉(zhuǎn)換。所有輸出數(shù)據(jù)在返給前端前我都強(qiáng)制round(..., 2)或str()避免這類玄學(xué)報錯。7. 寫在最后的一點(diǎn)建議這套源碼做下來我最大的體會是數(shù)據(jù)分析類的畢設(shè)重點(diǎn)不全在模型調(diào)參而在于能不能把每一步?jīng)Q策背后的業(yè)務(wù)邏輯說通。為什么選K-Means而不是DBSCAN為什么把貸款用途放進(jìn)聚類特征為什么風(fēng)險定價要由預(yù)警概率驅(qū)動這些問題比AUC多0.03更能體現(xiàn)你的工作量和理解深度。源碼交付時我習(xí)慣把環(huán)境依賴寫在一個requirements.txt里附上一份“快速運(yùn)行說明”從數(shù)據(jù)生成到啟動Flask服務(wù)三步跑通。任何工具鏈都經(jīng)不起折騰能一鍵演示的項目在評審時天然占優(yōu)勢。最后再分享一個小技巧如果你的時間倉促聚類部分只保留K-Means輪廓系數(shù)預(yù)警部分只保留邏輯回歸閾值調(diào)節(jié)可視化只保留聚類散點(diǎn)圖和風(fēng)險漏斗圖也能形成一個完整閉環(huán)。演示時按“數(shù)據(jù)預(yù)處理 - 分群 - 預(yù)警 - 定價 - 可視化”的順序講既有邏輯又有視覺沖擊比盲目堆模型靠譜得多。