前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SAS-如何找出数据集超长变量及观测,并自动进行变量的拆分...

SAS-如何找出数据集超长变量及观测,并自动进行变量的拆分...

作者头像
Setup
发布2019-10-20 14:48:28
3.3K0
发布2019-10-20 14:48:28
举报

前段时间有人给小编提了一个需求,找出数据集中长度超过200字节的变量,并对变量进行拆分...这个需求当然不难,但是还是分享给大家~主要最近没写啥程序,也就没学到啥新的技能...关于变量长度的拆分,我想也是一个常见的问题。

实现方法

小编每拿到一个需求的时候

最先考虑的是如何实现

因为不同的办法决定了代码的多少

以及运行效率的高低

不过

真正忙起来的时候哪有时间去思考那么多方法...

能够在第一时间解决问题的方法就是好方法

...

以此为例,小编最先想到实现这个需求的办法是啥:

1.找出数据集中字符变量(各观测存储字符串最长长度超过200)的变量...

2.根据实际储存最长长度进行计算需要新衍生变量个数并进行衍生...

3.强制转化变量属性大于200个长度但存储最长长度未达200字符的变量...

4.调整数据集中变量顺序及删除乱七八糟的衍生过程文件...

实现步骤基本上就是这样了,然后就进行细节的填充。细节的填充就是SAS程序进行各步骤的实现,接下来看看小编的实现方法..

写这个程序的时候,我开始打算开放好几个宏参数...

程序写着、写着就写懒了....不想弄太多功能了.

正所谓“杀猪焉用宰牛刀”,太多功能了,也用不到...

下面与小编看看这个程序的代码:

首先定义了3个宏参数:

1.inds :输入需要处理的数据集

2.maxlen:指定超过的长度...默认为200,这个就是写懒了的典型例子..

写了一半就不想开放了...然后又懒的修改前面的,也就弄一个默认值这里

而且后面的计算规则也基本都是依据200长度来写的

...

3.cnt:拆分后衍生变量之间的间隔符号,默认为空

下面这段程序的功能就是check一下输入的数据集的格式是否正确,

不正确的话会跳出宏的执行(%return;跳出宏的执行)

如果正确的话,就重新定义了几个Local宏变量

代码语言:javascript
复制
%macro  aut_dev_var(inds=,maxlen=%str(200),cnt=%str( ));
%local libname memname;
%if &inds.= %then %do;
   %put note:plesce check your dataset name;
   %return;
%end;
%if %length(%sysfunc(compress("&inds.","."))) ne %length(%sysfunc(compress("&inds.",""))) %then %do;
   %let libname=%scan("&inds.",1,".");
   %let memname=%scan("&inds.",2,".");
%end;
%else %do;
   %let libname=work;
   %let memname=&inds.;
%end;

然后就到了对输入的数据集进行处理的阶段了~

获取数据集的变量名,变量类型,变量长度等数据集的属性等...

并筛选出超过200字符长度字符变量....

如果不存在这样的变量,则直接跳转到宏的结尾阶段(%goto语句跳转)

代码语言:javascript
复制
/*情况一:inds 输入为单个数据集 */

proc contents data=&libname..&memname. out=_varstemp10(keep=memname name label varnum type length ) directory noprint memtype=data centiles;
proc sort data=_varstemp10  out=_varstemp10  sortseq=linguistic(numeric_collation=on);by memname varnum ;
quit;

/*找出需要转置处理的变量 */
data _varstemp11;
  set _varstemp10;
  if input(&maxlen.,??best.)<length and type=2  ;
run;
%let dsid=%sysfunc(open(_varstemp11));
%let nobs=%sysfunc(attrn(&dsid,nobs));
%let rc= %sysfunc(close(&dsid));

%if  &nobs. eq 0 %then %do;
%put ******************************************************************************;
skip  2;
%put &memname.不存在超过限定长度的变量以及观测...将跳出后续处理;
skip  2;
%put ******************************************************************************;
%goto exit;
%end;

接着,如果存在变量属性超过200长度变量,则将这样变量塞入宏变量中

同时利用_N_给每条观测添加一个行号....

接着就给数据集做一个transpose,将每个变量的值变成纵向的结构

并找出存储值超过指定长度的观测(本来打算将这样的记录做一个输出、也就这儿为啥用transpose的原因...后来想了想还是算了,输出也没啥用...应该没人看)

代码语言:javascript
复制
proc sql noprint;
    select name into:translist separated by " " from  _varstemp11   ;
  quit;

/*衍生数据集行号:作为索引变量,数据集转置key变量*/
data _varstemp17;
  set &libname..&memname.;
  temp_line_id=_n_;
run;
proc transpose data=_varstemp17 out=_varstemp17  prefix=value;
by  temp_line_id;
var &translist.;
run;
/*进行筛选,将超过指定长度的观测挑选出来*/
data _varstemp17;
  length  domain value1 $3000.;
  set _varstemp17;
  length=length(value1);
  domain=compress(%upcase("&memname."));
  if input(&maxlen.,??best.)<length;
run;


/*获取超出指定长度的记录数*/
%let dsid=%sysfunc(open(_varstemp17));
%let nobs=%sysfunc(attrn(&dsid,nobs));
%let rc= %sysfunc(close(&dsid));


%if  &nobs. eq 0 %then %do;
%put ******************************************************************************;
skip  2;
%put &memname.不存在超过限定长度的变量以及观测...将跳出后续处理;
skip 2;
%put ******************************************************************************;
%goto exit;
%end;

接着,在上面的基础上找出各变量存储的最长长度...

代码语言:javascript
复制
/*找出数据集中变量超过指定长度的变量的最长字符个数*/
proc sql undo_policy=none;
create table _varstemp16 as  select distinct domain,_name_,_label_,max(length) as max  from   _varstemp17
group by domain,_name_;
quit;

接着还是创建宏变量...

下面的宏变量就是用来存放衍生程序的语句

新生成的变量,小编采用的ksubstr来拆分变量,为什么用Ksubstr

这个地方不好言传,可以慢慢意会...

也可以说是避免将一个汉字从中劈开,造成乱码这种情况...

然后一个超过长变量到底衍生新生成几个变量合适呢?

这个是由下面程序的do语句控制的~

代码语言:javascript
复制
data _varstemp12;
  set _varstemp16;
  do i=1 to (max*2)/(&maxlen.)+1;
  newvar=compress(strip(_name_)||strip("_&cnt.")||strip(i)||strip("=ksubstr(strip(")||strip(_name_)||strip("),")||ifn(i=1,1,(i-1)*100+1)||strip(",100)"));
  newlabl=compress(strip(_name_)||strip("_&cnt.")||strip(i)||strip('="')||strip(_label_)||strip(i)||strip('"'));
  output;
  end;
run;

为更好的看到这一步的效果:小编决定插入一个执行过程中的截图:

比如IETEST这个变量最长长度269个字符,我在此处进行拆分3个语句...

然后将这个数据集merge到总的数据结构的数据集中

这一步操作是为了retain变量在数据集中出现的顺序号

因为我后面还会在set数据集前length变量长度,会修改变量出现的顺序

同事衍生变量的时候新生成变量一般都在最后,

而要做到新生成变量出现的位置在原始的变量那个地方...

因此就需要retain一下数据中的变量....

代码语言:javascript
复制
proc sort data=_varstemp12(rename=(domain=memname _name_=name))  out=_varstemp13  sortseq=linguistic(numeric_collation=on);by  memname name i;quit;
proc sort data=_varstemp10  out=_varstemp10  sortseq=linguistic(numeric_collation=on);by  memname name varnum ;quit;

data _varstemp14;
  length memname name $3000.;
  merge _varstemp10 _varstemp13;
  by memname name;
  if ^missing(i) then name=compress(strip(name)||strip("_&cnt.")||strip(i));
run;

merge后的效果大概就是下面的:待会会在定义宏变量的时候 order by varnum,i

接着,将这些语句啊,变量啊...塞进相应的宏变量中

通过调用宏变量的方式,实现程序语句的批量处理...

代码语言:javascript
复制
proc sql noprint;
    select newvar into:new_varlist separated by ";" from _varstemp12   ;
    select newlabl into:new_lablist separated by "  " from _varstemp12   ;
    select name into:new_ordlist separated by "  " from _varstemp14  order by varnum,i ;
    select name into:new_lenlist separated by "  " from _varstemp14(where=(^missing(i)));
  select  strip("max(length(")||strip(name)||strip("))")||"  as  "||strip("len_")||strip(name) into:droplist separated by ","
  from _varstemp14(where=(^missing(i)))  ;
    select NAME into:chg_lenlist separated by " " from _varstemp14(where=(type=2 AND length>200 ));
quit;

 /*
option  error 关闭黑色的数据error 主要由于变量进行ksubstr进行截取的时候出现位置问题.这里可以关闭,不显示
同样varlenchk=nowarn 也是关闭警告,在变量长度发生改变的时候关闭警告
*/
  option error=0 varlenchk=nowarn;

data &memname.;
  set &libname..&memname.;
  length &new_lenlist. $200.;format &new_lenlist. $200.;informat &new_lenlist. $200.;
  &new_varlist.;;
  label &new_lablist.;
run;

data &memname.;
  length &chg_lenlist. $200.;
  set  &memname.;
run;

data &memname.(keep=&new_ordlist.);
  retain &new_ordlist.;
  set  &memname.;
run;

这里有俩个option是很有趣的option

一个是error=0;

另外一个就是varlenchk=nowarn;

至于作用,可以见上面代码中注释的部分...

特别建议大家在SASHELP中输入nowarn

我想一定会有新大陆发现...

一些小的option,可以让日志更美观....

有时候还能帮助你隐藏或者提醒编程中的错误....

言归正传,接着上面的代码来说...

做完上面的操作,我们的需求基本完成了...

已经衍生生成了新变量,同时添加了标签

也改变了变量出现的位置顺序,而且还修改了变量的长度...

但是呢...由于前面的do语句以及ksubstr的作用

是否有多余的变量生成呢...

也就是衍生的变量可能下面全是空的...

这个时候就需要进行一步操作,drop掉多余的变量...

代码语言:javascript
复制
proc sql undo_policy=none;
create table _varstemp15 as select distinct &droplist. from  &memname.  ;
quit;


proc transpose data=_varstemp15 out=_varstemp18 ;
var _all_;
run;


data _varstemp18;
  set _varstemp18;
  length  domain var $200.;
  domain=upcase("&memname.");
  var=substr(_name_,5);
  drop _name_;
  if col1 in (0 1);
run;

/*获取多余变量名称*/
%let dsid=%sysfunc(open(_varstemp18));
%let nobss=%sysfunc(attrn(&dsid,nobs));
%let rc= %sysfunc(close(&dsid));


%if  &nobss. eq 0 %then %do;
%put ******************************************************************************;
skip  2;
%put &memname.不存在多余变量...程序将跳出...
skip 2;
%put ******************************************************************************;
%goto  exit;
%end;


  proc sql noprint;
      select var into:dp_list separated by " " from _varstemp18   ;
  quit;

data &memname.(drop=&dp_list.);
  set &memname.;
run;

做完这一步就算是真的操作完了...

当然还是还在简单的处理一下

删除过程中乱七八糟的过程文件....

%symdel 删除全局宏变量,这里又有/nowarn;

如果droplista这个宏变量不存在,没有/nowarn是会绿色的警告的...

有了这个就不会有警告...

代码语言:javascript
复制
/*删除过程中的衍生数据集*/
%symdel droplista/nowarn;
%global droplista;
proc contents data=work._all_ out=_varstemp10(where=(index(memname,"_VARSTEMP")) keep=memname) directory noprint memtype=data centiles;
proc sort data=_varstemp10  out=_varstemp10  sortseq=linguistic(numeric_collation=on) nodupkey;by memname ;
run;
proc sql noprint;
select  distinct memname into:droplista separated by " " from _varstemp10;
quit;

proc delete data= &droplista  ;quit;
%mend;

然后呢

上面的这个macro是针对单个数据进行处理的

写个循环调用这个宏就可以批量操作了

也都比较简单

....

其实,我写完后就发现我写麻烦了...为啥这么说呢

因为完全可以不计算变量储存的最长长度

接着用变量属性的长度...

然后最后也删除一下多余的衍生变量,就可以了

今天就这么多了,后续内容,敬请期待~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-08-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 SAS程序分享号号号 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档