重新编码并为sas变量添加前缀

时间:2016-12-16 17:07:53

标签: macros sas recode

让我们说我有一堆变量以相同的方式命名,我想重新编码并为每个变量添加一个前缀(变量都是数字)。

在Stata中我会做类似的事情(假设变量以eq开头)

foreach var of varlist eq* {
    recode var (1/4=1) (else=0), pre(r_)
}

我如何在SAS中执行此操作?我想使用%DO宏,但我不熟悉它们(我想避免使用SQL)。如果你能包含解释每一步的评论,我将不胜感激!

5 个答案:

答案 0 :(得分:2)

如果使用数字后缀命名变量,

SAS语法会更容易。也就是说,如果您有十个变量名称为eq1,eq2,....,eq10,那么您可以使用变量列表来定义两组变量。

有很多方法可以翻译您的重新编码逻辑。如果我们假设你有干净的变量,那么我们可以使用布尔表达式来生成0/1结果。因此,如果4和5映射到1而其余映射为0,则可以使用x in (4,5)x > 3作为布尔表达式。

data want;
  set have;
  array old eq1-eq10 ;
  array new r_eq1-r_eq10 ;
  do i=1 to dim(old);
    new(i) = old(i) in (4,5);
  end;
run;

如果您缺少值或其他复杂情况,您可能需要使用IF / THEN逻辑或SELECT语句,或者您可以定义可用于转换值的格式。

如果您的名称列表更随机,那么您可能需要使用某些代码生成(例如宏代码)来生成新的变量名称。

这是一种在SAS中使用eq:变量列表语法的方法,该语法类似于之前变量选择的语法。在源数据集的空(obs = 0)版本上使用PROC TRANSPOSE以获取具有与您的名称模式匹配的变量名称的数据集。

proc transpose data=have(obs=0) out=names;
  var eq: ;
run;

然后使用旧名称和新名称列表生成两个宏变量。

proc sql noprint ;
  select _name_
       , cats('r_',_name_)
    into :old_list separated by ' '
       , :new_list separated by ' '
  from names
  ;
quit;

然后,您可以在ARRAY语句中使用这两个宏变量。

  array old &old_list ;
  array new &new_list ;

答案 1 :(得分:1)

您可以使用rename和破折号指明要重命名的变量。请注意,以下内容仅重命名col个变量,而不是other变量:

data have;                                                                                                                                 
    col1=1;                                                                                                                               
    col2=2;                                                                                                                               
    col3=3;                                                                                                                               
    col5=5; 
    other=99; 
    col12=12; 
run;  


%macro recoder(dsn = , varname = , prefix = );

/*select all variables that include the string "varname"*/
/*(you can change this if you want to be more specific on the conditions that need to be met to be renamed)*/
proc sql noprint;
    select distinct name into: varnames
    separated by " "
    from dictionary.columns where memname = upcase("&dsn.") and index(name, "&varname.") > 0;
quit;

data want;
    set have;

    /*loop through that list of variables to recode*/
    %do i = 1 %to %sysfunc(countw(&varnames.)); 
    %let this_varname = %scan(&varnames., &i.);

        /*create a new variable with desired prefix based on value of old variable*/
        if &this_varname. in (1 2 3) then &prefix.&this_varname. = 0;
            else if &this_varname. in (4 5) then &prefix.&this_varname. = 1;

    %end;
run;

%mend recoder;

%recoder(dsn = have, varname = col, prefix = r_);

答案 2 :(得分:1)

PROC TRANSPOSE将为您提供变量命名方式的灵活性。

proc transpose data=have(obs=0) out=vars;
   var col1-numeric-col12;
   copy col1;
   run;
proc transpose data=vars out=revars(drop=_:) prefix=RE_;
   id _name_;
   run;
data recode;
   set have;
   if 0 then set revars;
   array c[*] col1-numeric-col12;
   array r[*] re_:;
   call missing(of r[*]);
   do _n_ = 1 to dim(c);
      if      c[_n_] in(1 2 3) then r[_n_] = 0;
      else if c[_n_] in(4 5)   then r[_n_] = 1;
      else                          r[_n_] = c[_n_];
      end;
   run;
proc print;
   run;

答案 3 :(得分:1)

编写一个宏来解析几乎那么精确的语法几乎是微不足道的。

我不一定会使用这个 - 我更喜欢转置和数组方法,两者都更像是'SASsy' (想想' pythonic'但是对于SAS) - 但这或多或少正是你在上面所做的。

首先设置数据集:

data class;
  set sashelp.class;
  age_ly = age-1;
  age_ny = age+1;
run;

然后是宏:

%macro do_count(data=, out=, prefix=, condition=, recode=, else=, var_start=);
%local dsid varcount varname rc;          *declare local for safety;

%let dsid = %sysfunc(open(&data.,i));       *open the dataset;


%let varcount = %sysfunc(attrn(&dsid,nvars)); *get the count of variables to access;

  data &out.;                                 *now start the main data step;
    set &data.;                               *set the original data set;
    %do i = 1 %to &varcount;                  *iterate over the variables;
      %let varname= %sysfunc(varname(&dsid.,&i.));   *determine the variable name;
      %if %upcase(%substr(&varname.,1,%length(&var_start.))) = %upcase(&var_start.) %then %do;                   *if it matches your pattern then recode it;
        &prefix.&varname. = ifn(&varname. &condition., &recode., &else.);   *this uses IFN - only recodes numerics.  More complicated code would work if this could be character.;
      %end;
    %end;
    %let rc = %sysfunc(close(&dsid));         *clean up after yourself;
  run;

%mend do_count;

   %do_count(data=class, out=class_r, var_start=age, condition= > 14, recode=1, else=0, prefix=p_);

答案 4 :(得分:0)

  

表达式(1/4 = 1)表示应重新编码值{1,2,3,4}   1。

也许您根本不需要制作新的变量?如果变量的值为1,2,3,4,5,并且您希望将它们视为只有两个组,则可以使用格式进行处理。

首先使用格式定义分组。

proc format ;
  value newgrp 1-4='Group 1' 5='Group 2' ;
run;

然后你可以在分析步骤中使用FORMAT语句让SAS处理你的五级变量,如果它只有两个级别。

proc freq ;
  tables eq: ;
  format eq: NEWGRP. ;
run;