SAS 程序冷知识——proc import中遇到的那些bug

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SAS 程序冷知识——proc import中遇到的那些bug相关的知识,希望对你有一定的参考价值。

参考技术A 当我们用proc import导入一个excel文档的时候,经常会出现这样的情况:

这是因为excel的sheet名字过长导致的(有时候DM老是把sheet名字弄的老长,还后面缀这日期,搞得每次更新文件都先改程序)。

这种情况下最简单的处理就是手动修改excel的sheet名字,但是一般作为正式项目,作为外部数据的excel是不好随便改的。

既然不能改文件就只能改程序了,这里提供一个新的方法:

这两段程序到底哪里有不同呢?最主要的是dbms=的值不同,前者填写的是excel,后者填写的是xlsx。需要注意的是填写xlsx后,原来的两个参数就不能用了需要删掉。

有的时候excel文档是很讨厌的,比如原来数据是1.20,当转成SAS的时候,程序会“贴心”的把变量转成数值型,从而丢掉了1.20后面的0。这本来不影响分析,但是ORRES是要收集原始值的,人家填的是1.20,你怎么能写1.2呢?这个时候就需要我们强制把excel所有变量都变成字符型。

其实这是个偷懒的小技巧。我们只需要修改getnames=这个参数为no,这样excel第一行就会被当作变量的值而不是变量名或标题了。而excel的第一行一般来说,都是含有字符的,所以这样会让所有变量都被当作字符型处理。

当然,我们还可以直接修改excel,在excel中就直接把所有变量都定义为字符的,但是这样又犯了改原始数据的忌讳总之不推荐。

最后需要注意的是,mixed选项是很重要的,如果是no的话,一列中如果有纯数字的话很容易被判定为数值型,从而把那些有字符的变量置空。加了mixed=yes以后,一列中如果既有数字又有字符,就会被判定为字符型。但如果一列真的是纯数字,则会被判定为数值型。另外,对于日期格式,如果没有mixed话,会把日期导成date格式的数值型,但使用mixed之后,日期也会被当作字符处理。

如果dbms=excel的话,导入的字符变量最大长度默认是1024,再长会截断。但是如果加入语句textsize=32767;可以设定这个长度。但是如果dbms=xlsx的话,就不会出这个问题。

网上说scantext是可以自动扫描变量的最大宽度的,但是实际操作下来似乎并非如此,具体有什么作用还不知道。

尽管使用了textsize=32767;,有些变量还是会被截断。这是因为SAS在读入的时候,是预先检查excel前面的若干行来判断长度和变量类型的,所以如果特别长的值在最后几行,可能会导致没有检查到改行,从而变量长度比值要短,以至于发生了截断。这种情况就要用dbms=xlsx了。

T:SAS/ Proc SQL - 选择进入:不在:

【中文标题】T:SAS/ Proc SQL - 选择进入:不在:【英文标题】:T:SAS/ Proc SQL - select into: not in: 【发布时间】:2018-11-08 20:18:47 【问题描述】:

我目前有一个 proc 内容数据文件,如下所示:

DATA CONTENTS;
    INPUT NAME $;
    DATALINES;
        VARA
        VARB
        VARC
        VARD
        VARE
    ;
RUN;

我希望将最后一个变量变成这样的宏变量

PROC SQL;
    SELECT NAME INTO: MACRO_VARIABLE
        SEPARATED BY " "
            FROM CONTENTS
                WHERE VARNUM > 1
                AND
                WHERE NAME NOT IN:(VARA VARB)
;
QUIT;

我想要适应的新增功能是

Where name not in:(VarA varB)

有没有办法做到这一点,因为我的 VARA 和 VARB 是来自我的控制器页面的用户输入,我无法将它们指定为逗号分隔,因为它们稍后将在脚本中成为“group_by”变量。

编辑:

假设我的控制器中有一个宏变量

%LET group_by_variable = VARA VARB;

然后我执行相同的例程,但像这样替换宏变量

PROC SQL;
SELECT NAME INTO: MACRO_VARIABLE
    SEPARATED BY " "
        FROM CONTENTS
            WHERE VARNUM > 1
            AND
            WHERE NAME NOT IN:(&group_by_variable.)
 ;
QUIT;

【问题讨论】:

【参考方案1】:

在常规 SAS 语句中,您可以使用冒号修饰符来执行截断字符串操作。

if  NAME NOT IN: ('VARA' 'VARB')

但是在 PROC SQL(以及 WHERE 语句)中你不能。所以请改用EQT 运算符。

WHERE NAME NOT EQT 'VARA'

您不能将变量名称与IN 运算符一起使用。但看起来您并不是要引用变量名,而是要引用实际的字符串。因此,您需要在值周围添加引号。

在空格分隔的列表周围添加引号并不难。如果值之间正好有一个空格,则可以通过一个函数调用来完成。

"%sysfunc(tranwrd(VARA VARB,%str( )," "))"

如果您的姓名列表位于宏变量中,请使用compbl() 确保只有一个空格。

%let mylist=%sysfunc(compbl(&mylist));

【讨论】:

【参考方案2】:

是的,你可以做到,只是你的查询语法错误。我建议查找一些有关 SAS SQL 的指南。

首先,每个“select”语句只能有一个“where”语句。去掉第二个“where”,只剩下“and”。

其次,在 'in' 语句之后删除 ':'。

最后,在要检查的变量之间添加逗号。

PROC SQL;
    SELECT NAME INTO: MACRO_VARIABLE
        SEPARATED BY " "
            FROM CONTENTS
                WHERE VARNUM > 1
                AND
                NAME NOT IN (VARA, VARB)
;
QUIT;

如果您不能添加逗号,只需让 SAS 为您添加逗号,方法是将所有出现的空格字符替换为逗号。

PROC SQL;
    SELECT NAME INTO: MACRO_VARIABLE
        SEPARATED BY " "
            FROM CONTENTS
                WHERE VARNUM > 1
                AND
                NAME NOT IN (
                    %sysfunc(tranwrd(%quote(VARA VARB),%str( ),%str(, )))
                )
;
QUIT;

【讨论】:

嗨乔希,感谢您的回复,但我正在寻找的是一个答案,它要么告诉我没有逗号(,)是可能的,或者没有逗号是不可能的,我已将我的问题编辑得更明确 @MattMcilwham 好的,那么您可以将字符串中的空格替换为逗号。我已经编辑了我的答案以显示如何。

以上是关于SAS 程序冷知识——proc import中遇到的那些bug的主要内容,如果未能解决你的问题,请参考以下文章

Sas程序优化使用较少的工作空间

哪位能详细说明一下sas的数据分析过程?

如何在data步中调用proc

面试中会遇到的 Java 冷知识,你懂多少?

SAS的proc model语句应该怎么用

面试会遇到的15个 Java 冷知识,你知道多少?