删除包含调查中特殊字符的重复答案

时间:2018-05-26 12:44:49

标签: string macros sas sas-macro

您好我正在处理以下问题。我有一个调查,你可以标记几个答案,也可以添加自己的答案。我试图得到唯一的答案,以便能够计算他们的出现例如:让我们假设我们有3个答案:a,b,c。人nr 1标记答案a,人nr 2标记答案b,c,人nr 3标记a,c。我想收到结果:" a"被标记了2次。要做到这一点,我试图删除重复的答案并创建一个存储这些独特答案的宏变量:a,b,c。

我已将所有调查问题重命名为v1-v& n_que。其中n_que是一个宏变量,用于保存调查中问题数量的信息。我试图将所有答案分成一个表(使用前面的例子,我会得到一个具有以下值的列):a,b,c,a,c。然后我想对这些数据进行排序并删除重复项。我尝试过以下方法:

%macro coll_ans(lib, tab);
    %do _i_ = 1 %to &n_que. %by 1;
            %global betav&_i_.;

            proc sql noprint;
                    select distinct v&_i_. into :betav&_i_. separated by ', '
                            from &lib..&tab.
                                where v&_i_. ^= ' ';
            quit;

            data a&_i_.;
                %do _j_ = 1 %to %sysfunc(countw(%quote(&&&betav&_i_.), ',')) %by 1;
                    text = %scan(%quote(&&&betav&_i_), &_j_., ',');
                    output;
                %end;
            run;
    %end;
%mend coll_ans;

值得一提的是,如果有人选择了超过1个答案,例如a和b,答案将用逗号分隔,这就是我选择此分隔符以统一记录的原因。 我已经尝试了几乎所有的东西,将%引用改为%bquote,%superq,写作&&而不是&&&并且我不断收到以下错误(其他40个人中的第一个):

 ERROR: The function NO is unknown, or cannot be accessed.

" NO"是调查中第一个问题的答案之一,完整答案是:否(转到第9个问题)。值得一提的是,整个调查都很流行,但我使用了正确的编码,所以我不相信它可能会导致一些问题(希望如此)。

我会感激所有的建议,因为我遇到了一个不可逾越的墙

2 个答案:

答案 0 :(得分:1)

猜猜你有一个类似的数据集:

data have ;
  input id v1 : $8. v2 : $8.;
  cards ;
  1 a   a
  2 b,c b
  3 a,c c
;

您可以转置数据集,使其每个ID变量值有一条记录。

data tran (keep=id VarName Value);
  set have ;
  array vars{*} v1 v2 ;
  do i=1 to dim(vars) ;
    Varname=vname(vars{i}) ;
    do j=1 to countw(vars{i},',') ;  
      Value=scan(vars{i},j,',') ;
      output ;
    end ;
  end ;
run ;

输出数据集如下所示:

id    Varname    Value

 1      v1         a
 1      v2         a
 2      v1         b
 2      v1         c
 2      v2         b
 3      v1         a
 3      v1         c
 3      v2         c

您可以使用PROC FREQ或SQL来获取计数。

proc freq data=tran ;
  tables varname*value/missing list ;
run ;

输出

Varname    Value    Frequency
v1         a               2
v1         b               1
v1         c               2
v2         a               1
v2         b               1
v2         c               1

答案 1 :(得分:0)

首先,如果您发布接收调查数据的格式会更好,因为这将决定最简单/最快的方法。

另外,作为一般规则,最好是获得输入和输入。在非宏SAS代码中输出,然后使用宏来优化过程等。以这种方式调试更容易 - 即使对于长时间使用宏的人来说......:)

那就是说,从你的Proc SQL代码看来:

一个。您在单个分隔文本字段中收到答案,例如“a,b,c”或“b,c”或“a,b,z”

*** example data;
data work.answers;
    length answer $10.;
    input answer;
    datalines;
    a,b,c
    a
    b
    b,c
    NO
    a,b,z
    n
run;

*** example valid answer entries;
data work.valid;
    length valid $10.;
    input valid;
    datalines;
    a
    b
    c
    NO
    YES
run;

湾您想要验证每个答案条目并生成计数,例如:

NO  1   
YES 0   
a   3   
b   4   
c   2   

在SAS中执行此操作的许多方法,但是为了解析标记化的文本数据,使用散列对象的重复数据删除查找表非常方便。下面的代码还会将以下内容打印到日志中以进行调试/验证...

answer=a,b,c num_answers=3 val=a val=b val=c validated=a,b,c
answer=a num_answers=1 val=a validated=a
answer=b num_answers=1 val=b validated=b
answer=b,c num_answers=2 val=b val=c validated=b,c
answer=NO num_answers=1 val=NO validated=NO
answer=a,b,z num_answers=3 val=a val=b val=z -invalid validated=a,b, validated=a,b,
answer=n num_answers=1 val=n -invalid validated=  validated= 

一旦掌握了散列对象的声明语法,它就非常合乎逻辑且相对较快。当然,您可以添加验证规则 - 例如大写和大写小写条目......

*** first, de-duplicate your lookup table. ;
proc sort data=work.valid nodupkey;
by valid;
run;

data _null_;
    length valid $10. answer_count 4. count 4. validated $10.;
    retain count 0;

    *** initialize & load hash object ;
    if _N_ = 1 then do;

        declare hash h(multidata: 'n', ordered: 'y');
        rc = h.defineKey('valid');
        rc = h.defineData('valid','count');
        rc = h.defineDone();        

        do until(eof1);
            set work.valid end=eof1;
            h.add();
        end;

    end;

    *** now process questions/answers;
    do until(eof);

        *** read each answer;       
        set answers end=eof;        
        num_answers=countw(answer);
        putlog answer= num_answers= @;

        *** parse each answer entry;
        validated=answer;
        do i=1 to num_answers;

            val=scan(answer,i);
            putlog val= @;

            *** (optional) keep track of total #answers: valid + invalid;
            answer_count+1;

            *** check answer entry in lookup table;
            rc= h.find(key:val);

            *** if entry NOT in lookup table, remove from validated answer;
            if rc ne 0 then do;
                putlog "-invalid " @;
                validated=tranwrd(validated,trim(val),' ');
            end;

            *** if answer found, increment counter in lookup table;
            else do;
                count+1;
                h.replace();
            end;

        end;    
        putlog validated=;

    end;

    *** save table of answer counts to disk;
    if eof then h.output(dataset: 'work.counts');

run;