sas 变量降维、变量聚类、变量去除共线性

2018-05-29  本文已影响0人  _瑾_瑜_

今天的文章的使用场景是,是因为我很热衷处理那种别人不喜欢整理的各种流水数据,例如运营商通话流水啊,银行卡流水啊,信用卡流水等等,那么这些数据做衍生变量有个经常会碰到的问题,就是像这种“最近一天的通话次数”有可能跟“最近三天的通话次数”这种相关性很强,但是在拟合的之后,这种相关性强的只能进一个,不然共线性就来找你啦,所以这时候你要处理是: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

这张表保存的是每个簇的各个变量的指标。

上一篇下一篇

猜你喜欢

热点阅读