R语言机器学习建模标准流程

前沿

统计学习是机器学习的基础,机器学习的方法代表了统计的最新发展,二则都是包含于数据科学之中;传统的统计模型大多对数据有一定的要求或者假设,模型本色也有比较明确的数学形式,模型的优劣主要依据对数据的分布假定得到的检验来判断;真实世界的数据分布做任何假设,因为更加的抽象和充满不确定性,高度非线性,难以用有限的数学公式来描述。机器学习对数据没有任何假定,产生的结果用交叉验证的方法来判断,摆脱了假设分布->明确数学模型来拟合->假设检验->p值的经典统计过程,交叉验证模型预测效果在具体实践中更符合对现实世界的描述。

1、确定预测目的

就是确定我们要解决什么问题,目的是什么?主要的商业价值在哪里?

2、确定样本范围

不同产品、不同渠道、不同场景和不同的商业模式等都会造成申请客户的组内方差较大;所以需要分析确定这些不同的样本之间在风险上和数据上是否存在较大的差异,如果差异较大,建议针对不同产品、渠道、场景和商业模式等单独抽取样本建立模型。根据预测目的不同,场景不同,会有有许多异常样本,故我们需要予以选择,这种异常样本通常是由其他外部因素造成的,比如医美分期、教育分期场景中,商户面造成的风险样本应该剔除,如服务纠纷导致的客户逾期,商户跑路导致的客户逾期等,都需要做清洗,这样拿到的样本才合理,样本的组内方差才会相对一致。

3、目标样本的选择

目标样本主要基于具体情况对好坏样本下一个合理的定义。这里的定义通常与好、坏样本的逾期天数,好样本的还款比例有关。但同时需要注意中间样本(即介于好坏之间的样本)的占比不要过高。坏样本通常卡一个最大逾期天数,这个逾期天数的限定需要看逾期的滚动率,比如从M1滚动到M2的比例只有10%,而M2滚动到M3的比例可能有80%,那么你就可以定义逾期大于30天以上的样本为坏样本,当然这个逾期天数并没有精确到具体期数,通常前期逾期大于30天的人要比后面逾期的人更坏一些,这个度可以自己琢磨。另外对于那种恶意逾期的人,即从第一期开始就没还款或只还过极少量贷款的人要不要放进来,也可以看具体情况,通常在模型建立完之后,需要看一下模型对这类人的预测效果。好样本通常卡一个小的逾期天数和一个较大的还款比例,这个逾期天数和还款比例也可以参照上文逾期滚动的方法来确定,比如,一个人逾期多少天之后会继续逾期下去,或者一个人一般还到多少期之后逾期的概率会非常小,据此就可以确定这两个阈值。

4、数据时间窗口
            分为建模数据窗口和验证数据窗口,建模数据是模型训练数据,验证数据是out of time验证以避免模型过拟合的数据,一般选取建模数据窗口后的一段时间。
数据时间窗口选取的原则
1)表现期成熟:也就观察期,表现期=借款期限+违约定义期限,比如借款30天的产品,以M1作为违约定义,那么放款后60天才能算表现期成熟。
2)保证数据新鲜度(有效性):模型是为了预测未来的数据,所以要保证建模的数据最接近未来,所以选取最近的数据。
3)保证数据周期性:很多贷款产品特别是pay day loan,逾期率具有时间周期性,发薪日逾期率明显低于其他时间,这种情况,数据窗口最好以月为单位选取。
4)保证样本量大小:根据经验,违约样本的数量需要至少1000个。

5、数据源确定

数据源可以分为内部数据(场景流程过程中产生的所有的数据)、外部数据(非内部数据资源,如:同盾、百融、聚信立等),同时也包括:爬虫数据源,具体就是确定此次建模能用到的所有数据表。按照数据属性也可以分为:基本属性信息、行为数据(贷前、贷中和贷后)、贷后还款数据(信贷领域)等,根据具体产品、场景等来定义,具体问题具体分析。
数据源选取的原则
1)数据覆盖率:数据覆盖率不能过低(不同模型算法要求不同,逻辑回归要求覆盖率较高,xgboost等数模型要求低些)。
2)数据稳定性:数据的计算逻辑是维持稳定的,不会发生数据定义的改变
3)未来有效性:在模型实施期,可能无法获取的数据,不能用于建模

6、变量衍生

变量衍生就是我们常说的特征工程,‘特征工程没做好,模型调到老’;特征工程的衍生方法后面会专门开一个版块详细阐述,主要方法是通过时间切片,变量组合,业务可解释性,也可以通过算法自动构造和衍生。

7、变量处理

变量一般可以分为离散变量(无序类别变量、有序类别变量),连续变量。类别变量一般可以dummy化或者直接woe化。如果无序类别变量的类别过多,可以根据逻辑或风险进行一定的归类,比如城市,按逻辑可以分为一线城市、二线城市等,按风险可以分为高风险城市,中风险城市等等。有序变量是另外一种类别变量,只不过这种变量之间的类别是有一定顺序的,比如学历,通常这种变量可以赋值为一定的数字当做连续变量进行离散,若类别不多,可以人工进行分类。连续变量通常需要离散分箱,比较简单的一般等频、等宽离散等,如果用有监督的离散,一般利用y的分布进行分组,通常离散的指标也可以用一些常见的统计值,比如iv,信息增益等。现在基于信息增益的有一种成熟的离散方法,称为MDLP,它最大的优点是给出了一个离散停止点,另外我们也会要求离散的组数不要过多,或者说某组的样本数不能过少,否则容易造成一定的过拟合。卡方分箱、最优分箱等都是我们常用的对于连续变量的分箱方法,后面会单独开一个版块详细阐述。

6、变量初筛

变量初筛主要是根据一些常规指标进行筛选,比如缺失率不能高于95%,集中度不能高于95%,另外也可以根据iv等统计值做筛选,初筛一般条件较松,会放入较多的弱变量,比如:IV>=0.02。

7、变量选择

前面的变量初筛主要是单变量指标的筛选,没有考虑变量组合的影响,所以需要用模型的方式来进行变量选择,比如决策树模型、GBDT等树模型进行选择。逻辑回归里面有一种逐步回归选择的方式来确定变量是否入模,在python里面可以用RFECV的方法来代替,原理上是一样的。如果你用的lasso,也可以直接进行变量选择。由于逻辑回归属于线性模型,有共线性的问题,所以你需要看变量之间的相关性,若两个变量相关性太强,可以剔除其中一个(通常保留IV较大的)。另外需要计算变量的vif,若某变量vif过高,需确定具体原因,剔除某些变量,直到各变量的vif值趋于正常;或者相关性系数矩阵进行选择。

8、模型建立

可以用多种算法进行拟合、选择最优,在建模过程中不同算法的选择,建模的流程也会不一样,所以需要具体算法具体分析。

9、模型效果评价

评价模型的指标主要用预测集的ks、auc和gini值等三个指标,另外lift曲线还需要建立一个根据样本预测概率排序的分组,一般分为20组或其他,观察这20组的平均风险倍数的走势,然后需要将建模时剔掉的中间样本加入,同样分为20组,这两个风险分组可以作为后续策略制定的依据。比如我拒掉最后两组,那么策略人员可能关心会拒掉多少比例,拒掉的坏样本占总体坏样本的比例是多少等等。一般来说,如果模型的K-S值达到30%,则该模型是有效的,超过30%以上则模型区分度越高,本例中模型的K-S值达到40%以上,已经可以上线使用;auc一般在70%可以上线使用。

在模型有效的前提下,需要用外推样本对模型进行稳定性的评估即OOT测试(out of time);外推样本尽可能选择近期的样本,选取样本的规则应该与模型一致,如模型选择的是过件的样本,那么你外推样本肯定也需要是过件的。同样外推样本的变量衍生、处理等过程与建模样本一样,首先计算各个变量的psi,看其psi的大小是不是在正常范围,对于那些psi较大的变量,需要分析其不一致的原因,若由于一些外部因素造成的,可能需要重新变量选择。看完变量,就可以对外推样本算出一个概率分,同样进行分组,分组的切点用的是上文分组的切点,计算psi,看其分组与上面的分组的差别,若在可接受的范围,则模型稳定效果良好。

10、模型上线

需要根据oot数据进行通过策略的制定和grade划分等保证有效性;上线流程和方法每家都不太一样,规避操作风险,保持变量处理等逻辑的正确等。

11、模型监控

模型建模的主要目的为了防止模型钝化;监测与报告,关注和定期检验模型的区分能力与预测能力的变化及模型稳定性的变化,在出现模型可能不能满足业务需求的情况时,反馈至模型开发团队,及时进行模型更新或重新开发。模型监控与模型效果评测一样,也是从两个方面去监控,一是有效性,主要看过件样本在后续的逾期表现;二是稳定性,同样是变量稳定性和模型稳定性,评测的方式与模型效果评价部分类似。

机器学习项目模板(R语言)

# 1. Prepare Problem 问题准备
# a) Load libraries 加载所需R包
# b) Load dataset 加载所需数据集
# c) Split-out validation dataset 数据集划分

# 2. Summarize Data 数据概要
# a) Descriptive statistics 描述性统计分析
# b) Data visualizations 数据可视化

# 3. Prepare Data  数据准备
# a) Data Cleaning 数据清洗
# b) Feature Selection 特征选择
# c) Data Transforms 数据变换

# 4. Evaluate Algorithms 算法评测
# a) Test options and evaluation metric 测试集和评价指标
# b) Spot Check Algorithms 测试算法
# c) Compare Algorithms 算法对比分析

# 5. Improve Accuracy 性能优化
# a) Algorithm Tuning 调参
# b) Ensembles 集成

# 6. Finalize Model 模型应用
# a) Predictions on validation dataset 模型预测
# b) Create standalone model on entire training dataset 全数据集构建模型
# c) Save model for later use 模型保存和实施
# 乳腺癌识别问题

# 二分类问题

# 问题描述: https://archive.ics.uci.edu/ml/datasets/Breast+Cancer+Wisconsin+(Original)
# World-Class Results: http://www.is.umk.pl/projects/datasets.html#Wisconsin

# 加载R包
library(mlbench)
library(caret)
library(doMC)
registerDoMC(cores=8)

# 加载数据集
data(BreastCancer)

# 数据集划分
set.seed(7)
validation_index <- createDataPartition(BreastCancer$Class, p=0.80, list=FALSE)
# select 20% of the data for validation
validation <- BreastCancer[-validation_index,]
# use the remaining 80% of data to training and testing the models
dataset <- BreastCancer[validation_index,]


# 数据概要

# 数据集样本数和变量数
dim(dataset)

# 数据集检视
head(dataset, n=20)

# 数据集变量类型
sapply(dataset, class)

# 移除ID变量
dataset <- dataset[,-1]
# 变量类型转换
for(i in 1:9) {
    dataset[,i] <- as.numeric(as.character(dataset[,i]))
}

# 数据摘要
summary(dataset)

# 类别变量分布
cbind(freq=table(dataset$Class), percentage=prop.table(table(dataset$Class))*100)

# 变量集之间的相关性
complete_cases <- complete.cases(dataset)
cor(dataset[complete_cases,1:9])

# 变量集直方图
par(mfrow=c(3,3))
for(i in 1:9) {
    hist(dataset[,i], main=names(dataset)[i])
}

# 变量集核密度图
par(mfrow=c(3,3))
complete_cases <- complete.cases(dataset)
for(i in 1:9) {
    plot(density(dataset[complete_cases,i]), main=names(dataset)[i])
}

# 变量集盒箱图
par(mfrow=c(3,3))
for(i in 1:9) {
    boxplot(dataset[,i], main=names(dataset)[i])
}

# 散点图矩阵
jittered_x <- sapply(dataset[,1:9], jitter)
pairs(jittered_x, names(dataset[,1:9]), col=dataset$Class)

# 基于类别的变量集盒箱图
par(mfrow=c(3,3))
for(i in 1:9) {
    barplot(table(dataset$Class,dataset[,i]), main=names(dataset)[i], legend.text=unique(dataset$Class))
}



# 算法评测

# 重复3次的10折交叉验证
control <- trainControl(method="repeatedcv", number=10, repeats=3)
metric <- "Accuracy"
# LG
set.seed(7)
fit.glm <- train(Class~., data=dataset, method="glm", metric=metric, trControl=control)
# LDA
set.seed(7)
fit.lda <- train(Class~., data=dataset, method="lda", metric=metric, trControl=control)
# GLMNET
set.seed(7)
fit.glmnet <- train(Class~., data=dataset, method="glmnet", metric=metric, trControl=control)
# KNN
set.seed(7)
fit.knn <- train(Class~., data=dataset, method="knn", metric=metric, trControl=control)
# CART
set.seed(7)
fit.cart <- train(Class~., data=dataset, method="rpart", metric=metric, trControl=control)
# Naive Bayes
set.seed(7)
fit.nb <- train(Class~., data=dataset, method="nb", metric=metric, trControl=control)
# SVM
set.seed(7)
fit.svm <- train(Class~., data=dataset, method="svmRadial", metric=metric, trControl=control)
# Compare algorithms
results <- resamples(list(LG=fit.glm, LDA=fit.lda, GLMNET=fit.glmnet, KNN=fit.knn, CART=fit.cart, NB=fit.nb, SVM=fit.svm))
summary(results)
dotplot(results)


# Evaluate Algorithms Transform

# 10-fold cross validation with 3 repeats
control <- trainControl(method="repeatedcv", number=10, repeats=3)
metric <- "Accuracy"
# LG
set.seed(7)
fit.glm <- train(Class~., data=dataset, method="glm", metric=metric, preProc=c("BoxCox"), trControl=control)
# LDA
set.seed(7)
fit.lda <- train(Class~., data=dataset, method="lda", metric=metric, preProc=c("BoxCox"), trControl=control)
# GLMNET
set.seed(7)
fit.glmnet <- train(Class~., data=dataset, method="glmnet", metric=metric, preProc=c("BoxCox"), trControl=control)
# KNN
set.seed(7)
fit.knn <- train(Class~., data=dataset, method="knn", metric=metric, preProc=c("BoxCox"), trControl=control)
# CART
set.seed(7)
fit.cart <- train(Class~., data=dataset, method="rpart", metric=metric, preProc=c("BoxCox"), trControl=control)
# Naive Bayes
set.seed(7)
fit.nb <- train(Class~., data=dataset, method="nb", metric=metric, preProc=c("BoxCox"), trControl=control)
# SVM
set.seed(7)
fit.svm <- train(Class~., data=dataset, method="svmRadial", metric=metric, preProc=c("BoxCox"), trControl=control)
# Compare algorithms
transform_results <- resamples(list(LG=fit.glm, LDA=fit.lda, GLMNET=fit.glmnet, KNN=fit.knn, CART=fit.cart, NB=fit.nb, SVM=fit.svm))
summary(transform_results)
dotplot(transform_results)



# 性能优化
# 调参
# Tune SVM

# 10-fold cross validation with 3 repeats
control <- trainControl(method="repeatedcv", number=10, repeats=3)
metric <- "Accuracy"
set.seed(7)
grid <- expand.grid(.sigma=c(0.025, 0.05, 0.1, 0.15), .C=seq(1, 10, by=1))
fit.svm <- train(Class~., data=dataset, method="svmRadial", metric=metric, tuneGrid=grid, preProc=c("BoxCox"), trControl=control)
print(fit.svm)
plot(fit.svm)


# Tune kNN

# 10-fold cross validation with 3 repeats
control <- trainControl(method="repeatedcv", number=10, repeats=3)
metric <- "Accuracy"
set.seed(7)
grid <- expand.grid(.k=seq(1,20,by=1))
fit.knn <- train(Class~., data=dataset, method="knn", metric=metric, tuneGrid=grid, preProc=c("BoxCox"), trControl=control)
print(fit.knn)
plot(fit.knn)


# 集成
# Ensembles: Boosting and Bagging


# 10-fold cross validation with 3 repeats
control <- trainControl(method="repeatedcv", number=10, repeats=3)
metric <- "Accuracy"
# Bagged CART
set.seed(7)
fit.treebag <- train(Class~., data=dataset, method="treebag", metric=metric, trControl=control)
# Random Forest
set.seed(7)
fit.rf <- train(Class~., data=dataset, method="rf", metric=metric, preProc=c("BoxCox"), trControl=control)
# Stochastic Gradient Boosting
set.seed(7)
fit.gbm <- train(Class~., data=dataset, method="gbm", metric=metric, preProc=c("BoxCox"), trControl=control, verbose=FALSE)
# C5.0
set.seed(7)
fit.c50 <- train(Class~., data=dataset, method="C5.0", metric=metric, preProc=c("BoxCox"), trControl=control)
# Compare results
ensemble_results <- resamples(list(BAG=fit.treebag, RF=fit.rf, GBM=fit.gbm, C50=fit.c50))
summary(ensemble_results)
dotplot(ensemble_results)



# 模型应用

# prepare parameters for data transform
set.seed(7)
dataset_nomissing <- dataset[complete.cases(dataset),]
x <- dataset_nomissing[,1:9]
preprocessParams <- preProcess(x, method=c("BoxCox"))
x <- predict(preprocessParams, x)

# prepare the validation dataset
set.seed(7)
# remove id column
validation <- validation[,-1]
# remove missing values (not allowed in this implementation of knn)
validation <- validation[complete.cases(validation),]
# convert to numeric
for(i in 1:9) {
    validation[,i] <- as.numeric(as.character(validation[,i]))
}
# transform the validation dataset
validation_x <- predict(preprocessParams, validation[,1:9])

# make predictions
set.seed(7)
predictions <- knn3Train(x, validation_x, dataset_nomissing$Class, k=9, prob=FALSE)
confusionMatrix(predictions, validation$Class)

参考文章1:项目|机器学习项目模板(R语言)

学习文章:数据分析实例:员工流失建模与预测

你可能感兴趣的:(信用模型)