R语言实现KS

将代码封装在函数PlotKS_N里,Pred_Var是预测结果,可以是评分或概率形式;labels_Var是好坏标签,取值为1或0,1代表坏客户,0代表好客户;descending用于控制数据按违约概率降序排列,如果Pred_Var是评分,则descending=0,如果Pred_Var是概率形式,则descending=1;N表示在将数据按风险降序排列后,等分N份后计算KS值。

PlotKS_N函数返回的结果为一列表,列表中的元素依次为KS最大值、KS取最大值的人数百分位置、KS曲线对象、KS数据框。

代码如下:

PlotKS_N<-function(Pred_Var, labels_Var, descending, N){
  # Pred_Var is prop: descending=1
  # Pred_Var is score: descending=0
  library(dplyr)
  
  df<- data.frame(Pred=Pred_Var, labels=labels_Var)
  
  if (descending==1){
    df1<-arrange(df, desc(Pred), labels)
  }else if (descending==0){
    df1<-arrange(df, Pred, labels)
  }
  
  df1$good1<-ifelse(df1$labels==0,1,0)
  df1$bad1<-ifelse(df1$labels==1,1,0)
  df1$cum_good1<-cumsum(df1$good1)
  df1$cum_bad1<-cumsum(df1$bad1)
  df1$rate_good1<-df1$cum_good1/sum(df1$good1)
  df1$rate_bad1<-df1$cum_bad1/sum(df1$bad1)
  
  if (descending==1){
    df2<-arrange(df, desc(Pred), desc(labels))
  }else if (descending==0){
    df2<-arrange(df, Pred, desc(labels))
  }
  
  df2$good2<-ifelse(df2$labels==0,1,0)
  df2$bad2<-ifelse(df2$labels==1,1,0)
  df2$cum_good2<-cumsum(df2$good2)
  df2$cum_bad2<-cumsum(df2$bad2)
  df2$rate_good2<-df2$cum_good2/sum(df2$good2)
  df2$rate_bad2<-df2$cum_bad2/sum(df2$bad2)
  
  rate_good<-(df1$rate_good1+df2$rate_good2)/2
  rate_bad<-(df1$rate_bad1+df2$rate_bad2)/2
  df_ks<-data.frame(rate_good,rate_bad)
  
  df_ks$KS<-df_ks$rate_bad-df_ks$rate_good
  
  L<- nrow(df_ks)
  if (N>L) N<- L
  df_ks$tile<- 1:L
  qus<- quantile(1:L, probs = seq(0,1, 1/N))[-1]
  qus<- ceiling(qus)
  df_ks<- df_ks[df_ks$tile%in%qus,]
  df_ks$tile<- df_ks$tile/L
  df_0<-data.frame(rate_good=0,rate_bad=0,KS=0,tile=0)
  df_ks<-rbind(df_0, df_ks)
  
  M_KS<-max(df_ks$KS)
  Pop<-df_ks$tile[which(df_ks$KS==M_KS)]
  M_good<-df_ks$rate_good[which(df_ks$KS==M_KS)]
  M_bad<-df_ks$rate_bad[which(df_ks$KS==M_KS)]
  
  library(ggplot2)
  PlotKS<-ggplot(df_ks)+
    geom_line(aes(tile,rate_bad),colour="red2",size=1.2)+
    geom_line(aes(tile,rate_good),colour="blue3",size=1.2)+
    geom_line(aes(tile,KS),colour="forestgreen",size=1.2)+
    
    geom_vline(xintercept=Pop,linetype=2,colour="gray",size=0.6)+
    geom_hline(yintercept=M_KS,linetype=2,colour="forestgreen",size=0.6)+
    geom_hline(yintercept=M_good,linetype=2,colour="blue3",size=0.6)+
    geom_hline(yintercept=M_bad,linetype=2,colour="red2",size=0.6)+
    
    annotate("text", x = 0.5, y = 1.05, label=paste("KS=", round(M_KS, 4), "at Pop=", round(Pop, 4)), size=4, alpha=0.8)+
    
    scale_x_continuous(breaks=seq(0,1,.2))+
    scale_y_continuous(breaks=seq(0,1,.2))+
    
    xlab("of Total Population")+
    ylab("of Total Bad/Good")+
    
    ggtitle(label="KS - Chart")+
    
    theme_bw()+
    
    theme(
      plot.title=element_text(colour="gray24",size=12,face="bold"),
      plot.background = element_rect(fill = "gray90"),
      axis.title=element_text(size=10),
      axis.text=element_text(colour="gray35")
    )
  
  result<-list(M_KS=M_KS,Pop=Pop,PlotKS=PlotKS,df_ks=df_ks)
  return(result)
}

接下面以实际数据为例查看该函数的运行结果。

pred_train是建模得到的预测结果,这里是概率形式:

> pred_train
[1] 0.40418112 0.35814193 0.45220572 0.53482002 0.12923573 ...

labels_train是好坏标签:

> labels_train
[1] 0 0 0 0 0 ...

函数运行的结果存放在列表train_ks里:

train_ks <- PlotKS_N(pred_train, labels_train, 1, 100)

接下来查看train_ks中的每一元素:

1)KS最大值

> train_ks$M_KS
[1] 0.4492765

2)KS取最大值的人数百分位置

> train_ks$Pop
[1] 0.3803191

3)KS曲线对象

> train_ks$PlotKS

4)KS数据框,tile为人数百分位置,rate_good好客户累计百分比,rate_bad坏客户l累计百分比,KS=rate_bad-rate_good

> train_ks$df_ks
rate_good  rate_bad   KS      tile
0.000000000 0.00000000 0.00000000 0.00000000
0.001307190 0.04233302 0.04102583 0.01022913
0.003660131 0.07996237 0.07630224 0.02025368
0.008104575 0.11006585 0.10196128 0.03027823
0.011764706 0.14299153 0.13122683 0.04030278
0.015686275 0.17497648 0.15929021 0.05032733
0.020653595 0.20319849 0.18254490 0.06035188
0.024836601 0.23424271 0.20940611 0.07037643
0.029542484 0.26246472 0.23292224 0.08019640
0.035294118 0.28786453 0.25257042 0.09022095
0.040784314 0.31420508 0.27342077 0.10024550
......

本文分享自微信公众号 - 大数据建模的一点一滴(bigdatamodeling)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python实现KS

    Python和R有很多相似处,本篇KS实现就是将上篇R语言方法转成Python,代码封装在函数PlotKS里,函数的逻辑可以参考上篇R语言的实现。

    小石头
  • 模型预测概率的修正

    在很多场景中,我们只对模型的排序性能感兴趣,不太关注其预测概率,因为只要模型的排序性能没有下降,根据排序性设置一定的阈值就能够满足业务的需要。而模型预测概率的...

    小石头
  • 特征工程 | PCA降维

    主成分分析(PCA)是一种多元统计方法,主要利用降维的思想,在损失很少信息的前提下,把多个变量转化为少数几个互不相关的综合变量,各综合变量即称为主成...

    小石头
  • pygame-游戏开发学习笔记(五)–pygame.Font,字体与中文以及错误检测的问题

    本节内容基本属于干货,代码在github上:包括了字体和图片文件可以直接拉下来测试https://github.com/luyishisi/The_crawle...

    十四君
  • 程序员的十年工作创业血泪史,万字长文,仔细读完,受益匪浅

    吉日噶拉(在外企、上市公司工作过,自己也创业失败过,遇到过很多失败挫折,甚至露宿街头,但是最后还是挺过来了),是一个十几年的程序员了,本文介绍了他的相关经历,以...

    技术zhai
  • 一个十几年程序员给所有新老程序员的忠告

    吉日噶拉(在外企、上市公司工作过,自己也创业失败过,遇到过很多失败挫折,甚至露宿街头,但是最后还是挺过来了),是一个十几年的程序员了,里面介绍了他的相关经历,以...

    AWeiLoveAndroid
  • 程序员的十年工作创业血泪史,万字长文,仔细读完,受益匪浅

    本文所书写的内容,无论是对刚入门的程序员,还是工作了十年八年的程序员都有一些经验值得借鉴学习。

    技术zhai
  • 程序员(工作十几年)的创业血泪史,万字长文,与君共勉!

    他是一个十几年的程序员了,在外企、上市公司工作过,自己也创业失败过,遇到过很多失败挫折,甚至露宿街头,但是最后还是挺过来了,本文介绍了他的相关经历,以及他的一些...

    Java架构技术
  • Apache Shiro Hello World

    Shiro 一个Apache 权限处理框架,现在更流行于security,能够指定用户的具体操作哪一个按钮,搭配接口,通过注解实现。

    疯狂的KK
  • 揭秘47万微信群和2亿微信用户背后的数字规律

    微信群已经进入到我们的日常生活中,成为社交关系的主要纽带。但微信群有自己的规律,长期群能存活很长的时间,临时群则转瞬即逝。来自清华大学、康奈尔大学、腾讯公司和香...

    华章科技

扫码关注云+社区

领取腾讯云代金券