登录
首页精彩阅读SAS编程中的这些小问题你遇到过吗
SAS编程中的这些小问题你遇到过吗
2017-04-02
收藏

SAS编程中的这些小问题你遇到过吗

在用SAS编程时,总是时不时会遇到各种各样的小问题,我本人也遇到过一些有意思的问题,在写程序的过程中,为了避免这些小问题也慢慢的积累了一些经验,那么通过这一节分享给大家吧,希望会给各位童鞋带来一些帮助!

问题一




WARNING: The quoted string currently being processed has become more than 262 bytes long.  You might have unbalanced quotation marks.




上述问题一般出现在这种情况下:

data tmp;

do i = 1 to 100;

var = 'var'||left(i);

output;

end;

run;

proc sql;

select var into : varlist separated by ' ' 

from tmp;

quit;

data _null_;

var = scan("&varlist.",1,' ');

put var =;

run;

当我需要对某一个变量的所有行值生成一个宏变量的时候,就会通过如上的方式进行编程,那么通过scan函数进行拆解时,就会得到上述这种警告。从上述警告可以看到是因为字符超过了262个字节。尽管没有报错,但是出于编程的完美运行角度看,有些童鞋可能就受不了了。

那么我们可以通过添加一行代码来解决这个问题:

options noquotelenmax;

问题二




WARNING: 没有解析符号引用 VARLIST。




这种警告应该会很常见,那么我所指的问题并不是通常我们所说的宏变量未生成的情况,而是在有条件的生成宏变量的情况下合理的未生成宏变量的结果,如下所示:

proc sql;

select distinct age into : agelist separated by ' ' 

from sashelp.class

where age > 16;

quit;

%put agelist = &agelist.;

上述代码表示将满足条件的age不重复的通过空格分隔符生成宏变量agelist,但是很显然数据集中的age并不满足这个条件,因此会出现上述所谓的警告,那么为了避免这个问题,我们可以在程序的最前面对宏变量进行声明,可以是局部的,也可以是全局的,视具体情况而定,这样我们就可以得到一个初始化的值为空的宏变量。

在这里,我们对其进行全局的声明:

%global agelist;

问题三




WARNING: 没有解析宏 CI 的调用。




在统计报告的报表里,通常在第一列的某一行会出现一个标签“%95CI”,而为了让这个标签出现,我们通常习惯用下列语句:

proc sql;

create table tmp as

select '('||compress(lower)||','||compress(upper)||')' as confidence label = "95%CI"

from dataset;

quit;

通过上述类似这种语句我们就可以得到对应的95%CI,那么为了避免%被误认为宏的调用,我们可以采用两种办法:

一:label = '95%CI'

二:label = %nrstr("95%CI")

问题四




这个问题来自论坛,涉及到anydtdte的格式默认长度问题,很有意思,特意贴出来。

程序如下所示:

data a;

input date $ 1-51;

cards;

2012-01-19T11:30

2011-12-22T11:15

2012-03-08T08:15

;

run;

data b;

set a;

date1=scan(date,1,'T');

date2=input(date,anydtdte.);

format date2 date9.;

run;

最终的结果如下所示:

上述结果有两处问题:

第一:date2的结果与date1的日期结果对不上,例如第二列为2012年1月19日,到了第三列变成了2012年1月1日;

第二:第三列date2的最后一行结果为缺失。

那么问题的关键在在哪呢,从上述代码我们可以看到编程做日期转换的过程中采用anydtdte格式来进行转化,这个思路并没有错,那么错在什么地方呢?

首先给出SAS HELP的语法:
 

从上述编程可看到,这么童鞋在采用anydtdte格式进行转化时并没有设定字符长度,而是采用了anydtdte默认读取的长度值9,因此在读取date1字符串时,就变成了只读取前9位,因而出现日期对不上,到了最后一行更是因为第九位数字为0而没有此日期因此无法转化从而出现缺失的情况。

那么纠正这个错误想必各位童鞋都应该了解了,只需要在anydtdte后面加个数字10就完美的解决了这个问题了。

date2=input(date,anydtdte10.);

问题五




%abort 和 %return




关于这两个宏语句,作用都差不多,都是为了中断程序的运行,只是轻重程度不一样,这一点需要谨记:

%abort直接结束SAS进程。也就是说你的SAS在执行完这个语句之后,你的SAS会被立即关闭,甚至都来不及保存,因此运行这个语句需要慎重考虑。

%return 中断你当前运行的宏。


对于%return举个简单的例子:

%macro checkit(error);

%if &error = 1 %then %do;

%put 程序中断,请修正参数;

%return;

%end;

%else%put 继续进行;

%mend checkit;

上述编程表示当输入的error = 1 时,日志会输出“程序中断,请修正参数”,同时宏被中断;当输入的error = 其他值时,日志会输出“继续进行”。

问题六




为了凑成六六大顺,再写一个今天某位童鞋遇到的一个问题吧。

问题是这样的:

一个数据集的一个变量假定为var,var的值为1 1 2 2 2 3 . . 5。可以看到有2个1,3个2,2个缺失,一个5。那么这位童鞋想通过程序统计var为2的个数,于是写出了如下代码:

proc sql;

select count(var = 2) as varcnt

from tmp;

quit;




这位童鞋可能有点不太明白sum函数和count函数在遇到逻辑比较运算的时候的区别。

首先我说一下count函数吧。

Count函数一般在sql中有两种写法,一种是count(*),这个表示对数据集行数的统计,如果加了group by,那就是分组的行数统计;一种是count(variable),这个是表示对某一个变量的非缺失行数的统计,加了group by 那也是同理;如果加了逻辑比较运算的话,像count(expression),跟count(*)基本上没啥区别,当然前提是这个运算不是简单的数值运算,我们知道数值运算中缺失值加任何值都是缺失,除非采用计算函数。

以上述数据为例:

data tmp;

input var @@;

cards;

1 1 2 2 2 . . 5

;

run;

proc sql;

select count(var) from tmp;

select count(*) from tmp;

select count(var = 1) from tmp;

quit;

最终得到的结果是:第一行为6,第二行为8,第三行为8。第三行中var = 1最终的结果要么是0,要么是1,因为非缺失的var的值 = 1肯定要么是0要么是1,而缺失的var值 = 1 的结果肯定是0,因此都是非缺失的,因此其实跟第一种写法意义一样。数据分析师培训

而sum函数则一般在sql中有两种写法:一种是sum(variable),这个表示对variable每行值的累加,不考虑缺失值;一种是sum(expression),那么就是对expression的结果进行累加,如果expression = 1 ,那么就是加1,如果expression = 0,那么就是加0。


数据分析咨询请扫描二维码

客服在线
立即咨询