2016-02-09 2 views
2

Что я хочу сделать: Мне нужно создать новые переменные для каждой метки значений переменной и выполнить некоторую перекодировку. У меня есть все метки значений, выводимые из файла SPSS (см. Образец).Создайте новые переменные из значений формата

Пример:

proc format; library = library ; 
    value SEXF 
     1 = 'Homme' 
     2 = 'Femme' ; 
    value FUMERT1F 
     0 = 'Non' 
     1 = 'Oui , occasionnellement' 
     2 = 'Oui , régulièrement' 
     3 = 'Non mais j''ai déjà fumé' ; 
    value ... (many more with different amount of levels) 

Новая переменная будет фактическим один без F и с подчеркиванием + уровень (например, уровень FUMERT1F 0 стал бы FUMERT1_0).

После этого мне нужно перекодировать переменные по этой схеме:

data ds; set ds; 
    FUMERT1_0=0; 
    if FUMERT1=0 then FUMERT1_0=1; 

    FUMERT1_1=0; 
    if FUMERT1=1 then FUMERT1_1=1; 

    FUMERT1_2=0; 
    if FUMERT1=2 then FUMERT1_2=1; 

    FUMERT1_3=0; 
    if FUMERT1=3 then FUMERT1_3=1; 
run; 

Любая помощь будет оценена :)

EDIT: Оба ответа от Джо и один из data_null_ работают, но StackOverflow выиграл «Позвольте мне привести несколько правильных ответов.

+0

Вы не объясняют, как используются метки значений? Похоже, вы делаете манекены, и SAS имеет PROC для этого. –

+0

Я использую их в proc reg, но я могу изменить свой метод для proc surveyreg с помощью класса. – Oligg

+0

Да, это то же самое, что и инструкция CLASS делает только инструкцию CLASS. –

ответ

2

Обновить, чтобы добавить _ подчеркивание до конца каждого имени. Похоже, что PROC TRANSREG не имеет значения, чтобы помещать знак подчеркивания между именем переменной и значением переменной класса, чтобы мы могли просто сделать временное переименование. Создайте имена rename name = newname, чтобы переименовать переменную класса, чтобы завершить ее под знаком подчеркивания, и переименовать их. CAT и SQL в макропеременные.

data have; 
    call streaminit(1234); 
    do caseID = 1 to 1e4; 
     fumert1 = rand('table',.2,.2,.2) - 1; 
     sex = first(substrn('MF',rand('table',.5),1)); 
     output; 
     end; 
    stop; 
    run; 
%let class=sex fumert1; 
proc transpose data=have(obs=0) out=vnames; 
    var &class; 
    run; 
proc print; 
    run; 
proc sql noprint; 
    select catx('=',_name_,cats(_name_,'_')), catx('=',cats(_name_,'_'),_name_), cats(_name_,'_') 
     into :rename1 separated by ' ', :rename2 separated by ' ', :class2 separated by ' ' 
     from vnames; 
    quit; 
%put NOTE: &=rename1; 
%put NOTE: &=rename2; 
%put NOTE: &=class2; 
proc transreg data=have(rename=(&rename1)); 
    model class(&class2/zero=none); 
    id caseid; 
    output out=design(drop=_: inter: rename=(&rename2)) design; 
    run; 
%put NOTE: _TRGIND(&_trgindn)=&_trgind; 

enter image description here


Сначала попробуйте: Глядя на код, который вы поставки и выход из Джо, я не очень понимаю необходимость форматов. Мне кажется, что вы просто хотите создать манекены для списка переменных класса. Это можно сделать с помощью TRANSREG.

data have; 
    call streaminit(1234); 
    do caseID = 1 to 1e4; 
     fumert1 = rand('table',.2,.2,.2) - 1; 
     sex = first(substrn('MF',rand('table',.5),1)); 
     output; 
     end; 
    stop; 
    run; 

proc transreg data=have; 
    model class(sex fumert1/zero=none); 
    id caseid; 
    output out=design(drop=_: inter:) design; 
    run; 
proc contents; 
    run; 
proc print data=design(obs=40); 
    run; 

enter image description here

+0

I У SAS был пророк для этого, но он никогда не использовал его и не помню, чтобы это было видно на «L before» - хорошо выглядит! – Joe

+0

Хорошо работает! Только одно: можно ли добавить знак подчеркивания между именем переменной и номером категории? – Oligg

+0

@Joe Если мой поиск архива верен, PROC TRANSREG не упоминается через 10 лет. –

1

Хорошей альтернативой вашему коду является использование proc transpose. Это не даст вам 0 в не-1 ячейках, но их достаточно легко достать. Это имеет тот недостаток, что затрудняет получение переменных в определенном порядке.

В принципе, переставьте один раз в вертикальное положение, а затем переставьте назад, используя имя старой переменной, объединенное с переменной значением в качестве нового имени переменной. Hat tip to Data null для показа этой функции в недавнем сообщении SAS-L. Если ваша версия SAS не поддерживает конкатенацию в PROC TRANSPOSE, сделайте это в шаге данных заранее.

Я показываю, используя PROC EXPAND, чтобы установить пропуски на 0, но вы можете сделать это и на шаге данных, если у вас нет ETS или если PROC EXPAND работает слишком медленно. Существуют и другие способы сделать это - включая настройку набора данных с предварительным транспозисом 0s - и если у вас есть сложный сценарий, где это необходимо, это может сделать хороший отдельный вопрос.

data have; 
    do caseID = 1 to 1e4; 
    fumert1 = rand('Binomial',.3,3); 
    sex = rand('Binomial',.5,1)+1; 
    output; 
    end; 
run; 

proc transpose data=have out=want_pre; 
    by caseID; 
    var fumert1 sex; 
    copy fumert1 sex; 
run; 

data want_pre_t; 
    set want_pre; 
    x=1; *dummy variable; 
run; 

proc transpose data=want_pre_t out=want delim=_; 
    by caseID; 
    var x; 
    id _name_ col1; 
    copy fumert1 sex; 
run; 

proc expand data=want out=want_e method=none; 
convert _numeric_ /transformin=(setmiss 0); 
run; 
+0

Спасибо! Это делает работу за то, что я хочу :) Моя идея была больше ориентирована на цикличность значений, установленных внутри формата (возможно, это возможно?), Но так как ваша работа похожа на очарование, я сохраню это. – Oligg

+0

Вы не можете напрямую получить значения формата на шаге данных, нет. Есть еще пять или шесть способов сделать это - фигуры 2 было достаточно :) - но я не думаю, что вы можете сделать это исключительно на шаге данных без искажений эпического размера. Я полагаю, вы могли бы перебрать все числа и посмотреть, присваивает ли им формат значение ... но это кажется ... сложным. – Joe

1

Для этого метода необходимо использовать два понятия: cntlout набора данных из proc format и генерации кода. Этот метод, вероятно, будет быстрее, чем другой вариант, который я представил (поскольку он проходит через данные только один раз), но он полагается на переменное имя < -> формат отношений, являющийся простым. Если это не так, потребуется немного более сложная вариация; вы должны опубликовать на этом основании, и это можно изменить.

Во-первых, опция cntlout в proc format составляет набор данных в каталоге формата. Это не единственный способ сделать это, но это очень просто. Укажите соответствующее имя lib, как при создании формата, но вместо того, чтобы его создать, он выгрузит набор данных, и вы сможете использовать его для других целей.

Во-вторых, мы создаем макрос, который выполняет ваше действие один раз (создавая переменную с именем name_value, а затем присваивая ее соответствующему значению), а затем используйте proc sql, чтобы сделать кучу вызовов на этот макрос, один раз для каждого строка в вашем наборе данных cntlout. Примечание. Возможно, вам понадобится предложение where или некоторые другие модификации, если ваша библиотека форматов содержит форматы переменных, которые не находятся в вашем наборе данных, или если у нее нет хороших опрятных отношений, которые ваш пример делает. Затем мы просто делаем эти вызовы на шаге данных.

*Set up formats and dataset; 
proc format; 
    value SEXF 
     1 = 'Homme' 
     2 = 'Femme' ; 
    value FUMERT1F 
     0 = 'Non' 
     1 = 'Oui , occasionnellement' 
     2 = 'Oui , régulièrement' 
     3 = 'Non mais j''ai déjà fumé' ; 
quit; 


data have; 
    do caseID = 1 to 1e4; 
    fumert1 = rand('Binomial',.3,3); 
    sex = rand('Binomial',.5,1)+1; 
    output; 
    end; 
run; 

*Dump formats into table; 
proc format cntlout=formats; 
quit; 

*Macro that does the above assignment once; 
%macro spread_var(var=, val=); 
    &var._&val.= (&var.=&val.); *result of boolean expression is 1 or 0 (T=1 F=0); 
%mend spread_var; 

*make the list. May want NOPRINT option here as it will make a lot of calls in your output window otherwise, but I like to see them as output.; 
proc sql; 
    select cats('%spread_var(var=',substr(fmtname,1,length(Fmtname)-1),',val=',start,')') 
    into :spreadlist separated by ' ' 
    from formats; 
quit; 


*Actually use the macro call list generated above; 
data want; 
    set have; 
    &spreadlist.; 
run; 
+0

Я заблокирован в формате proc cntlout. Как я могу указать только один конкретный формат (переменную) для инструкции вместо всех моих форматов? Спасибо за помощь :) – Oligg

+0

Операция 'select' выведет вас туда, хотя в примере, который вы даете, я предполагаю, что вы хотите все форматы - или, по крайней мере, вы хотите, чтобы все форматы, подходящие для переменных в определенном наборе данных. Конечно, вы не хотите делать только по одному. Я подозреваю, что более вероятно, что вы захотите присоединиться к результату 'cntlout' с помощью словаря. Словаря или с помощью набора данных' proc content' для определения того, какие форматы вы действительно хотите. – Joe

+0

Мне нужно запустить их все сразу, а также подать одно имя переменной в макрос для другой цели (если только это не очень медленно) – Oligg

Смежные вопросы