筆者最近利用決策樹(shù)對(duì)貸前風(fēng)控的策略進(jìn)行調(diào)整和優(yōu)化,因?yàn)槟壳暗娜蝿?wù)是降低資損,所以對(duì)好用戶的誤殺高一點(diǎn)是可以容忍的,但是任然想在降低誤殺的前提下提升識(shí)別壞用戶的水平,今兒得空,將有關(guān)的東西整理一下。
整理的流程是:決策樹(shù)簡(jiǎn)介--->數(shù)據(jù)整理---->決策樹(shù)建模---->查看規(guī)則效果---->搭建規(guī)則----->規(guī)則上線
為什么要先將決策樹(shù)放最前講呢?因?yàn)楣P者認(rèn)為不同的模型算法對(duì)數(shù)據(jù)方面的要求是不一樣的,所以最好是在了解了算法對(duì)數(shù)據(jù)的要求的前提下再去清洗整理數(shù)據(jù)會(huì)更有效果一些
1.決策樹(shù)
決策樹(shù)之所以能成為常用的建模工具,從使用經(jīng)歷來(lái)看,有以下幾點(diǎn)吧:
A.生成的結(jié)果易于解釋,在實(shí)際工作中容易部署,尤其是對(duì)于金融風(fēng)控來(lái)講,在什么變量的什么閾值下的用戶該被拒絕或通過(guò),這個(gè)很依賴if-then這種判斷
B.能有效處理各類數(shù)據(jù),例如稀疏的,偏態(tài)的,連續(xù)的,類別的,缺失值,很少需要對(duì)變量的值進(jìn)行什么標(biāo)準(zhǔn)化啊,類別轉(zhuǎn)數(shù)值啊
C.可以對(duì)變量重要性進(jìn)行評(píng)估,有時(shí)候可以當(dāng)做特征選擇的手段來(lái)使用
但是也有一些缺陷,而這些缺陷決定了我們的數(shù)據(jù)處理過(guò)程:
A.當(dāng)預(yù)測(cè)變量彼此高度相關(guān)時(shí),那么選擇哪個(gè)變量作為切分點(diǎn)有很大幾率是隨機(jī)的,會(huì)導(dǎo)致彼此相關(guān)的變量間一些微小的變動(dòng)會(huì)導(dǎo)致隨機(jī)選擇不同的變量作為切分點(diǎn),結(jié)果可能會(huì)得到一組完全不同的劃分,即模型的方差很大,出來(lái)的規(guī)則策略不穩(wěn)定,且會(huì)選擇比實(shí)際需要更多的變量,雖然集成方法能夠解決這個(gè)問(wèn)題,但是
集成方法的解釋性不好,目前筆者的水平還沒(méi)發(fā)現(xiàn)可以用在金融風(fēng)控策略方面的,如果有大佬知道還請(qǐng)答答疑。針對(duì)這塊,可以對(duì)預(yù)測(cè)變量查看兩兩相關(guān)性,相關(guān)性大的選擇數(shù)據(jù)質(zhì)量較好的,且業(yè)務(wù)上更有解釋性的變量
B.便宜沒(méi)好貨雖然不是絕對(duì)的,但是基本上是這樣的,而決策樹(shù)因?yàn)橛辛己玫慕忉屝郧乙子谟?jì)算會(huì)使得單棵決策樹(shù)較其他模型而言一般具有次優(yōu)的預(yù)測(cè)能力。原因在于樹(shù)模型會(huì)將數(shù)據(jù)劃分為若干矩形的區(qū)域,如果預(yù)測(cè)變量和結(jié)果變量之間的關(guān)系并不能由矩形來(lái)刻畫,那么樹(shù)的預(yù)測(cè)能力就不是最優(yōu)的
C.決策樹(shù)還具有選擇偏差:****具有很多不同取值的預(yù)測(cè)變量通常比取值較離散的變量更容易出現(xiàn)在模型中,且缺失值越多,變量選擇會(huì)更有有偏。針對(duì)這個(gè)問(wèn)題,筆者想到的辦法是盡可能的減少變量的缺失值,并用變量的WOE值來(lái)代替原始數(shù)值,或者盡可能選擇值較為集中的變量
通過(guò)對(duì)決策樹(shù)的優(yōu)缺點(diǎn)進(jìn)行進(jìn)行梳理,得到我們的數(shù)據(jù)處理過(guò)程
2.數(shù)據(jù)處理
2.1查看數(shù)據(jù)分布
對(duì)于風(fēng)控策略來(lái)講,假定壞用戶永遠(yuǎn)是少數(shù),那么好的數(shù)據(jù)分布應(yīng)該是比較集中的,異常值是較少的,所以在處理數(shù)據(jù)之前可以看看各個(gè)白能量的數(shù)據(jù)分布
library(readxl)
library(data.table)
Sys.setlocale(category = "LC_ALL", locale = "zh_cn.utf-8") #mac系統(tǒng)對(duì)于中文在R中的支持
origin_data <- read_excel('數(shù)據(jù).xlsx',sheet = 'Sheet1')
study_data <- data.table(origin_data)
sd <- study_data[,.SD,.SDcols=-c(1,3,4,5)] #將沒(méi)有業(yè)務(wù)含義的數(shù)據(jù)剔除
我們可以構(gòu)建一個(gè)自定義函數(shù),對(duì)于數(shù)值型數(shù)據(jù)用直方圖來(lái)和密度圖來(lái)展示,類別型數(shù)據(jù)用條形圖來(lái)展示
plots(sd,save = TRUE) #save代表將圖保存到本地
這里只挑選兩個(gè)結(jié)果圖來(lái)


2.2 查看缺失值并進(jìn)行缺失值填補(bǔ)
在前面我們講到,缺失值如果比較多的話,決策樹(shù)就越會(huì)進(jìn)行有偏選擇變量,所以要盡可能保證沒(méi)有缺失值,但是在實(shí)際業(yè)務(wù)中缺失值在所難免,比如購(gòu)買的第三方數(shù)據(jù)并沒(méi)有這個(gè)用戶的相關(guān)數(shù)據(jù),那就有缺失值了,所以缺失值處理要根據(jù)業(yè)務(wù)來(lái)定,如果第三方數(shù)據(jù)的缺失值很低,可以進(jìn)行填補(bǔ)或者刪除,如果缺失值太大,那么就只能刪除了
筆者這里也自定義了一個(gè)查看各個(gè)變量的缺失率的函數(shù)
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
可以看到有些變量是有缺失值的,因?yàn)楣P者所在公司目前的策略平臺(tái)并不支持線上處理數(shù)據(jù),只能進(jìn)行簡(jiǎn)單的四則運(yùn)算,所以對(duì)于缺失值只能將其刪除,但是也不妨礙我們?cè)谧约壕毩?xí)的時(shí)候?qū)W一些填補(bǔ)方法
缺失值填補(bǔ)方法整理如下:
1.中心趨勢(shì)值填補(bǔ),即對(duì)于數(shù)值型變量,用平均值或者中位數(shù)填補(bǔ),類別型用眾數(shù)填補(bǔ),這類填補(bǔ)方式的優(yōu)點(diǎn)是計(jì)算方便快捷,缺點(diǎn)是沒(méi)有考慮目標(biāo)變量的情況
2.處理缺失值的方法,根據(jù)變量之間的相關(guān)關(guān)系填補(bǔ)缺失值。比如選取離缺失值比較近的幾行數(shù)據(jù)來(lái)進(jìn)行填補(bǔ),用戶的最多的就是k近鄰算法了,可以用VIM包的中kNN函數(shù)來(lái)操作,也可以用caret包中的preProcess函數(shù)。需要注意的是,采用K近鄰方法時(shí),會(huì)對(duì)原始數(shù)據(jù)進(jìn)行標(biāo)準(zhǔn)化,如果需要返回原始值,還需將標(biāo)準(zhǔn)化公式倒推回來(lái);
3.使用Bagging樹(shù)集成方法,理論上對(duì)缺失值的填補(bǔ)更權(quán)威,但其效率比較低,這個(gè)可以用caret包中的preProcess函數(shù)
4.多重插補(bǔ)法,可以試試mice包,其操作原理是基于MC(蒙特卡洛模擬法)
這里筆者用的是最簡(jiǎn)單的方式:
如果缺失率超過(guò)某一閾值,刪除那一列;對(duì)于數(shù)值型變量,符合正態(tài)分布的變量用平均值填補(bǔ),不符合正態(tài)分布的用中位數(shù)填補(bǔ);對(duì)于名義變量,我們用眾數(shù)填補(bǔ)
#threshold=0.3代表缺失率超過(guò)30%就把這一列數(shù)據(jù)刪除,alpha=0.05用來(lái)判斷正態(tài)分布的
sd <- centralImputation(sd,threshold = 0.3,alpha = 0.05)
no_null_data <- sd$complete_data
> sd$delete_vars
以下數(shù)值型變量的不重復(fù)值少于3個(gè)(包含缺失值),建議剔除該變量`
[1] "V11" "V133" "target"
以下類別型變量的不重復(fù)值少于2個(gè)(包含缺失值),建議剔除`
NULL
由結(jié)果可看到,V11,V133列因?yàn)椴恢貜?fù)值太少太少,做規(guī)則都不合適了,所以建議剔除
no_null_data <- subset(no_null_data,select=-c(V11,V133))
2.3 刪除高相關(guān)的預(yù)測(cè)變量和完全線性關(guān)系的變量
上面我們講到了,如果變量之間相關(guān)性較大的話,會(huì)導(dǎo)致決策樹(shù)算出來(lái)的模型不穩(wěn)定
可以利用cor函數(shù)來(lái)查看每個(gè)變量之間的相關(guān)性,但是如果變量太多的話人工看過(guò)去是很花費(fèi)時(shí)間和精力的,除非自己寫個(gè)函數(shù)把相關(guān)性弱的挑出來(lái)
這里可以使用caret包中的
函數(shù)語(yǔ)法及參數(shù)介紹:
findCorrelation(x, cutoff = .90, verbose = FALSE,names = FALSE, exact = ncol(x) < 100)
x:為一個(gè)相關(guān)系數(shù)矩陣
cutoff:指定高度線性相關(guān)的臨界值,默認(rèn)為0.9
verbose:邏輯值,指定是否打印出函數(shù)運(yùn)算的詳細(xì)結(jié)果
names:邏輯值,是否返回變量名,默認(rèn)返回需要?jiǎng)h除變量的對(duì)應(yīng)索引值
exact:邏輯值,是否重新計(jì)算每一步的平均相關(guān)系數(shù)
x = subset(no_null_data,select = -c(target))
x_no_character <- subset(x,select = -c(V1)) #去除已知的類別型數(shù)據(jù)
corr <- cor(x_no_character) #在用findCorrelation之前要先計(jì)算出相關(guān)性矩陣
發(fā)現(xiàn)這里出現(xiàn)了個(gè)錯(cuò)誤,如下所示,這說(shuō)明數(shù)據(jù)里面混入了我所不知道的類別型數(shù)據(jù)
corr <- cor(x_no_character)
> Error in cor(x_no_character) : 'x' must be numeric
所以只好寫了個(gè)識(shí)別數(shù)據(jù)類型的函數(shù)
>> 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"
終于發(fā)現(xiàn)了問(wèn)題所在,分別查看這兩列數(shù)據(jù),發(fā)現(xiàn)是用戶ID,是沒(méi)有用的,所以將其刪除
x_no_character <- subset(x_no_character,select = -c(V124,V87))
data_type(x_no_character) #發(fā)現(xiàn)已經(jīng)沒(méi)有類別型數(shù)據(jù)了
corr <- cor(x_no_character) #在用findCorrelation之前要先計(jì)算出相關(guān)性矩陣
corr[upper.tri(corr)] #返回相關(guān)系數(shù)矩陣中的上三角值,預(yù)先查看高相關(guān)性值,但不能明確那組變量間是高相關(guān)的。
library(caret)
fc <- findCorrelation(corr,cutoff=0.80) #返回需要?jiǎng)h除變量的對(duì)應(yīng)索引值
x_need_data <- subset(x_no_character,select = -fc)
2.4 計(jì)算各個(gè)變量的WOE值
后續(xù)的下回再寫