设为首页收藏本站

EPS数据狗论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2496|回复: 1

SAS宏分享:统计各个变量的缺失值

[复制链接]

1

主题

3

金钱

49

积分

新手用户

发表于 2018-3-5 23:55:04 | 显示全部楼层 |阅读模式
%macro PrxChange(InputString,PrxString);

/**********************************************************************/
/* 此宏利用正则表达式的方法替换原始字符串的匹配子串为目标子串。其中, */
/* InputString是原始字符串;PrxString是指定子串的正则表达式,注意正则 */
/* 表达式要用/.../符号括起来。                                        */
/*                                                                    */
/* 最终原始字符串中的匹配子串替换为目标子串。注意用于替换子串的正则表 */
/* 达式形如:s/SourceString/TargetString/                             */
/*                                                                    */
/*                                      Created on 2012.8.6           */
/*                                      Modified on 2012.8.6          */
/**********************************************************************/

%local PrxStringID RegRt;

%let RegRt=0;
%let PrxStringID=%SYSFUNC(PRXPARSE(&PrxString));

%if &PrxStringID GT 0 %then %do;
        %let RegRt=%SYSFUNC(PRXCHANGE(&PrxStringID, -1, &InputString));                /* -1表示全部替换 */
%end;

%syscall PrxFree(PrxStringID);
%str(&RegRt)                /* 最后不需要加分号 */

%mend;


%macro Demo();

/* replace the matching string to target string */
%let zip=%PrxChange(InputString=Jones Fred,PrxString=s/(\w+) (\w+)/22 1/);
%put &zip;

%mend;
%macro ChkVarType(SourceTable,InputVar,FlagVarType);

/**********************************************************************/
/* 此宏的作用是检查某数据表中指定变量的类型,即数值型或字符型。其中, */
/* SourceTable是原始表格;InputVar是指定的变量,若为多个变量,请用空 */
/* 格分隔;FlagVarType是标记宏变量名称,=N表示为数值型,=C表示为字符 */
/* 型,若有多个InputVar变量,则不同位置上的N或C代表相应变量的类型。 */
/* */
/* 最终得到的是宏变量&FlagVarType,=N表示指定变量为数值型,=C表示为字 */
/* 符型,若为多个变量,则不同位置上的N或C代表相应变量的类型。 */
/* */
/* Created on 2012.4.27 */
/* Modified on 2012.9.18 */
/**********************************************************************/

%if %SYSFUNC(FIND(&SourceTable,.)) NE 0 %then %do;
%let CVT_LibName=%UPCASE(%SCAN(&SourceTable,1,.));
%let CVT_MemName=%UPCASE(%SCAN(&SourceTable,2,.));
%end;
%else %do;
%let CVT_LibName=WORK;
%let CVT_MemName=%UPCASE(&SourceTable);
%end;

%ChkDataSet(DataSet=&CVT_LibName..&CVT_MemName,FlagDataSetExists=CVT_FlagDataSetExists);

%if &CVT_FlagDataSetExists EQ 1 %then %do;
%ChkVar(SourceTable=&SourceTable,InputVar=&InputVar,FlagVarExists=CVT_FlagVarExists);

%if %SYSFUNC(FIND(&CVT_FlagVarExists,0)) EQ 0 %then %do;
proc contents data=&SourceTable out=CVT_temp(keep=NAME TYPE) noprint;
run;

%global &FlagVarType;

%if %SYSFUNC(FIND(&InputVar,%STR( ))) NE 0 %then %do;
%SeparateString(InputString=&InputVar,OutputString=CVT);

%do CVT_i=1 %to &CVT_Num;
%let CVT_FlagVarExists&CVT_i=0;

data _null_;
set CVT_temp;
if UPCASE(NAME)=UPCASE("&&CVT_Var&CVT_i.") then call symputx("CVT_FlagVarType&CVT_i",TYPE);
run;
%end;

%let &FlagVarType=&&CVT_FlagVarType1;

%do CVT_j=2 %to &CVT_Num;
%let &FlagVarType=&&&FlagVarType.&&CVT_FlagVarType&CVT_j;
%end;
%end;
%else %do;
%let &FlagVarType=0;

data _null_;
set CVT_temp;
if UPCASE(NAME)=UPCASE("&InputVar.") then call symputx("&FlagVarType.",TYPE);
run;
%end;

%let &FlagVarType=%SYSFUNC(TRANSLATE(&&&FlagVarType,NC,12)); /* 转换变量类型的显示方式,N表示数值型,C表示字符型 */
%end;
%else %do;
%put ERROR: There is no variable named %SCAN(&InputVar,%SYSFUNC(FIND(&CVT_FlagVarExists,0))), please check it again.;
%goto exit;
%end;
%end;
%else %if &CVT_FlagDataSetExists EQ 0 %then %do;
%put ERROR: The DataSet "&SourceTable." does not exist, please check it again.;
%goto exit;
%end;
%else %do;
%put ERROR: There may be something wrong with the macro ChkDataSet, please contact the writer for help.;
%goto exit;
%end;

/* 若要显示&FlagVarType的值,请取消下面的注释 */
/*%put &FlagVarType=&&&FlagVarType;*/

/* 删除不必要的表格 */
proc delete data=CVT_temp;
run;

%exit:
%mend;


%macro Demo();

%let SourceTable=Allretoffund_holding_temp1;
%let InputVar=End_Yr End_Mt End_Dy Stk_Name;
%let FlagVarType=FlagVarType1;
%ChkVarType(&SourceTable,&InputVar,&FlagVarType);

%mend;
%macro SeparateString(InputString,OutputString);
/**********************************************************************/
/* 此宏用于将含有一组单词的字符串拆分为一个个的单词,并将这些单词依次 */
/* 存放于一系列宏变量之中。注意,字符串中单词的定义为由字母、数字和下 */
/* 下划线组成的一个整体,而分隔符可以为除字母、数字、下划线以及逗号之 */
/* 外的其他任意字符。其中InputString是所选的字符串,OutputString是输 */
/* 出的字符串前缀,不需要加最后的下划线。 */
/* */
/* 最终得到的是一组单词的宏变量&OutputString._Var1,&OutputString.Var2 */
/* 等以及字符串所含单词数量的宏变量&OutputString._Num。 */
/* */
/* Created on 2012.9.18 */
/* Modified on 2012.12.6 */
/**********************************************************************/

data SS_temp;
Str="&InputString";
run;

data SS_temp;
set SS_temp;
Words=0;
do while(SCAN(Str,Words+1,' ') NE "");
Words+1;
end;
run;

%global &OutputString._Num;

proc sql noprint;
select Words into :&OutputString._Num from SS_Temp;
quit;

%do SS_i=1 %to &&&OutputString._Num;
%global &OutputString._Var&SS_i;
%let &OutputString._Var&SS_i.=%SYSFUNC(SCAN(&InputString,&SS_i,' '));
%end;

/* 去除&OutputString._Num前后的空格 */
%let &OutputString._Num=%SYSFUNC(TRIM(&&&OutputString._Num));

/* 删除不必要的表格 */
proc delete data=SS_temp;
run;

%mend;


%macro Demo();

%let InputString=12 -24;
%let OutputString=a;
%SeparateString(&InputString,&OutputString);

%put &a_Num;
%put &a_Var2;

%mend;
%macro ChkDataSet(DataSet,FlagDataSetExists);

/**********************************************************************/
/* 此宏用于检查指定的数据集是否存在。其中,DataSet是指定的数据集,若 */
/* 需要指定具体的逻辑库,则采用逻辑库.数据库的格式,可设多个数据集, */
/* 用空格分隔;FlagDataSetExists是标记宏变量名称,=1表示数据集存在, */
/* 否则=No,若指定了多个数据集,则不同位置上的1或0代表相应的数据集是 */
/* 否存在。另外需要注意,第一,当仅指定一个数据集时,若不指定逻辑库名 */
/* 称,而只指定数据集名称,此时若在SAS环境中只包含一个指定的数据集, */
/* 则标记宏变量FlagDataSetExists=1,若包含多个同名的数据集,则会报错;*/
/* 第二,当指定多个数据集时,若不指定逻辑库名称,则默认为WORK逻辑库。 */
/* */
/* 最终得到的是宏变量&FlagDataSetExists,若指定数据集存在,则有 */
/* &FlagDataSetExists=1,否则=0,若为多个数据集,则不同位置上的1或0代 */
/* 表相应的数据集是否存在。 */
/* */
/* Created on 2012.11.16 */
/* Modified on 2012.11.16 */
/**********************************************************************/

/* 检查DataSet的存在性 */
%if &DataSet EQ %STR( ) %then %do;
%put ERROR: The DataSet should not be blank, please check it again.;
%goto exit;
%end;

/* 开始进行计算 */
%global &FlagDataSetExists;

/* 情形一:仅设定一个数据集,此时若省略逻辑库名,则在所有逻辑库中查找同名的数据集并予以报告 */
%if %SYSFUNC(FIND(&DataSet,%STR( ))) EQ 0 %then %do;
/* 检查DataSet的合法性 */
%if %SYSFUNC(FIND(&DataSet,.)) NE 0 %then %do;
%let CDS_LibName=%UPCASE(%SCAN(&DataSet,1,.));
%let CDS_DataSet=%UPCASE(%SCAN(&DataSet,2,.));
%end;
%else %do;
%let CDS_LibName=%STR();
%let CDS_DataSet=%UPCASE(&DataSet);
%end;

%if &CDS_DataSet EQ %STR() %then %do;
%put ERROR: The DataSet should not be blank, please check it again.;
%goto exit;
%end;
%else %if &CDS_LibName NE %STR() %then %do;
%let &FlagDataSetExists=%SYSFUNC(EXIST(&CDS_LibName..&CDS_DataSet.));
%end;
%else %do;
proc sql noprint;
create table CDS_temp as
select * from sashelp.vtable
where memname="&CDS_DataSet";
quit;

proc sql noprint;
select count(*) into :CDS_DataSetNum from CDS_temp;
quit;

%if &CDS_DataSetNum EQ 0 %then %let &FlagDataSetExists=0;
%else %if &CDS_DataSetNum EQ 1 %then %let &FlagDataSetExists=1;
%else %do;
%put ERROR: There could be more than one DataSets with the same name appointed in different libraries, please reassign a LibName first.;
%goto exit;
%end;
%end;
%end;
/* 情形二:设定多个数据集,此时若省略逻辑库名,则默认为WORK逻辑库 */
%else %do;
%SeparateString(InputString=&DataSet,OutputString=CDS_DateSet);

%do CDS_i=1 %to &CDS_DateSet_Num;
/* 检查DataSet的合法性 */
%if %SYSFUNC(FIND(&&CDS_DateSet_Var&CDS_i,.)) NE 0 %then %do;
%let CDS_LibName_&CDS_i.=%UPCASE(%SCAN(&&CDS_DateSet_Var&CDS_i,1,.));
%let CDS_DataSet_&CDS_i=%UPCASE(%SCAN(&&CDS_DateSet_Var&CDS_i,2,.));
%end;
%else %do;
%let CDS_LibName_&CDS_i.=WORK;
%let CDS_DataSet_&CDS_i.=%UPCASE(&&CDS_DateSet_Var&CDS_i);
%end;

%let CDS_FlagDataSetExists_&CDS_i.=%SYSFUNC(EXIST(&&CDS_LibName_&CDS_i...&&CDS_DataSet_&CDS_i.));
%end;

%let &FlagDataSetExists=&&CDS_FlagDataSetExists_1;

%do CDS_j=2 %to &CDS_DateSet_Num;
%let &FlagDataSetExists=&&&FlagDataSetExists.&&CDS_FlagDataSetExists_&CDS_j;
%end;
%end;

/* 如果想要输出结果,请取消下面的注释 */
/*%put &&&FlagDataSetExists;*/

/* 删除不必要的表格 */
proc datasets lib=work nolist;
delete CDS_temp;
quit;


%exit:
%mend;


%macro Demo();

%let DataSet=Gfl_fundcodelist_mgrname Gfl_managersoffund; /* 数据集名称,可设为多个,用空格分隔 */
%let FlagDataSetExists=FlagDataSetExists1; /* 宏变量的名称,注意不能与参数名称相同*/
%ChkDataSet(&DataSet,&FlagDataSetExists);

%put &FlagDataSetExists1;

%mend;

%macro ChkValue(SourceTable,InputVar,Value,FlagValueExists);

/**********************************************************************/
/* 此宏的作用是检查某数据表中是否含有指定变量为某特定值的观测。其中, */
/* SourceTable是原始表格;InputVar是指定的变量,且只能指定一个变量; */
/* Value是指定的值,字符串不需要加引号,可以设为多个值,用空格分隔; */
/* FlagValueExists是标记宏变量名称,=1表示原数据表中含有指定变量为某 */
/* 特定值的观测,否则=0。 */
/* */
/* 最终得到的是宏变量&FlagValueExists,不同位置上的数值表示对应的值是 */
/* 否在原表中的指定变量中存在,=1表示原数据表中含有指定变量为某特定值 */
/* 的观测,否则=0。 */
/* */
/* Created on 2012.11.6 */
/* Modified on 2012.11.12 */
/**********************************************************************/

/* 检查SourceTable的存在性 */
%if %SYSFUNC(FIND(&SourceTable,.)) NE 0 %then %do;
%let CVL_LibName=%UPCASE(%SCAN(&SourceTable,1,.));
%let CVL_MemName=%UPCASE(%SCAN(&SourceTable,2,.));
%end;
%else %do;
%let CVL_LibName=WORK;
%let CVL_MemName=%UPCASE(&SourceTable);
%end;

%ChkDataSet(DataSet=&CVL_LibName..&CVL_MemName,FlagDataSetExists=CVL_FlagDataSetExists);

%if &CVL_FlagDataSetExists EQ 0 %then %do;
%put ERROR: The DataSet "&SourceTable." does not exist, please check it again.;
%goto exit;
%end;

/* 检查InputVar的唯一性 */
%if %SYSFUNC(FIND(&InputVar,%STR( ))) NE 0 %then %do;
%put ERROR: The InputVar should be only a single variable, please check it again.;
%goto exit;
%end;

/* 检查InputVar的存在性 */
%ChkVar(SourceTable=&CVL_LibName..&CVL_MemName,InputVar=&InputVar,FlagVarExists=CVL_FlagInputVarExists);

%if %SYSFUNC(FIND(&CVL_FlagInputVarExists,0)) NE 0 %then %do;
%put ERROR: The InputVar "%SCAN(&InputVar,%SYSFUNC(FIND(&CV_FlagInputVarExists,0)))" does not exist in SourceTable, please check it again.;
%goto exit;
%end;

/* 开始进行计算 */
/* 拆分Value */
%SeparateString(InputString=&Value,OutputString=CVL_Value);

/* 为&FlagValueExists设置初始值 */
%do CVL_i=1 %to &CVL_Value_Num;
%let CVL_FlagValueExists_&CVL_i.=0;
%end;

/* 检查InputVar的格式 */
%ChkVarType(SourceTable=&CVL_LibName..&CVL_MemName,InputVar=&InputVar,FlagVarType=CVL_InputVarType);

%if &CVL_InputVarType EQ C %then %do;
%do CVL_j=1 %to &CVL_Value_Num;
data _null_;
set &SourceTable;
call symputx("CVL_FlagValueExists_&CVL_j.",'1');
where UPCASE(&InputVar)=UPCASE("&&CVL_Value_Var&CVL_j.");
run;
%end;
%end;
%else %if &CVL_InputVarType EQ N %then %do;
%do CVL_k=1 %to &CVL_Value_Num;
data _null_;
set &SourceTable;
call symputx("CVL_FlagValueExists_&CVL_k.",'1');
where &InputVar=&Value;
run;
%end;
%end;

/* 连接上述多个宏变量,生成&FlagValueExists */
%global &FlagValueExists;

%let &FlagValueExists=&CVL_FlagValueExists_1;

%do CVL_l=2 %to &CVL_Value_Num;
%let &FlagValueExists=&&&FlagValueExists.&&CVL_FlagValueExists_&CVL_l;
%end;

/* 若要显示&FlagValueExists的值,请取消下面的注释 */
/*%put &FlagValueExists=&&&FlagValueExists;*/

%exit:
%mend;


%macro Demo();

%let SourceTable=Allretoffund_holding_temp1;
%let InputVar=End_Yr;
%let Value=2004; /* 字符串不需要加引号 */
%let FlagValueExists=FlagValueExists1;
%ChkValue(&SourceTable,&InputVar,&Value,&FlagValueExists);

%mend;
%macro Demo();

%let SourceTable=GLOLD_TradeDate;
%let TargetTable=AAA;
%let InputVar=CHARACTER;                /* =Numeric表示统计全部数值型变量,=Character表示统计全部字符型变量,=All表示统计全部变量,大小写不敏感 */
%GetMissNum(&SourceTable,&TargetTable,&InputVar);

%mend;
%macro GetMissNum(SourceTable,TargetTable,InputVar);
/**********************************************************************/
/* 此宏的作用是统计原表中不同变量的缺失值数量。其中SourceTable是原始  */
/* 表格,SourceTable是结果表格;TargetTable是结果表格;InputVar是原始 */
/* 表格中的变量,可设多个变量,用空格分隔,也可如下设置:=Numeric表示 */
/* 统计全部数值型变量,=Character表示统计全部字符型变量,=All表示统计 */
/* 全部变量。                                                         */
/*                                                                    */
/* 最终结果表格中包含所有指定变量的名称、类型和相应的缺失值数量。     */
/*                                                                    */
/*                                      Created on 2012.9.6           */
/*                                      Modified on 2012.10.16        */
/**********************************************************************/

/* 检查TargetTable的存在性 */
%if &TargetTable EQ %STR() %then %do;
        %put ERROR: The TargetTable should not be blank, please check it again.;
        %goto exit;
%end;

/* 检查InputVar的合法性 */
%if %UPCASE(&InputVar) NE NUMERIC AND %UPCASE(&InputVar) NE CHARACTER AND %UPCASE(&InputVar) NE ALL %then %do;
        %ChkVar(SourceTable=&SourceTable,InputVar=&InputVar,FlagVarExists=GMN_FlagVarExists);

        %if %SYSFUNC(FIND(&GMN_FlagVarExists,0)) NE 0 %then %do;
                %put ERROR: The InputVar should be Numeric, Character, All or any variable name in SourceTable, case insensitive and without quotes.;
                %goto exit;
        %end;
%end;

%if %UPCASE(&InputVar) EQ NUMERIC %then %do;
        proc means data=&SourceTable noprint;                /* proc means仅针对数值型变量 */
                  output out=GMN_MissNumeric nmiss=;
        run;

        proc transpose data=GMN_MissNumeric out=&TargetTable name=VarName;
                var _ALL_;
        run;

        data &TargetTable(rename=(COL1=MissNum));
                set &TargetTable;
                VarType='N';
                if _N_>2;
        run;
%end;
%else %if %UPCASE(&InputVar) EQ CHARACTER %then %do;
        proc contents data=&SourceTable position out=GMN_VarList(keep=name type varnum) noprint;
        run;

        /* 检查字符型变量是否存在 */
        %ChkValue(SourceTable=GMN_VarList,
                InputVar=type,
                Value=2,
                FlagValueExists=GMN_FlagCharVarExists);

        %if &GMN_FlagCharVarExists GT 0 %then %do;
                proc sql noprint;
                        select compress(name)||'_0' into :GMN_VarNameChar separated by ' '
                                from GMN_VarList where type=2 order by varnum;
                quit;

                data GMN_VarListChar(drop=_CHARACTER_ i);
                        set &SourceTable(keep=_CHARACTER_);
                        array mychar(*) $ _CHARACTER_;
                        array mynum(*) &GMN_VarNameChar;
                        do i=1 to dim(mychar);
                            if  mychar(i) ="" then mynum{i}=.;
                                else mynum(i)=1;
                        end;
                run;

                proc means data=GMN_VarListChar noprint;
                          output out=GMN_MissChar nmiss=;
                run;

                proc transpose data=GMN_MissChar out=&TargetTable name=VarName;
                        var _ALL_;
                run;

                data &TargetTable(rename=(COL1=MissNum));
                        set &TargetTable;
                        VarType='C';
                        if SUBSTR(VarName,LENGTH(VarName)-1,2) EQ '_0' then VarName=SUBSTR(VarName,1,LENGTH(VarName)-2);
                        if _N_>2;
                run;
        %end;
        %else %do;
                %put ERROR: There is no character variable existed in SourceTable, please check it again.;
                %goto exit;
        %end;
%end;
%else %do;
        proc means data=&SourceTable noprint;                /* proc means仅针对数值型变量 */
                  output out=GMN_MissNumeric nmiss=;
        run;

        proc transpose data=GMN_MissNumeric out=GMN_MissNumeric name=VarName;
                var _ALL_;
        run;

        data GMN_MissNumeric;
                set GMN_MissNumeric;
                VarType='N';
        run;

        proc contents data=&SourceTable position out=GMN_VarList(keep=name type varnum) noprint;
        run;

        /* 检查字符型变量是否存在 */
        %ChkValue(SourceTable=GMN_VarList,
                InputVar=type,
                Value=2,
                FlagValueExists=GMN_FlagCharVarExists);

        %if &GMN_FlagCharVarExists GT 0 %then %do;
                proc sql noprint;
                        select compress(name)||'_0' into :GMN_VarNameChar separated by ' '
                                from GMN_VarList where type=2 order by varnum;
                quit;

                data GMN_VarListChar(drop=_CHARACTER_ i);
                        set &SourceTable(keep=_CHARACTER_);
                        array mychar(*) $ _CHARACTER_;
                        array mynum(*) &GMN_VarNameChar;
                        do i=1 to dim(mychar);
                            if  mychar(i) ="" then mynum{i}=.;
                                else mynum(i)=1;
                        end;
                run;

                proc means data=GMN_VarListChar noprint;
                          output out=GMN_MissChar nmiss=;
                run;

                proc transpose data=GMN_MissChar out=GMN_MissChar name=VarName;
                        var _ALL_;
                run;

                data GMN_MissChar;
                        set GMN_MissChar;
                        VarType='C';
                        if SUBSTR(VarName,LENGTH(VarName)-1,2) EQ '_0' then VarName=SUBSTR(VarName,1,LENGTH(VarName)-2);
                run;

                data GMN_MissNum;
                        length VarName $32;
                        set GMN_MissNumeric GMN_MissChar;
                run;
        %end;
        %else %do;
                data GMN_MissNum;
                        set GMN_MissNumeric;
                run;
        %end;

        proc sql noprint;
                create table &TargetTable as
                        select GMN_VarList.Name as VarName,GMN_MissNum.COL1 as MissNum,GMN_MissNum.VarType
                                from GMN_VarList left join GMN_MissNum
                                on GMN_VarList.Name EQ GMN_MissNum.VarName
                                order by GMN_VarList.VarNum;
        quit;

        /* 若InputVar=All,则就此完结,否则还需要进行如下的步骤 */
        %if %UPCASE(&InputVar) NE ALL %then %do;
                %let InputVar_Comma=%PrxChange(InputString=&InputVar,PrxString=s/(\w+)/'$1'/);                /* 给InputVar中的代码加引号 */
                %let InputVar_Comma=%SYSFUNC(TRANSLATE(&InputVar_Comma,%STR(,),%STR( )));                /* 替换InputVar中的空格为逗号 */

                proc sql noprint;
                        create table &TargetTable as
                                select GMN_VarList.Name as VarName,GMN_MissNum.COL1 as MissNum,GMN_MissNum.VarType
                                        from GMN_VarList inner join GMN_MissNum
                                        on GMN_VarList.Name=GMN_MissNum.VarName and
                                                GMN_VarList.Name in (&InputVar_Comma)
                                        order by GMN_VarList.VarNum;
                quit;
        %end;
%end;

/* 删除不必要的表格 */
proc datasets lib=work nolist;
        delete GMN_:;
quit;

%exit:
%mend;

0

主题

2

金钱

68

积分

新手用户

发表于 2018-5-2 10:23:58 | 显示全部楼层
厉害了,终于找到了
回复 支持 反对

使用道具 举报

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

本版积分规则

关闭

站长推荐上一条 /1 下一条

客服中心
关闭
在线时间:
周一~周五
8:30-17:30
QQ群:
653541906
联系电话:
010-85786021-8017
在线咨询
客服中心

意见反馈|网站地图|手机版|小黑屋|EPS数据狗论坛 ( 京ICP备09019565号-3 )   

Powered by BFIT! X3.4

© 2008-2028 BFIT Inc.

快速回复 返回顶部 返回列表