【问题标题】:Deleting duplicate answers containing special characters in the survey删除调查中包含特殊字符的重复答案
【发布时间】:2023-04-02 00:32:01
【问题描述】:

您好,我正在处理以下问题。我有一项调查,您可以在其中标记几个答案并添加自己的答案。我试图获得独特的答案,以便能够计算它们的出现,例如:假设我们有 3 个答案:a、b、c。第 1 个人标记答案 a,第 2 个人标记答案 b,c,第 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,答案用逗号分隔,这就是我选择这个分隔符的原因,以统一记录。 我几乎尝试了所有方法,将 %quote 更改为 %bquote、%superq、编写 && 而不是 &&&,并且我不断收到以下错误(其他 40 个错误中的第一个):

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

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

感谢所有的建议,因为我遇到了一堵无法逾越的墙

【问题讨论】:

  • 请添加一些记录以显示您拥有的数据示例。 (可能是带有 ID 变量的假数据和像你描述的“a”、“b”、“c”这样的答案)。应该可以通过将数据转置到每个 ID-answer 的一条记录、重复数据删除然后运行 ​​PROC FREQ 来获得您所描述的内容。您不需要拆分为多个数据集。您应该能够使用 DO 循环进行转置,而不需要宏 %DO 循环。

标签: string macros sas sas-macro


【解决方案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

【讨论】:

    【解决方案2】:

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

    此外,作为一般规则,最好在非宏 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;
    

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

    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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-01-31
      • 1970-01-01
      • 1970-01-01
      • 2014-05-20
      • 2013-06-30
      • 2020-11-19
      • 1970-01-01
      相关资源
      最近更新 更多