今天的文章的使用场景是,是因为我很热衷处理那种别人不喜欢整理的各种流水数据,例如运营商通话流水啊,银行卡流水啊,信用卡流水等等,那么这些数据做衍生变量有个经常会碰到的问题,就是像这种“最近一天的通话次数”有可能跟“最近三天的通话次数”这种相关性很强,但是在拟合的之后,这种相关性强的只能进一个,不然共线性就来找你啦,所以这时候你要处理是:1、你要让那个变量进去。2、那些变量是一类的,他们共线性在一起很强。
你跟我说,这谁不会啊,这不就是vif嘛,一看我就知道那几个相关性高了,是的,我们经常会有vif,但是模型做多了,你会发现,vif无论要多方便,但是有时候vif过了,但是还是存在共线性,所以你这时候还是要去看相关矩阵。所以vif并不会万能,我今天也不是要说相关矩阵,我今天要说的是sas的一个过程步叫做“proc varclus”,看着是不是很像聚类的那个过程步,是这个这个是变量的聚类,将相关性强的变量聚在一起,这里我不展开细讲,我给你链接,你自己去看,我今天不是来介绍这个过程的,我是来给代码~~
链接在这里:http://blog.sina.com.cn/s/blog_5d3b177c0100equm.html
https://wenku.baidu.com/view/7c4929f34693daef5ef73de1.html。
这是思路
代码主要实现其实就是对变量降维,而且是降维后,给你提取同类变量中那个最好的。代码的思路是这样子的:
1、 输入一批数值变量,现在的代码只能实现数值变量的。我建议两百以内,你想要一千,我绝不拦你。
2、 使用proc varclus过程将变量聚类,控制群的数目
Minclusters(minc)=正整数:指定最少要有几个群。
Maxclusters(maxc)=正整数:指定最多有几个群。
Proportion(percent)=正有理数:群主成份所能解释的变异数百分比。注意,这里proportion=0.75与percent=75是一样的。
Maxeigen=实数:规定每个群内第二特征值的最大可能值。
请自行选择,本人最常使用第二特征根。
3、 每一簇的变量都去跑一遍iv,再结合变量聚类结果指标和业务进行变量筛选。
挑选变量的原则如下:
选择IV值最大的变量
选择1-R平方最小的变量
选择业务解释性好的变量。
4、 选择取出这一簇里面,iv最高的或者1-R方最小的。
5、 我知道你会说,但是我想看下其他变量的怎么样,我也给你保留了!
代码:
%macro varclus(DSin=,target=,Maxclusters=,group=,method=,DSout=);
*method=1每组取iv最大;method=2每组取1-R方最小;
%let lib=%upcase(%scan(&DSin.,1,'.'));
%let dname=%upcase(%scan(&DSin.,2,'.'));
proc sql noprint;
select name into:name_list SEPARATED by " "
from sashelp.VCOLUMN
where left(libname)="&lib." and left(memname)="&dname." and lowcase(name)^=lowcase("user_id.") and lowcase(name)^=lowcase("&target") ;
quit;
%put &name_list.;
ods listing close;
ods output clusterquality=summary
rsquare=clusters;
proc varclus data=&DSin.
Minclusters=2
Maxclusters=&Maxclusters.
percent=75
Maxeigen=7
outtree=fortree
short;
var &name_list.;
run;
ods listing;
data _null_;
set summary;
call symput('nvar',compress(NumberOfClusters));
run;
data clusters_&nvar;
set clusters;
where NumberOfClusters=&nvar;
run;
data var_select;
set clusters_&nvar;
retain Cluster1;
if Cluster~="" then Cluster1=Cluster;
run;
data _null_;
set var_select;
call symputx(compress("varname"||_n_),compress(Variable));
call symputx(compress("n"),compress(_n_));
run;
data total_result;
length varname$30.;
length group_id 8.;
length new_min 8.;
length new_max 8.;
length interval$30.;
length group_num 8.;
length bad_num 8.;
length good_num 8.;
length good_rate 8.;
length bad_rate 8.;
length woe 8.;
length iv 8.;
run;
%do i=1 %to &n.;
%put &&varname&n.;
proc rank data=&DSin.(keep =&&varname&i. &target.) out = tmp ties = low groups = &group.;
var &&varname&i.;
ranks new_var;
run;
proc sql noprint;
create table result1 as
select distinct
"&&varname&i." as varname,
new_var,
min(&&varname&i.) as min,
max(&&varname&i.) as max,
case when new_var^=. then compress(put(min(&&varname&i.),8.)||"-"||put(max(&&varname&i.),8.)) else "null " end as interval,
count(*) as group_num,
sum(&target.) as bad_num,
count(*)-sum(&target.) as good_num
from tmp
group by new_var;
quit;
proc sql noprint;
select count(*)into:good_total from tmp(where=(&target.=0));
select count(*)into:bad_total from tmp(where=(&target.=1));
create table result2 as
select
varname,
case when new_var=. then 0 else new_var end as group_id,
case when min=min(min) then . else min end as new_min,
case when max=max(max) then . else max end as new_max,
interval,group_num,bad_num,good_num,
good_num/&good_total. as good_rate,
bad_num/&bad_total. as bad_rate,
log((bad_num/&bad_total.)/(good_num/&good_total.)) as woe,
log((bad_num/&bad_total.)/(good_num/&good_total.))*((bad_num/&bad_total.)-(good_num/&good_total.)) as iv
from result1 a;
quit;
proc append base=total_result data=result2 force;run;
proc sql;
create table iv_result as
select distinct varname, sum(iv) as iv
from total_result(where=(varname^=''))
group by varname;
quit;
%end;
/*合并筛选指标*/
proc sql noprint;
create table var_select_m as
select * from var_select as a left join iv_result as b on a.Variable=b.varname;
quit;
/*变量筛选*/
%if &method.=1 %then %do;
proc sort data=var_select_m;
by Cluster1 descending iv /* iv*/;
run;
%end;
%else %do;
proc sort data=var_select_m;
by Cluster1 RSquareRatio /* RSquareRatio*/;
run;
%end;
data var_selected(where=(row=1));
set var_select_m;
if first.Cluster1 then row=1;
else row+1;
by Cluster1;
run;
%global var_clus;
proc sql noprint;
select Variable into :var_clus separated by ' '
from Var_selected;
quit;
%put &var_clus;
data &DSout.;
set &DSin.;
keep target &var_clus;
run;
%mend;
这是代码讲解
varclus(DSin=,target=,Maxclusters=,group=,method=,DSout=)
DSin:你的数据集
Maxclusters:填的是你想最多变成多少簇。
Group:跑iv的时候你想分几组算iv。
method:method=1每组取iv最大;method=2每组取1-R方最小;
以上就是这个宏的参数填写,接下来我跟大家说下结果有哪些。
结果:这个结果产出的全部数据集。主要看两张表:
1、Var_select_d:
保留的是每一簇筛选出来的变量,如果想换取变量,请参考下一张表。
2、Var_select_m
这张表保存的是每个簇的各个变量的指标。