【问题标题】:recode and add prefix to sas variables重新编码并为 sas 变量添加前缀
【发布时间】:2016-12-16 17:07:52
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你能用变量名显示前后数据吗?你在改变变量名吗?还是制作新的变量?你在改变变量值吗?如果有怎么办?例如 (1/4=1) 是什么意思?它看起来像是一个明显错误的布尔表达式。
  • 我想创建新变量,使用原始变量名称但带有前缀 (r_)。表达式 (1/4=1) 表示值 {1,2,3,4} 应重新编码为 1。变量是标量 [1,2,3,4,5],我想重新编码 4和 5 到 1 和 1,2,3 到 0。
  • 为什么要重新编码变量?为什么不给变量附加一个格式?
  • 我不知道这意味着什么,但我想计算它们的平均值,而且我通常更简单地生成重新编码的变量(这就是我在 R、Stata 和 SPSS 中所做的) .

标签: macros sas recode


【解决方案1】:

如果您的变量使用数字后缀命名,那么 SAS 语法会更容易。也就是说,如果您有 10 个变量名称分别为 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 ;

【讨论】:

  • 最后一个代码块中使用的 & 是什么?
  • 这是您引用由 PROC SQL 查询生成的宏变量的方式。 & 是宏处理器的触发器,将后面的内容视为宏变量的名称。宏变量的值将被替换为引用,并将生成的代码传递给 SAS,就像您已将其键入到源程序中一样。
  • 谢谢,我使用最后 3 个代码块来执行我需要的操作并在数组中添加内容。在 SAS 中使用这么多代码来克隆一堆变量并为它们添加前缀似乎很疯狂——这就是我想做的,所以也许我的解释不清楚?
  • 你能解释一下SQL块吗?我不熟悉 SAS 中的那个过程。
  • PROC SQL 只允许您使用 SQL 代码。 INTO 子句允许它生成宏变量值。您也可以只使用数据步骤将代码行写入文件并使用 %INCLUDE。在 SAS 中,您最有可能要做的就是不理会变量,只需对它们应用格式,以便在分析时即时完成重新编码。
【解决方案2】:

您可以使用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_);

【讨论】:

  • 虽然有用,但它只是重命名变量。而且每个数据集的变量数量可能会发生变化,所以我希望能够使用某种通配符。
  • 对不起,您最初的“重新编码”是什么意思并不清楚。查看更新!
  • 有什么方法可以简化解决方案?
  • 这是两个步骤,这两个步骤都是执行您要求的操作所必需的,所以不,您不能有意义地缩短它。
【解决方案3】:

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;

【讨论】:

  • copy col1; 语句有什么作用?这种情况下需要吗?
  • @Tom COL1 是在第二个转置中转置的变量。我可能应该使用 VAR 语句使其显而易见,但默认值是转置所有 _NUMERIC_ 变量。有趣的是,我不得不使用 ID 语句,虽然 _NAME_ 是默认的 ID 变量,但是当您使用 PREFIX= 时,ID 并不隐含。
  • 所以你不需要它。没有它,第一个转置创建一个只有 1 列而不是 2 列的数据集,第二个转置创建一个包含 0 个观察而不是 1 的数据集。看起来也不需要 ID 语句。至少 9.4 rel 3.
  • @tom 您似乎部分正确。我不需要一个变量来转置,但为了获得我想要 RE_oldname 的新变量名称,我确实需要 ID _NAME_;否则,它们将被命名为 RE_1-RE_6 SYSVLONG4 9.04.01M3P06242015
【解决方案4】:

编写一个宏来解析几乎完全相同的语法几乎是微不足道的。

我不一定会使用这个——我更喜欢转置和数组方法,两者都更“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_);

【讨论】:

    【解决方案5】:

    表达式 (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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-10
      • 2018-04-27
      • 1970-01-01
      相关资源
      最近更新 更多