2016-12-16 3 views
-1

Позволяет сказать, что у меня есть куча переменных, названных одинаково, и я бы хотел их перекодировать и добавить префикс для каждого (переменные все числовые).перекодировать и добавить префикс к переменным sas

В 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, то вы могли бы просто использовать списки переменных для определения обоих наборов переменных.

Существует несколько способов перевода вашей логики рекодирования. Если мы предположим, что у вас есть чистые переменные, мы можем просто использовать логическое выражение для генерации результата 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 логика или ЗЕЬЕСТ или вы могли бы определить формат, который вы могли бы использовать для преобразования значений.

Если ваш список имен более случайный, вам может потребоваться генерация новых имен переменных, например, макрокоманды.

Вот один из методов, который использует синтаксис списка переменных eq: в SAS, который раньше аналогичен синтаксису выбора вашей переменной. Используйте PROC TRANSPOSE в пустой (obs = 0) версии вашего исходного набора данных, чтобы получить набор данных с именами переменных, которые соответствуют вашему шаблону имен.

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

Так что вам это не нужно. Без него первый транспозитор создает набор данных с одним столбцом вместо 2, а второй транспозиция создает набор данных с 0 наблюдениями вместо 1. Он не похож на необходимость в заявлении идентификатора. По крайней мере, с 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; 
Смежные вопросы