筆者最近利用決策樹對貸前風控的策略進行調整和優化,因為目前的任務是降低資損,所以對好用戶的誤殺高一點是可以容忍的,但是任然想在降低誤殺的前提下提升識別壞用戶的水平,今兒得空,將有關的東西整理一下。
整理的流程是:決策樹簡介--->數據整理---->決策樹建模---->查看規則效果---->搭建規則----->規則上線
為什么要先將決策樹放最前講呢?因為筆者認為不同的模型算法對數據方面的要求是不一樣的,所以最好是在了解了算法對數據的要求的前提下再去清洗整理數據會更有效果一些
1.決策樹
決策樹之所以能成為常用的建模工具,從使用經歷來看,有以下幾點吧:
A.生成的結果易于解釋,在實際工作中容易部署,尤其是對于金融風控來講,在什么變量的什么閾值下的用戶該被拒絕或通過,這個很依賴if-then這種判斷
B.能有效處理各類數據,例如稀疏的,偏態的,連續的,類別的,缺失值,很少需要對變量的值進行什么標準化啊,類別轉數值啊
C.可以對變量重要性進行評估,有時候可以當做特征選擇的手段來使用
但是也有一些缺陷,而這些缺陷決定了我們的數據處理過程:
A.當預測變量彼此高度相關時,那么選擇哪個變量作為切分點有很大幾率是隨機的,會導致彼此相關的變量間一些微小的變動會導致隨機選擇不同的變量作為切分點,結果可能會得到一組完全不同的劃分,即模型的方差很大,出來的規則策略不穩定,且會選擇比實際需要更多的變量,雖然集成方法能夠解決這個問題,但是
集成方法的解釋性不好,目前筆者的水平還沒發現可以用在金融風控策略方面的,如果有大佬知道還請答答疑。針對這塊,可以對預測變量查看兩兩相關性,相關性大的選擇數據質量較好的,且業務上更有解釋性的變量
B.便宜沒好貨雖然不是絕對的,但是基本上是這樣的,而決策樹因為有良好的解釋性且易于計算會使得單棵決策樹較其他模型而言一般具有次優的預測能力。原因在于樹模型會將數據劃分為若干矩形的區域,如果預測變量和結果變量之間的關系并不能由矩形來刻畫,那么樹的預測能力就不是最優的
C.決策樹還具有選擇偏差:****具有很多不同取值的預測變量通常比取值較離散的變量更容易出現在模型中,且缺失值越多,變量選擇會更有有偏。針對這個問題,筆者想到的辦法是盡可能的減少變量的缺失值,并用變量的WOE值來代替原始數值,或者盡可能選擇值較為集中的變量
通過對決策樹的優缺點進行進行梳理,得到我們的數據處理過程
2.數據處理
2.1查看數據分布
對于風控策略來講,假定壞用戶永遠是少數,那么好的數據分布應該是比較集中的,異常值是較少的,所以在處理數據之前可以看看各個白能量的數據分布
library(readxl)
library(data.table)
Sys.setlocale(category = "LC_ALL", locale = "zh_cn.utf-8") #mac系統對于中文在R中的支持
origin_data <- read_excel('數據.xlsx',sheet = 'Sheet1')
study_data <- data.table(origin_data)
sd <- study_data[,.SD,.SDcols=-c(1,3,4,5)] #將沒有業務含義的數據剔除
我們可以構建一個自定義函數,對于數值型數據用直方圖來和密度圖來展示,類別型數據用條形圖來展示
plots(sd,save = TRUE) #save代表將圖保存到本地
這里只挑選兩個結果圖來
2.2 查看缺失值并進行缺失值填補
在前面我們講到,缺失值如果比較多的話,決策樹就越會進行有偏選擇變量,所以要盡可能保證沒有缺失值,但是在實際業務中缺失值在所難免,比如購買的第三方數據并沒有這個用戶的相關數據,那就有缺失值了,所以缺失值處理要根據業務來定,如果第三方數據的缺失值很低,可以進行填補或者刪除,如果缺失值太大,那么就只能刪除了
筆者這里也自定義了一個查看各個變量的缺失率的函數
n_r <- na_ratio(sd)
> head(n_r)
vars na_ratio
1 target 0
2 V1 0
3 V2 0
4 V3 0
5 V4 0
6 V5 0
> tail(n_r)
vars na_ratio
130 V129 0.00000000
131 V130 0.02855439
132 V131 0.12752863
133 V132 0.12752863
134 V133 0.12752863
135 V134 0.00000000
可以看到有些變量是有缺失值的,因為筆者所在公司目前的策略平臺并不支持線上處理數據,只能進行簡單的四則運算,所以對于缺失值只能將其刪除,但是也不妨礙我們在自己練習的時候學一些填補方法
缺失值填補方法整理如下:
1.中心趨勢值填補,即對于數值型變量,用平均值或者中位數填補,類別型用眾數填補,這類填補方式的優點是計算方便快捷,缺點是沒有考慮目標變量的情況
2.處理缺失值的方法,根據變量之間的相關關系填補缺失值。比如選取離缺失值比較近的幾行數據來進行填補,用戶的最多的就是k近鄰算法了,可以用VIM包的中kNN函數來操作,也可以用caret包中的preProcess函數。需要注意的是,采用K近鄰方法時,會對原始數據進行標準化,如果需要返回原始值,還需將標準化公式倒推回來;
3.使用Bagging樹集成方法,理論上對缺失值的填補更權威,但其效率比較低,這個可以用caret包中的preProcess函數
4.多重插補法,可以試試mice包,其操作原理是基于MC(蒙特卡洛模擬法)
這里筆者用的是最簡單的方式:
如果缺失率超過某一閾值,刪除那一列;對于數值型變量,符合正態分布的變量用平均值填補,不符合正態分布的用中位數填補;對于名義變量,我們用眾數填補
#threshold=0.3代表缺失率超過30%就把這一列數據刪除,alpha=0.05用來判斷正態分布的
sd <- centralImputation(sd,threshold = 0.3,alpha = 0.05)
no_null_data <- sd$complete_data
> sd$delete_vars
以下數值型變量的不重復值少于3個(包含缺失值),建議剔除該變量`
[1] "V11" "V133" "target"
以下類別型變量的不重復值少于2個(包含缺失值),建議剔除`
NULL
由結果可看到,V11,V133列因為不重復值太少太少,做規則都不合適了,所以建議剔除
no_null_data <- subset(no_null_data,select=-c(V11,V133))
2.3 刪除高相關的預測變量和完全線性關系的變量
上面我們講到了,如果變量之間相關性較大的話,會導致決策樹算出來的模型不穩定
可以利用cor函數來查看每個變量之間的相關性,但是如果變量太多的話人工看過去是很花費時間和精力的,除非自己寫個函數把相關性弱的挑出來
這里可以使用caret包中的
函數語法及參數介紹:
findCorrelation(x, cutoff = .90, verbose = FALSE,names = FALSE, exact = ncol(x) < 100)
x:為一個相關系數矩陣
cutoff:指定高度線性相關的臨界值,默認為0.9
verbose:邏輯值,指定是否打印出函數運算的詳細結果
names:邏輯值,是否返回變量名,默認返回需要刪除變量的對應索引值
exact:邏輯值,是否重新計算每一步的平均相關系數
x = subset(no_null_data,select = -c(target))
x_no_character <- subset(x,select = -c(V1)) #去除已知的類別型數據
corr <- cor(x_no_character) #在用findCorrelation之前要先計算出相關性矩陣
發現這里出現了個錯誤,如下所示,這說明數據里面混入了我所不知道的類別型數據
corr <- cor(x_no_character)
> Error in cor(x_no_character) : 'x' must be numeric
所以只好寫了個識別數據類型的函數
>> data_type(x_no_character)
$numeric
[1] "V47" "V58" "V69" "V80" "V91" "V102" "V113" "V2" "V13" "V24" "V35"
[12] "V41" "V42" "V43" "V44" "V45" "V46" "V48" "V49" "V50" "V51" "V52"
[23] "V53" "V54" "V55" "V56" "V57" "V59" "V60" "V61" "V62" "V63" "V64"
[34] "V65" "V66" "V67" "V68" "V70" "V71" "V72" "V73" "V74" "V75" "V76"
[45] "V77" "V78" "V79" "V81" "V82" "V83" "V84" "V85" "V86" "V88" "V89"
[56] "V90" "V92" "V93" "V94" "V95" "V96" "V97" "V98" "V99" "V100" "V101"
[67] "V103" "V104" "V105" "V106" "V107" "V108" "V109" "V110" "V111" "V112" "V114"
[78] "V115" "V116" "V117" "V118" "V119" "V120" "V121" "V122" "V123" "V125" "V126"
[89] "V127" "V128" "V129" "V130" "V131" "V132" "V134" "V3" "V4" "V5" "V6"
[100] "V7" "V8" "V9" "V10" "V12" "V14" "V15" "V16" "V17" "V18" "V19"
[111] "V20" "V21" "V22" "V23" "V25" "V26" "V27" "V28" "V29" "V30" "V31"
[122] "V32" "V33" "V34" "V36" "V37" "V38" "V39" "V40"
$category
[1] "V124" "V87"
終于發現了問題所在,分別查看這兩列數據,發現是用戶ID,是沒有用的,所以將其刪除
x_no_character <- subset(x_no_character,select = -c(V124,V87))
data_type(x_no_character) #發現已經沒有類別型數據了
corr <- cor(x_no_character) #在用findCorrelation之前要先計算出相關性矩陣
corr[upper.tri(corr)] #返回相關系數矩陣中的上三角值,預先查看高相關性值,但不能明確那組變量間是高相關的。
library(caret)
fc <- findCorrelation(corr,cutoff=0.80) #返回需要刪除變量的對應索引值
x_need_data <- subset(x_no_character,select = -fc)
2.4 計算各個變量的WOE值
后續的下回再寫