楼主: ada89k
89983 10

[学习分享] Gini指数:利用Gini指数变量最优分类 [推广有奖]

  • 3关注
  • 70粉丝

管理员

院士

93%

还不是VIP/贵宾

-

威望
2
论坛币
1082293 个
通用积分
3.7466
学术水平
123 点
热心指数
149 点
信用等级
82 点
经验
45875 点
帖子
1640
精华
3
在线时间
2237 小时
注册时间
2017-2-7
最后登录
2019-9-17

ada89k 在职认证  发表于 2017-8-26 17:25:40 |显示全部楼层

Gini指数:利用Gini指数变量最优分类



介绍基本的思想:
       由于gini指数是衡量数据的不纯度,gini指数越大则表示数据越不纯,gini越小表示数据相对越纯。所有我们就需要在我们在确定切分点分类时候需保证在这个切分点时需要比在其他点切分时候gini指数小,那么则表示在这个切分点切分是最优的。

步骤:
   1、计算切分前的整体gini指数;
   2、遍历所有潜在切分点,分别计算切分后的gini指数,选取切分后gini指数最小的切分点;
   3、分别对第一次切分后的类重复上述1、2步骤直至达到我们想要的类别。

OK!直接贴上代码。

/*分类变量基于gini系数变量最优粗分类*/
options mlogic mprint symbolgen;
%macrogini_fz(indata=,var=,tar_var=,outdata=,g_value=);
libname data "/folders/myfolders/data/";
data temp;
    set &indata.;
run;
%local m n;
proc sql noprint;
    select max(&var.) into: m from temp;/*取分组变量的最大值*/
    select min(&var.) into: n from temp;/*取分组变量的最小值*/
    select count(&var.) into:total from temp;/*取总体数量*/
   
    %do a = &n. %to &m.;
    select sum(n_b) into:T_&a._1 from temp where &var.=&a.;/*违约客户的数量*/
    select sum(n_g) into: T_&a._0 from temp where &var.=&a.;/*非违约客户的数量*/
    select sum(total) into:T_&a._s from temp where &var.=&a.;/*该分组下的违约和非违约客户的的总数量*/
    select sum(n_b) into:T_1 from temp;/*总体中违约客户的数量*/
    select sum(n_g) into:T_0 from temp;/*总体中非违约客户的数量*/
    ;
    %end;
quit;
%put &m. &n. &total. &T_1.&T_0.;
/*分别计算每组中的样本占比*/
%do a=&n. %to &m.;
   %local g_&a.;
   %let g_&a.=0;
   
   %do b=0 %to 1;
       %letg_&a.=%sysevalf(&&g_&a.+&&T_&a._&b.*&&T_&a._&b.);
   %end;
   
   %letg_&a.=%sysevalf(1-&&g_&a./(&&T_&a._s*&&T_&a._s));
%end;
/*计算总体中的占比*/
%local g;
%let g=0;
%do b=0 %to 1;
    %let g=%sysevalf(&&g.+&&T_&b.*&&T_&b.);
%end;
%letg=%sysevalf(1-&&g./(&&total.*&&total.));
%put &g.;
/*计算各分组下的gini系数*/
%local g_k;
%let g_k=0;
%do a=&n. %to &m.;
    %letg_k=%sysevalf(&&g_k.+&&T_&a._s*&&g_&a./&&total.);
%end;
%letg_value=%sysevalf(1-&&g_k./&&g.);
%put &g_value.;
/*生成数据集*/
data &outdata.;
       %doa=&n. %to &m.;
           fenzu=&a.;
           bad=&&T_&a._1;
           good=&&T_&a._0;
           g_b_total=&&T_&a._s;
           g=&&g_&a.;
           g_total=&g_k.;
           output;
       %end;
run;
proc sort data=&outdata. ; bydescending g;run; /*按照每个分组的gini系数降序排列*/
%mend;
/*%gini_fz(indata=data.xinyong,var=address,tar_var=default,outdata=g_out,g_value=);*/
   
/*基于gini系数对变量进行粗分类*/
%macrogini_c(indata=,var=,tar_var=,b_max=,out_data=);
data temp_a;
    set &indata.;
run;
proc freq data=temp_a;/*统计变量下目标变量的频数*/
    table &var.*&tar_var. /out=ss_1(drop=percent) norow nopercent;
    table &var. /out=ss_2(drop=percent) norow nopercent;
    ;
run;
proc sort data=ss_1 ;by &var. ;run;
proc sort data=ss_2 ;by &var. ;run;
data temp_b;
    merge ss_1(in=a rename=(count=n_b))
          ss_2(in=b rename=(count=total))
          ;
    by &var.;
    if a;
run;
data temp_b;
    set temp_b;
    if &tar_var.=0 then delete;
    n_g=total-n_b;/*好客户的数量*/
    b_pct=n_b/total;/*坏客户在本组下的占比*/
    bin=1;/*初始化_全部都为一组*/
run;
proc sort data=temp_b;by bin b_pct;run;/*按照分组、坏客户占比升序排列*/
data temp_b;
    set temp_b;
    i=_N_;
run;
/**********************************START_确定分组的最优分类过程*************************************************/
%do k = 1 %to %eval(&b_max.-1);
proc sql noprint;
    select max(bin) into:bin from temp_b;
quit;
%put &bin.;
%do i=1 %to &bin.;
       procsql noprint;
            select count(*) into:num_&i. fromtemp_b where bin=&i.;
            create table temp_b_&i. as select *from temp_b where bin=&i.;
       quit;
       %put&&num_&i..;
%end;
proc sql noprint;
   create table temp_b_value(BinToSplit num, DatasetName char(80), Valuenum)
    ;
quit;
%do i=1 %to &bin.;
   %if &&num_&i.>1 %then %do;
   
   proc sql noprint;
        select count(*) into:nb from temp_b_&i. where bin=&i.;
   quit;
   
   %let best_value=0;
   %let best_i=1;
   
   %do m=1 %to %eval(&nb.-1);
   %let value=0;
       procsql noprint;
            select sum(n_b) into:n_b_1 fromtemp_b_&i. where i<=&m.;
            select sum(n_b) into:n_b_2 fromtemp_b_&i. where i>&m.;
            select sum(n_g) into:n_g_1 fromtemp_b_&i. where i<=&m.;
            select sum(n_g) into:n_g_2 fromtemp_b_&i. where i>&m.;
            select sum(total) into:n_t_1 fromtemp_b_&i. where i<=&m.;
            select sum(total) into:n_t_2 fromtemp_b_&i. where i>&m.;
            select sum(n_b) into:n_b_t fromtemp_b_&i. ;
            select sum(n_g) into:n_g_t fromtemp_b_&i. ;
            select sum(total) into:n_t fromtemp_b_&i. ;
       quit;
      
       %localg_1 g_2 g g_t g_z;
       %letg_1=%sysevalf(1-(&n_b_1.*&n_b_1.+&n_g_1.*&n_g_1.)/(&n_t_1.*&n_t_1.));
       %letg_2=%sysevalf(1-(&n_b_2.*&n_b_2.+&n_g_2.*&n_g_2.)/(&n_t_2.*&n_t_2.));
       %letg=%sysevalf(1-(&n_b_t.*&n_b_t.+&n_g_t.*&n_g_t.)/(&n_t.*&n_t.));/*为分组前的总体gini系数*/
       %letg_t=%sysevalf(&n_t_1.*&g_1./&n_t.+&n_t_2.*&g_2./&n_t.);/*分组后的gini系数*/
       %letg_z=%sysevalf(1-&g_t./&g.);/*将分组前和分组后的gini系数进行比较,并赋值与g_z*/
       %letvalue=&g_z.;
       %put&g_1. &g_2. &g. &g_t. &g_z. &value.;      
   
   %if %sysevalf(&best_value.<&value.) %then %do;/*根据gini系数,此处选取规则需要选取分组后gini系数更小的(意味着分组后纯度更高了)*/
       %let best_value=&value.;
       %let best_i=&m.;
   %end;
   %end;
   
   data temp_b_&i.;/*根据遍历的最小的value确定切分点和分组*/
        set temp_b_&i.;
        if i<=&best_i. then split=1;
        else split=0;
        drop i;
   run;
   proc sort data=temp_b_&i. ;by split b_pct;run;
   
   data temp_b_try&i.;/*将预计切分的数据拿出来*/
        set temp_b_&i.;
        if split=1 then bin=%eval(&bin.+1);
   run;
   data temp_b_in&i.;
        set temp_b;
        if bin=&i. then delete;
   run;
   data temp_b_in&i.;/*将预计切分的数据集与之前未拆分的部分合并为最新的数据集*/
        set temp_b_in&i.
            temp_b_try&i.
        ;
   run;
   %gini_fz(indata=temp_b_in&i.,var=bin,tar_var=default,outdata=g_out,g_value=value);
   
   proc sql noprint;
        insert into temp_b_valuevalues(&i.,"temp_b_in&i.",&value.);
   quit;
   
   %end;
%end;
proc sort data=temp_b_value;by descendingvalue;run;/*选取各组切分后gini指数最小的切分点,也即value值最大的*/
data _null_;
    set temp_b_value;
    if _N_=1 then call symput ("n",compress(BinToSplit));
run;
%put &n.;
data temp_b;
    set temp_b_in&n.;
    drop i;
run;
proc sort data=temp_b ;by bin b_pct;run;
data temp_b;/*重新再每个bin组定义i变量值,以便于下次循环切分*/
    set temp_b;
    retain i 0;
    by bin b_pct;
    if first.bin then i=1;
    else i=i+1;
run;
%end;
data temp_final;
    set temp_b;
run;
data &out_data.;
    retain &var. n_b n_g total bin ;
    set temp_final;
    keep &var. n_b n_g total bin ;
    label &var.="原分组" n_b="违约客户量" n_g="正常客户量" total="总客户量" bin="新分组";
run;
proc sort data=&out_data ; by bin ;run;
/**********************************END_确定分组的最优分类过程*************************************************/
proc datasets lib=work ;/*仅保留输出数据集*/
    save &out_data.;
run;
%mend;
%gini_c(indata=data.xinyong,var=employ,tar_var=default,b_max=4,out_data=g_best_out);

%gini_c宏中indata为输入数据集;
                    var为需分类的变量;
                    tar_var为目标变量;
                    b_max为想分为多少类;
                    outdata为输出数据集.
%gini_fz宏中indata为输入数据集;
                     var为需分类的变量;
                     tar_var为目标变量;
                     outdata为输出数据集;
                     g_value输出g_value.

贴上输出的结果图:
       结果是对employ变量的30多个组进行最优分类,最后分为4类的最优分类的结果在bin列。当然这里也可以自定义分为3类、5类、6类等等,都可以相应的输出相应的最优分类。
PS:n_b为每组对应的坏客户的数量、n_g对应的好客户的数量、total是改组客户数量总和。

QQ图片20170826170140.png

QQ图片20170826170311.png



已有 1 人评分经验 收起 理由
kongqingbao280 + 20 精彩帖子

总评分: 经验 + 20   查看全部评分

stata SPSS
西门高 发表于 2017-8-26 17:34:57 |显示全部楼层
谢谢分享
回复

使用道具 举报

陈信研究员 发表于 2017-8-26 18:20:32 |显示全部楼层
谢谢楼主分享,请问这个代码是在那个软件里运行啊,谢谢
回复

使用道具 举报

ada89k 在职认证  发表于 2017-8-26 18:27:37 |显示全部楼层
陈信研究员 发表于 2017-8-26 18:20
谢谢楼主分享,请问这个代码是在那个软件里运行啊,谢谢
SAS
回复

使用道具 举报

陈信研究员 发表于 2017-8-26 18:40:47 |显示全部楼层
ada89k 发表于 2017-8-26 18:27
SAS
好的,谢谢
回复

使用道具 举报

钱学森64 发表于 2017-8-26 19:41:08 |显示全部楼层
谢谢分享
回复

使用道具 举报

clb_polaris 发表于 2017-8-26 23:34:18 |显示全部楼层
谢谢分享
回复

使用道具 举报

风起天 在职认证  发表于 2017-8-27 15:12:22 |显示全部楼层
谢谢分享Gini指数变量最优分类
回复

使用道具 举报

cc110120 发表于 2017-9-16 14:01:37 |显示全部楼层
表示想看十万个冷笑话2怎么进来这里的?
回复

使用道具 举报

linzhjbtx 发表于 2018-10-24 17:02:40 |显示全部楼层
这里的gini指数和SAS EM里交互式变量分箱的gini指数是一样的吗?
所以SAS EM里面的gini指数是越小越好?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 我要注册

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2019-9-22 14:50