关于gini指数(二):利用gini指数变量最优分类
关键词:gini指数、决策树 gini指数、gini基尼指数 决策树
上一篇《关于gini指数(一)》介绍了gini指数的定义和基本计算方法。
本篇分享利用gini指数来确定变量的最优分类,即通过gini指数来确定如何来切分类别变量,将众多的类别降为我们想要的较少的大类别。
介绍基本的思想:
由于gini指数是衡量数据的不纯度,gini指数越大则表示数据越不纯,gini越小表示数据相对越纯。所有我们就需要在我们在确定切分点分类时候需保证在这个切分点时需要比在其他点切分时候gini指数小,那么则表示在这个切分点切分是最优的。
步骤:
1、计算切分前的整体gini指数;
2、遍历所有潜在切分点,分别计算切分后的gini指数,选取切分后gini指数最小的切分点;
3、分别对第一次切分后的类重复上述1、2步骤直至达到我们想要的类别。
OK!直接贴上代码。
/*分类变量基于gini系数变量最优粗分类*/
options mlogic mprint symbolgen;
%macro gini_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;
%let g_&a.=%sysevalf(&&g_&a.+&&T_&a._&b.*&&T_&a._&b.);
%end;
%let g_&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;
%let g=%sysevalf(1-&&g./(&&total.*&&total.));
%put &g.;
/*计算各分组下的gini系数*/
%local g_k;
%let g_k=0;
%do a=&n. %to &m.;
%let g_k=%sysevalf(&&g_k.+&&T_&a._s*&&g_&a./&&total.);
%end;
%let g_value=%sysevalf(1-&&g_k./&&g.);
%put &g_value.;
/*生成数据集*/
data &outdata.;
%do a=&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. ; by descending g;run; /*按照每个分组的gini系数降序排列*/
%mend;
/* %gini_fz(indata=data.xinyong,var=address,tar_var=default,outdata=g_out,g_value=); */
/*基于gini系数对变量进行粗分类*/
%macro gini_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.;
proc sql noprint;
select count(*) into:num_&i. from temp_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), Value num)
;
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;
proc sql noprint;
select sum(n_b) into:n_b_1 from temp_b_&i. where i<=&m.;
select sum(n_b) into:n_b_2 from temp_b_&i. where i>&m.;
select sum(n_g) into:n_g_1 from temp_b_&i. where i<=&m.;
select sum(n_g) into:n_g_2 from temp_b_&i. where i>&m.;
select sum(total) into:n_t_1 from temp_b_&i. where i<=&m.;
select sum(total) into:n_t_2 from temp_b_&i. where i>&m.;
select sum(n_b) into:n_b_t from temp_b_&i. ;
select sum(n_g) into:n_g_t from temp_b_&i. ;
select sum(total) into:n_t from temp_b_&i. ;
quit;
%local g_1 g_2 g g_t g_z;
%let g_1=%sysevalf(1-(&n_b_1.*&n_b_1.+&n_g_1.*&n_g_1.)/(&n_t_1.*&n_t_1.));
%let g_2=%sysevalf(1-(&n_b_2.*&n_b_2.+&n_g_2.*&n_g_2.)/(&n_t_2.*&n_t_2.));
%let g=%sysevalf(1-(&n_b_t.*&n_b_t.+&n_g_t.*&n_g_t.)/(&n_t.*&n_t.));/*为分组前的总体gini系数*/
%let g_t=%sysevalf(&n_t_1.*&g_1./&n_t.+&n_t_2.*&g_2./&n_t.);/*分组后的gini系数*/
%let g_z=%sysevalf(1-&g_t./&g.);/*将分组前和分组后的gini系数进行比较,并赋值与g_z*/
%let value=&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_value values(&i.,”temp_b_in&i.”,&value.);
quit;
%end;
%end;
proc sort data=temp_b_value;by descending value;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是改组客户数量总和。
转载请注明:数据分析 » 关于gini指数(二):利用gini指数变量最优分类