:從分箱到評分卡的Python風控建模全解析)
1. 從信貸風控到工具化scorecardpy到底解決了什么問題做信貸風控的同學早晚都會碰到一個繞不開的課題評分卡。無論是信用卡申請評分、消費貸的貸前審批還是存量客戶的額度調整與風險定價幾乎都離不開這張卡。它本質上是一種將客群的違約概率映射為整數分數的模型讓業(yè)務人員看到分數就能快速決策而不是面對一堆概率值無從下手。好幾年前我第一次獨立做評分卡項目時最痛苦的事情其實不是建模本身而是中間的臟活累活變量分箱要手動寫一堆自定義函數、WOE和IV要逐個變量去算、分箱邊界不單調還要反復調參、生成最終的評分卡還要按步長去計算每組得分。一輪流程走下來光數據清洗和變量處理就占了八成時間。后來接觸到scorecardpy這個Python庫算是把整個流程串起來了。它專門為評分卡建模設計覆蓋變量篩選、分箱、WOE編碼、IV評估、邏輯回歸擬合、評分卡生成與校驗輸出一條流水線走完非常適合標準化的申請評分卡或行為評分卡場景。這篇解讀我會按一個完整評分卡項目從數據到落地的順序把scorecardpy的設計思路、核心參數和實際坑位都過一遍。適合正要上手評分卡建模的數據分析師、風控策略同學以及想用Python替代傳統(tǒng)SAS流程的建模人員。讀完你至少能跑通一條完整流程并理解每一步為什么要這么做。2. 評分卡建模的核心邏輯與scorecardpy的設計取舍2.1 評分卡為什么長這樣從違約概率到分數的映射在拆工具之前我們得先把評分卡本身的原理理清楚否則你很容易被各種參數繞暈。評分卡模型在統(tǒng)計層面通常是邏輯回歸。之所以不用復雜樹模型或神經網絡核心原因是業(yè)務需要強解釋性和可追溯性。每一分的變化對應哪些特征變化需要能給監(jiān)管和業(yè)務講清楚。邏輯回歸的預測結果是違約概率p但業(yè)務方不希望直接跟概率打交道更習慣用一個整數分數。分數和概率之間通過一個線性變換關聯score offset - factor * ln(p/(1-p))其中p/(1-p)是違約oddsoffset和factor是兩個常數。如果你要求一個基準分數對應的基準odds以及分數每增加多少翻倍那么factor和offset都可以算出來。比如設定基準分數為600分基準odds為50:1分數每增加20分odds翻倍那么factor 20 / ln(2)約等于28.85offset 600 - factor * ln(50)。這些細節(jié)在scorecardpy里歸根到底就是offset_factor參數你想自定義就傳進去不想自己算也可以直接用默認。邏輯回歸的自變量一般不是原始特征值而是做過WOE編碼后的值。WOE全稱是Weight of Evidence也就是證據權重。它衡量的是某一分組內好客戶odds相對于總體好客戶odds的差異WOE_i ln(壞客戶占比 / 好客戶占比)在做分箱之后每個箱子都會有一個WOE值。用WOE編碼的好處有兩個一是將分類型和連續(xù)型變量統(tǒng)一映射到同一量綱的數值二是天然處理了非線性關系比如年齡和違約率可能是U型關系分箱后WOE能直接捕捉這種形態(tài)。IV值Information Value則是每個變量的預測力度量等于每個箱子的WOE乘以該箱內好壞客戶占比差再求和。IV值小于0.02一般認為變量基本無預測力0.02到0.1為弱預測力0.1到0.3為中等大于0.3為強但太高也要警惕可能是變量泄漏或過度擬合。scorecardpy最核心的woebin函數干的事情之一就是幫你快速算出一堆變量的WOE和IV免去手動分組比對。2.2 scorecardpy的架構思路為什么它把整個流程封裝得這么深第一次用scorecardpy的人往往會被它的抽象程度驚訝到。一個woebin函數參數里塞進去待分箱的DataFrame、目標變量y、分箱方法method、分箱數初始值等等它就能把全部分箱結果一次性返回。這背后有兩個設計動機。動機一是典型評分卡建模流程高度標準化。從數據選擇、分箱、WOE編碼到模型訓練雖然在每個環(huán)節(jié)都有各種方法論爭議比如分箱到底用卡方、決策樹還是等頻等距但整體骨架是固定的。一個足夠成熟的庫完全可以把這些流程封裝成高層接口讓建模人員專注于數據和業(yè)務理解本身。動機二是業(yè)務項目對效率和可復現性要求很高。傳統(tǒng)SAS代碼做評分卡有時候一個變量分箱就要寫上百行宏而且要人工反復看分布去調邊界。scorecardpy用決策樹或者卡方方法自動合并相鄰箱子幾分鐘跑完幾十個變量的分箱。我用它重新跑了之前SAS項目里四十幾個變量的數據集分箱結果和當時人工調了幾個月的結論高度接近但肝度完全不是一個量級。但深封裝也意味著如果你不理解內部機制出了奇怪結果很難排查。這也是我寫這篇解讀的初衷搞清楚參數背后在做什么才能真正用好這個工具。3. 核心環(huán)節(jié)實操從數據到評分卡的全流程拆解3.1 數據準備與變量篩選不是所有變量都能進模型先加載一份模擬的信貸數據。數據經過脫敏字段包括客戶年齡、收入、負債率、當前逾期次數、歷史逾期次數、信用卡使用率、查詢次數、貸款用途、居住年限等目標變量為target1代表違約0代表正常。接觸評分卡建模第一步不是急著跑模型而是先做變量篩選。scorecardpy提供了var_filter函數來粗篩變量。它有幾個關鍵參數iv_limit默認0.02低于這個IV的變量會被剔除。但你也可以先把一批變量都放進來做初步分箱看IV再決定保留哪些。missing_limit默認0.95缺失率超過95%的變量直接剔除保留這種變量風險很大填充方式也容易引入偏差。identical_limit默認0.95某個取值占比超過95%的變量也會被剔除這種變量相當于常數。return_rm_reason設為True時函數會返回每個變量被剔除的原因方便后續(xù)做特征篩選報告。踩過最大的坑是粗篩時把target誤放進特征里。如果一個業(yè)務上的運營指標恰好和target強相關比如逾期客戶已經被系統(tǒng)標記該字段的IV可能接近幾百分箱結果好得驚人模型卻完全不可用。所以var_filter在篩選時一定要顯式排除目標變量和主鍵ID。3.2 分箱的藝術woebin的自動分箱與手動干預分箱是評分卡建模的靈魂步驟。分箱是否合理直接決定WOE編碼能否真實反映變量與風險的關系也決定后續(xù)評分卡的業(yè)務可解釋性。scorecardpy里的woebin函數支持幾種分箱方法默認方法基于決策樹的分箱。庫底層調用決策樹來做有監(jiān)督分箱讓樹找到最佳切分點再控制葉子節(jié)點數量。這種方法的優(yōu)點是自動尋找非線性切分點缺點是過深時分箱結果容易過擬合。chimerge方法即卡方分箱。相鄰兩個箱子如果目標分布差異不顯著就合并直到滿足停止條件??ǚ椒窒涑鰜淼倪吔缤ǔ1容^平滑但可能忽略一些模式。等距分箱和等頻分箱。這兩種屬于無監(jiān)督分箱僅按數值分布切分如果直接這么用很容易出現好客戶和壞客戶混雜嚴重的箱子后續(xù)IV會偏低。一般不推薦用作默認方式但可以作為對比參考。實際建模時我通常的做法是先用默認決策樹分箱跑一遍觀察每個箱子的WOE排序以及好壞樣本占比再手動指定某些邊界。woebin里的breaks參數可以手工傳入分箱邊界比如年齡用[18,25,30,40,50,65]這樣業(yè)務解釋更強也方便后續(xù)在評審會上向策略同事展示。手動干預最常做的另一件事是處理單調性問題。評分卡通常要求核心變量與風險呈單調關系但實際數據經常會出現U型或者倒U型。比如年齡年輕人違約率高中年人違約率低到了退休年齡段可能又升高。如果分箱結果不單調可以考慮強制合并某些臨近箱子或者接受它作為分段型變量但謹慎解釋。scorecardpy沒有自動強制單調的開關你需要基于分箱結果決定要不要調用woebin_adj函數去人工調整。woebin_adj會以交互方式展示每個變量的分箱圖和控制選項你可以手動修改箱數、合并箱子、調整邊界。當時我在某個項目里處理收入變量時數據前1%是大額多筆收入導致第一個箱子WOE異常用woebin_adj直接把極端高收入段合并到了下一個箱子整個單調性立刻順暢了。3.3 WOE編碼與IV結果分析數據長什么樣心里要有底分箱完成后scorecardpy返回一個DataFrame里面包含每個變量的分箱邊界、計數、好壞占比、WOE和IV信息。這個結果結構非常清晰每一行是一個箱子主要字段有variable變量名稱bin分箱區(qū)間標簽比如[-Inf,30)表示小于30歲的區(qū)間count、count_dist該箱樣本量和占總體的比例good、bad、good_dist、bad_dist好壞樣本量以及各自占比woe該箱的WOE值iv該變量累計IV值把這些信息可視化之后你會發(fā)現很多有趣的現象。比如信用卡使用率這個變量通常使用率高的箱子WOE為正且絕對值大意味壞占比高這個變量在評分卡里往往是強變量。再比如查詢次數查詢較多的客戶可能近期資金緊張違約風險因此更高。要注意一點IV高不代表你就要無腦放進去必須檢查變量是否有時間穿透、是否包含純未來信息以及業(yè)務上是否允許使用。某些強變量比如過去12個月貸款審批通過次數可能在貸中審核時點根本拿不到更新值上線后就已經過時了。WOE編碼之后的數據集會替換原始特征這部分由woebin_ply函數完成。它有參數to_woe如果設為True就返回WOE編碼后的DataFrame設為False則返回原始值加WOE值的對照DataFrame。通常建模前我會用to_woeTrue因為邏輯回歸輸入需要的是數值型WOE。3.4 模型擬合與逐步回歸從候選變量到可用模型生成WOE數據集之后下一步是訓練邏輯回歸。直接簡單粗暴地往邏輯回歸里扔幾十個變量顯然不行共線性問題會讓系數極不穩(wěn)定解釋性也大打折扣。scorecardpy提供了glm訓練函數它其實是基于標準邏輯回歸加逐步特征選擇。這個函數有幾個值得注意的設計輸入訓練集X_train是WOE編碼后的數據y_train是0/1標簽。內部會計算每個候選變量的IV然后按IV從高到低的方式逐批次引入變量同時做AIC或BIC評估從而篩選出最終進入模型的變量組合。輸出結果中coefficients和selected_vars兩個結果會展示最終保留的變量及系數。曾經有一次我用了某個外部變量分箱和WOE都很完美但進入逐步回歸后始終保留著我發(fā)現它在業(yè)務上解釋不通——它的高IV完全來自特定人群的冗余信息。后來加了限制不讓該變量進入候選集換用另一個強解釋性變量模型在驗證集上的穩(wěn)定性反而更好。這說明自動篩選只能輔助決策最終變量去留必須結合業(yè)務判斷。訓練結束后可以順手看下模型的AUC和KS統(tǒng)計量這兩個指標是評分卡最常見的判斷標準。AUC通常0.7到0.8之間算可用KS在0.3以上模型就有區(qū)分度了。但如果訓練集上AUC超過0.95就要警惕是不是明顯過擬合看下是不是有變量泄漏進了特征。3.5 從概率到評分卡scorecard生成與分數落點分析模型訓練只是前半場后半場是把邏輯回歸系數轉換成分數。scorecardpy里的scorecard函數傳入擬合好的模型以及分箱映射關系就會返回評分卡格式的結果。評分卡輸出形式一般是一個字典鍵為變量名值為每個分箱對應的分數明細表。根據scorecardpy的映射規(guī)則分數通常是從一個基礎分出發(fā)加上每個變量分組對應的正負分數。最終客戶總分等于基礎分加各變量得分之和總分越高代表風險越低。生成分數后默認情況下scorecardpy還會計算每個客戶的總分前提是你傳入測試數據集并調用predict方法。我個人習慣立刻跑一下分數分布看是否存在明顯的分數斷層。如果大量人群集中在分數區(qū)間邊緣可能說明模型的區(qū)分粒度不夠需要回頭調整分箱邊界或變量組合。打分完成后還要做分數校準。前面提到的offset和factor在scorecardpy里對應scorecard函數的offset_factor參數。如果你不傳函數默認按某些默認值計算也就是基準分數為600基準odds為50比1PDO為20。這和國內很多實際使用的標準不太一樣所以一定要根據自己業(yè)務目標去設置。比如某些消費金融公司把客戶違約率萬分之幾作為好客戶標準分數映射邏輯就會不同。當時我把一個模型的基準分數從600調整為650整個客群的分數分布右移審批閾值跟著變動最終通過率完全變了。這說明分數變換參數直接影響業(yè)務口徑不是可有可無的細節(jié)你必須和策略同事或跟蹤上線管理的人對齊。4. 上手實操跑通一整套評分卡建模流程4.1 環(huán)境準備與基礎安裝先準備好環(huán)境。scorecardpy對Python版本要求不算苛刻一般3.7以上都可以用。安裝方式除了從PyPI下載也可以通過代碼倉庫的版本安裝這里我直接使用最常見的安裝命令配合國內鏡像會更快pip install scorecardpy如果下載速度慢可以用國內鏡像源常見的清華源、阿里源都可以加速pip install scorecardpy -i https://pypi.tuna.tsinghua.edu.cn/simple在導入階段有些新版本會提示依賴項缺少比如sklearn或pandas版本不匹配這種情況只要把相關依賴重新升級一下就行。順便提一句安裝庫之后最好看一下版本號后續(xù)使用過程中不同版本之間可能有細微參數差異。4.2 用自帶示例數據集快速跑通scorecardpy內部帶了一個示例數據集非常適合第一次跑通全流程。你只需要幾行代碼就能完成分箱和WOE模塊的調用import scorecardpy as sc dat sc.germancredit() y dat[creditability] X dat.drop(columnscreditability) # 變量粗篩 dt_sel sc.var_filter(dat, yy, iv_limit0.02, missing_limit0.95, identical_limit0.95, return_rm_reasonTrue) # 分箱 bins sc.woebin(dt_sel, yy) # WOE編碼 train_woe sc.woebin_ply(dt_sel, bins)上面這幾行就已經完成了數據篩選、分箱和WOE編碼三步。打印bins里任何一個變量的分箱結果都能看到詳細的WOE和IV統(tǒng)計我建議第一次練習時逐字段觀察一下培養(yǎng)感覺。如果你把bins傳給woebin_plot函數它會把每個變量的分布圖、好壞占比、WOE趨勢畫在一張圖上直觀看到變量和風險的關系形態(tài)。這個可視化在寫評審材料時特別有用比貼一堆數據表格強得多。4.3 從訓練到評分卡的完整腳本我給出一個平時常用的完整建模腳本處理好數據后你可以直接參考著改寫import scorecardpy as sc from sklearn.model_selection import train_test_split # 設示例數據 dat sc.germancredit() y dat[creditability] X dat.drop(columnscreditability) # 粗篩 X_sel, y_sel sc.var_filter(X, y, iv_limit0.05, missing_limit0.9, identical_limit0.9, return_rm_reasonFalse) # 分箱 bins sc.woebin(X_sel, y_sel) # WOE轉換 woe_data sc.woebin_ply(X_sel, bins) # 劃分訓練集和測試集 train, test train_test_split(woe_data, test_size0.3, stratifyy_sel, random_state42) X_train train.drop(columnscreditability) y_train train[creditability] X_test test.drop(columnscreditability) y_test test[creditability] # 邏輯回歸與逐步篩選 m1 sc.glm(X_train, y_train) # 在測試集上評估 pred m1.predict(X_test)整體流程走下來你會發(fā)現scorecardpy把過去手工需要寫幾百行代碼的環(huán)節(jié)壓縮到了十幾行。但正因為足夠快你更要警惕隨手就交付風險。每一輪產出之后都建議回頭人工檢查分箱是否合理、WOE編碼是否跟業(yè)務認知一致、模型系數符號是否符合預期。4.4 生成評分卡和分數解釋模型訓練完之后生成評分卡的代碼同樣非常簡短# 生成評分卡 card sc.scorecard(binsbins, modelm1, points0600, odds050, pdo20) # 給樣本打分 score sc.scorecard_ply(woe_data, card) # 查看評分卡明細 print(card)打印card之后你會看到一個很直觀的對照表每個變量每個分箱區(qū)間都對應該變量的加分或減分。比如年齡變量30到40歲區(qū)間可能加10分而25歲以下區(qū)間可能是減15分。最終客戶分數就是基礎分加各變量得分的累加。打分這個環(huán)節(jié)還有一個常見需求是把分數映射成概率違約等級比如A/B/C/D等級。最簡單的方法是直接把預測概率的輸出保留下來再按概率閾值切等級。但既然已經生成了整數分數也可以直接用分數分位數去切等級這個開源工具不直接提供等級映射功能需要自己處理。如果要做更細致的校準可以對比每個分數段客戶的實際違約率與理論違約率。理想狀態(tài)下二者應該一致或接近。假如預測違約率整體偏低意味著概率校準有問題這時需要檢查邏輯回歸是否存在明顯的偏差或者分數映射的基準odds設置不合理。5. 常見問題與排查技巧這些坑我都替你踩過5.1 分箱結果異常WOE全部為0或IV過高新手最常見的問題是跑完woebin后某變量的IV直接爆表或者WOE全是0。前者通常是變量和目標之間過于對應的信號比如一個狀態(tài)字段里目標為1的樣本全都在某個取值區(qū)間內分箱后該區(qū)間壞占比為100%WOE會趨向無窮大。這種變量一旦進模型會出現完美分離現象邏輯回歸系數無法收斂。排查時可以將這類變量拿出來單獨交叉分析確認它在未來數據上是否可獲取、是否有意義。WOE全為0則往往是因為變量本身沒有區(qū)分能力每個箱子的好壞占比都和總體一致導致每個箱子的ln(1)等于0。如果你看到所有變量都這樣大概率是目標變量傳錯了比如把訓練集中目標列全部傳成同一個值或者分箱參數設置過粗導致每個箱子都只有一個類別。調試的時候建議先用少量變量跑一次分箱并打印結果確認單變量邏輯沒問題后再全量跑幾十個變量這樣能大幅縮短排查時間。5.2 預測函數和變量名列不一致實際項目中最常遇到的報錯之一是predict時提示變量缺失原因是woebin_ply生成的訓練集列名和預測時傳入數據集的列名不一致比如訓練時你傳入了原始字段名預測時卻傳入了已經處理過的其他字段名或者分箱對象bins來自舊數據。解決方案是維護一個統(tǒng)一的變量映射字典確保每次建模和預測過程使用同一個配置字典。另外當數據有類別型字段時分箱和預測時的category順序也必須保持一致否則WOE映射會錯位這個非常隱蔽打印幾行預測數據對比一下就知道問題出在哪。5.3 缺失值處理和特殊值的分箱邏輯評分卡建模中缺失值不能直接在邏輯回歸里被忽略否則會影響預測穩(wěn)定性。scorecardpy的分箱會自動把缺失值單獨歸為一個箱子這樣缺失本身就擁有一個獨立的WOE值可以成為一個有實際含義的變量狀態(tài)。這種做法其實很實用因為缺失往往暗示客戶信息不完整、申請漏填或者渠道差異天生就有風險識別能力。但如果缺失率太高比如超過了95%var_filter會直接剔除該變量。有些時候缺失率雖然高但缺失本身非常強此時你可以用業(yè)務規(guī)則重新定義一下變量比如把是否缺失轉換為一個新的標志字段再去參加分箱這種嘗試往往有意想不到的效果。經驗法則是缺失占比在5%到50%之間的變量保留缺失組信息超過50%再結合具體業(yè)務判斷不能一刀切低于5%可以先做填充再分箱否則缺失組樣本太少WOE也不穩(wěn)定。5.4 評分卡上線前的樣本外驗證訓練集上的指標再漂亮也不能代表未來評分卡上線前必須在時間外樣本或者至少隨機留出的測試集上跑一遍。我習慣使用時間外數據來做驗證因為評分卡業(yè)務對時間穩(wěn)定性特別敏感。某個人群在不同月份的違約率波動可能很大如果時間外樣本的KS和AUC掉得厲害基本可以認定為模型過擬合了歷史模式。另外一個容易被忽略的檢查是PSI也就是群體穩(wěn)定性指標。對比訓練樣本和未來樣本的分數分布PSI小于0.1說明兩個集合分布非常穩(wěn)定0.1到0.25說明有輕微偏移需要關注大于0.25則提示模型可能需要重新開發(fā)或者至少要做分數校準。scorecardpy本身不直接提供PSI計算但你可以基于scorecard_ply生成的分數分位數去快速實現代碼量不大。5.5 變量共線性處理不只是看相關系數邏輯回歸雖然能容忍一定程度的相關性但高度共線會讓系數估計極不穩(wěn)定。具體表現是某個變量的系數符號和業(yè)務常識相反例如收入越高反而風險分數越低。scorecardpy的逐步回歸會基于AIC篩選變量但它不會完全自動消除共線性問題。我的做法是在喂給glm之前先計算所有WOE編碼后變量的方差膨脹因子VIF把VIF大于10的變量單獨篩選出來。如果兩個變量同時進入候選集且相關性很高保留解釋性更強、邏輯業(yè)務上更好講述的那個。比如負債率和月收入可能高度相關保留負債率往往比保留月收入解釋性更順因為負債率已有標準定義在策略評審中可講的故事更完整。這里提醒一句VIF計算要在WOE編碼后做而不是原始值上做。原始值尺度和分箱化后的形態(tài)差異巨大用原始值計算VIF容易得到錯誤的絕對值。6. 擴展應用與落地經驗總結評分卡建模工具說到底只是解放生產力的工具真正決定模型質量的還是你對業(yè)務的理解和建模流程的把握。scorecardpy最值得稱道的地方在于它將繁瑣流程標準化讓模型復用和迭代的成本大幅降低。我后來幾個不同項目之間只需要調整變量清單和分箱邊界模型框架就可以快速遷移歷史方法論也能直接沉淀到工具配置中。如果你覺得scorecardpy在某些環(huán)節(jié)不夠靈活它的模塊設計是拆開的你可以只使用它的woebin分箱和WOE編碼部分然后自己用statsmodels或者sklearn訓練邏輯回歸最后再用自定義函數生成評分卡。這種方式保留了自動分箱的效率同時把模型訓練的細節(jié)掌控在自己手里。引用一句業(yè)內的老話評分卡建模中最難的不是數學而是把業(yè)務邏輯轉化成可解釋的分數和規(guī)則。多看看分箱圖、多和策略同事討論變量邏輯、多復盤線上表現與預期差異比調包參數本身更重要。我個人的習慣是每次建模完之后都會把最后生成的評分卡表格打印出來貼在工位旁邊過幾天再回頭瞄一眼。很多時候你盯著屏幕寫代碼時會忽略某個變量分數的業(yè)務合理性但人肉看一遍紙質版反而容易發(fā)現邏輯漏洞。這個方法聽起來很笨但確實幫我避免過至少一次嚴重的事故。scorecardpy的生態(tài)還在持續(xù)迭代社區(qū)里關于它的討論也越來越多。如果你用它跑過真實業(yè)務數據有自己獨特的分箱調整心得非常值得沉淀下來分享。工具是標準化的但每個人的業(yè)務理解不同這些差異化經驗才是模型效果的真正分水嶺。