2016-12-16 117 views
-1

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

在Stata我会做这样的事情(假设变量开始eq

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

我怎样才能做到这一点的SAS?我想使用%DO宏,但我不熟悉它们(我想避免SQL)。我会很感激,如果你可以包括解释每一步的评论!

+0

你可以在变量名称之前和之后显示数据吗?你在改变变量名吗?或者制作新变量?你在改变变量值吗?如果是这样如何?例如(1/4 = 1)是什么意思?它看起来像一个明显错误的布尔表达式。 – Tom

+0

我想创建新变量,使用原始变量名称但带有前缀(r_)。表达式(1/4 = 1)表示值{1,2,3,4}应重新编码为1. 变量为标量[1,2,3,4,5],我想重新编码4和5分为1和1,2,3分为0. – vashts85

+0

为什么要重新编码变量?为什么不把格式附加到变量? – Tom

回答

2

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

有很多方法可以转换您的recode逻辑。如果我们假设你有干净的变量,那么我们可以使用一个布尔表达式来生成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 ; 
+0

最后一个代码块中使用的&是什么? – vashts85

+0

这就是你如何引用由PROC SQL查询生成的宏变量。 '&'是宏处理器触发宏观变量名称后面的内容。宏变量的值将被替换为引用,并且生成的代码被传递给SAS,就好像您已经将它输入到源程序中一样。 – Tom

+0

谢谢,我使用了最后3个代码块来完成我需要的操作,并在数组中添加东西。看起来很疯狂,它需要SAS中的这么多代码克隆一堆变量并为它们添加一个前缀 - 这正是我想要做的,或许我的解释不清楚? – vashts85

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_); 
+0

虽然有用,但它只是重命名变量。而且每个数据集的变量数量可能会有所不同,所以我希望能够使用某种通配符。 – vashts85

+0

对不起,你的意思是“recode”最初并不清楚。查看更新! – superfluous

+0

我想也许你没有提交更新? – vashts85

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; 
+0

'copy col1;'语句做了什么?在这种情况下需要吗? – Tom

+0

@Tom COL1是在第二个转置中转置的变量。我可能应该使用VAR语句使其明显,但默认情况下转置所有\ _NUMERIC \ _变量。有趣的是,我不得不使用ID语句,尽管\ _NAME \ _是默认的ID变量,但是当您使用PREFIX = ID时并不是隐含的。 –

+0

所以你不需要它。没有它,第一次转置使数据集只有1列而不是2,而第二次转置使数据集有0个观察值而不是1。它看起来不需要ID语句。至少有9.4 rel 3. – Tom

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_); 
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;