資料分箱
一、定義
資料分箱就是將連續變數離散化。
二、意義
• 離散特徵可變性強,易於模型的快速迭代;
• 稀疏向量運算速度快,方便儲存;
• 變數離散化後對異常資料有很強的魯棒性;
• 特徵離散以後,模型會更加穩定;
• 將邏輯迴歸模型轉換成評分卡形式的時候,分箱也是必須的。
三、分類
四、卡方分箱
(1)主要思想
• 自底向上資料離散;
• 相鄰區間具有類似的類分佈,則這兩個區間可以合併;
• 否則,這兩個區間應當分開。
(2)具體步驟
• 設定一個卡方閾值或分箱個數
• 對例項排序,每個例項屬於一個區間
• 計算每一對相鄰區間的卡方值
• 將卡方值最小的兩個區間合併
(3)分箱個數
限制最終的分箱個數結果,合併區間,直到分箱個數達到限制條件為止。
(4)卡方閾值
如果分箱的各區間最小卡方值小於卡方閾值,則繼續合併,直到最小卡方值超過設定閾值為止。
卡方閾值的確定:
• 根據顯著性水平和自由度得到卡方值;
• 自由度比類別數量小1。例如:有3類,自由度為2,則90%置信度(10%顯著性水平)下,卡方的值為4.6。
五、分箱評估
評估方法:
• WOE(weight of evidence),證據權重。WOE是對原始自變數的一種有監督的編碼形式。
• IV(information value),資訊價值。IV是衡量特徵區分度的一種指標。
(1)WOE:
要對一個變數進行WOE編碼,首先把這個變數進行分箱處理,分箱後,對於第i組,WOE的計算公式如下:
其中,pyi是第i組中響應客戶佔所有樣本中所有響應客戶的比例,pni是第i組中未響應客戶佔樣本中所有未響應客戶的比例。
當前這個組中響應的客戶和未響應客戶的比值,和所有樣本中這個比值的差異。這個差異是用這兩個比值的比值,再取對數來表示的。
(2)IV值
對於第i組,IV的計算公式如下:
由每個分組的IV值就可以得到整個變數的IV值,即將各個分組IV值相加:
(3)變數IV——預測能力對應表
(4)為什麼使用IV值進行判斷,而不直接使用WOE值進行判斷呢?
原因:
• IV值是非負的,衡量一個變數的預測能力比較合適;
• IV值體現出當前分組中個體的數量佔整體數量的比例,對變數預測能力的影響。
(5)注意事項
• 檢查最大箱,如果最大箱裡面資料數量佔總資料的90%以上,那麼棄用這個變數;
• 當有兩個變數相關性高並且只能保留一個時,選擇IV值高的或者分箱均衡的變數;
• 如果遇到響應比例為0或者100%時:將這個分組做成一個規則,作為模型的前置條件或者補充條件;重新對變數進行分組;人工調整。
六、R實現分箱
R中的woeBinning和smbinning包可以實現⾃自動分箱。
下面介紹woeBinning包。
woeBinning函式
woe.binning對數值變數或者因子變數生成一個受監督的細分和粗分類。
woe.tree.binning對數值變數和因子變數生成監督樹狀分割。
woe.binning.plot對woe.binning或者woe.tree.binning的分箱解決方案進行資料視覺化。
woe.binning.table對woe.binning或woe.tree.binning的分箱解決方案的結果進行表格化儲存。
woe.binning.deploy將把woe.binning或woe.tree.binning生成並儲存的分箱解決方案部署和應用到(新)資料中。
> library(woeBinning) > library(dplyr) > # 使用包自帶的資料集germancredit > data( "germancredit") > # 資料集檢視 > print(dim(germancredit))#21維,1000條資料 [1] 1000 21 > # 資料集部分變數資料獲取 > # 定性變數和定量變數 > df <- germancredit[, c( 'creditability', 'credit.amount', 'duration.in.month', 'savings.account.and.bonds', 'purpose')] > print(head(df)) creditability credit.amount duration.in.month savings.account.and.bonds purpose 1 good 1169 6 unknown/ no savings account radio/television 2 bad 5951 48 ... < 100 DM radio/television 3 good 2096 12 ... < 100 DM education 4 good 7882 42 ... < 100 DM furniture/equipment 5 bad 4870 24 ... < 100 DM car (new) 6 good 9055 36 unknown/ no savings account education > # 自動分箱操作 > binning <- woe.binning(df, 'creditability', df) > # 自動分箱後結果視覺化 > woe.binning.plot(binning) > # 分箱解決方案表格化儲存 > tabulate.binning <- woe.binning.table(binning)
> tabulate.binning $`WOE Table for duration.in.month` Final.Bin Total.Count Total.Distr. bad.Count good.Count bad.Distr. good.Distr. good.Rate WOE IV 1 <= 6 82 8.2% 9 73 3.0% 10.4% 89.0% -124.6 0.093 2 <= 15 349 34.9% 80 269 26.7% 38.4% 77.1% -36.5 0.043 3 <= 30 396 39.6% 128 268 42.7% 38.3% 67.7% 10.8 0.005 4 <= Inf 173 17.3% 83 90 27.7% 12.9% 52.0% 76.6 0.113 6 Total 1000 100.0% 300 700 100.0% 100.0% 70.0% NA 0.254 $`WOE Table for savings.account.and.bonds` Final.Bin Total.Count Total.Distr. bad.Count good.Count bad.Distr. good.Distr. good.Rate 1 misc. level neg. 48 4.8% 6 42 2.0% 6.0% 87.5% 2 unknown/ no savings account + 500 <= ... < 1000 DM 246 24.6% 43 203 14.3% 29.0% 82.5% 3 ... < 100 DM + 100 <= ... < 500 DM 706 70.6% 251 455 83.7% 65.0% 64.4% 4 Total 1000 100.0% 300 700 100.0% 100.0% 70.0% WOE IV 1 -109.9 0.044 2 -70.5 0.103 3 25.2 0.047 4 NA 0.194 $`WOE Table for purpose` Final.Bin Total.Count Total.Distr. bad.Count good.Count bad.Distr. 1 misc. level neg. 9 0.9% 1 8 0.3% 2 radio/television + car (used) 383 38.3% 79 304 26.3% 3 education + car (new) + misc. level pos. + business + furniture/equipment 608 60.8% 220 388 73.3% 4 Total 1000 100.0% 300 700 100.0% good.Distr. good.Rate WOE IV 1 1.1% 88.9% -123.2 0.010 2 43.4% 79.4% -50.0 0.086 3 55.4% 63.8% 28.0 0.050 4 100.0% 70.0% NA 0.146 $`WOE Table for credit.amount` Final.Bin Total.Count Total.Distr. bad.Count good.Count bad.Distr. good.Distr. good.Rate WOE IV 1 <= 5969.95 850 85.0% 231 619 77.0% 88.4% 72.8% -13.8 0.016 2 <= 9162.7 100 10.0% 40 60 13.3% 8.6% 60.0% 44.2 0.021 3 <= Inf 50 5.0% 29 21 9.7% 3.0% 42.0% 117.0 0.078 5 Total 1000 100.0% 300 700 100.0% 100.0% 70.0% NA 0.115 > # 分箱解決方案部署和應用到新的資料集(IV值大於0.1的) > df.with.binned.vars.added <- woe.binning.deploy(df,binning, add.woe.or.dum.var = 'woe',min.iv.total = 0.1) > View(df.with.binned.vars.added) > woe.df <- df.with.binned.vars.added %>% dplyr::select(contains( "woe.")) > View(head(woe.df)) >
結果: