SAS - Как пропустить определенные столбцы в цикле, используя массивы - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть набор данных, который содержит несколько числовых и символьных столбцов. Большинство столбцов символов - это простые вопросы «да» или «нет», но некоторые - нет. Для числовых столбцов я чувствую, что у меня есть правильное решение. Для столбцов символов я попытался минимизировать это, но не удалось. То, что я хочу сделать , и попытался, это цикл, который утверждает, что когда j = номер столбца var4 , тогда используйте замены Big / Small / IU. Идея состоит в том, что это сделает код менее «зависимым от переменной» из-за того, что я могу изменить переменную для var4 в операторе% let, и код будет короче по длине.

Поскольку оператор dim дает мне общее количество числовых или символьных столбцов, я предполагаю, что есть некоторый параметр, который дает мне расположение столбцов конкретной переменной, которую я использовал бы для цикла secound. Однако я не нашел такого заявления.

Мой код пока что

%let v1 = var1;
%let v2 = var2;
%let v3 = var3;
%let v4 = var4;

data have;
infile datalines delimiter = '|'; 
input surveyYear id var1 var2$ var3 var4$20. ;
datalines;
2016 |  1 |     10 |   Yes |     5 |   BIG
2016 |  2 |      6 |   YES |     8 |   Big
2016 |  3 |      8 |   YEs | 99999 |   big
2016 |  4 |      . |   yes |     5 | 99999
2017 |  5 |      6 |    No |     7 | SMALL
2017 |  6 |      5 |    Ye |     . | small
2017 |  7 |  99999 |    no |     3 | 99999
2018 |  8 |      3 | 99999 |     1 | SMall
2018 |  9 |      2 |    iu |     2 |    IU
2018 | 10 |     15 |    IU |     . |    Iu
;
run; 

data want;
set have;

    array var_num[*] _numeric_;
    do i=3 to dim(var_num);
        if var_num[i] = 99999 then var_num[i] = .;
    end;

    array var_cha[*] _character_;
    do j=1 to dim(var_cha);
        var_cha(j) = upcase(var_cha(j));
        if var_cha[j]  = 'YES'     then var_cha[j] = 'Yes';
        if var_cha[j]  = 'NO'      then var_cha[j] = 'No';
        if var_cha[j]  = 'IU'      then var_cha[j] = 'IU';
        if var_cha[j]  = '99999'   then var_cha[j] = 'IU';
        if var_cha[j]  = ''        then var_cha[j] = 'IU';
    end;
/* Integrate the code below into the loop*/
    if &v4 = 'BIG'     then &v4 = 'Big city';
    if &v4 = 'SMALL'   then &v4 = 'Small city';
    if &v4 = 'IU'      then &v4 = 'Unknow city size';
    if &v4 = '99999'   then &v4 = 'Unknow city size';

drop i j;
run;

Концептуальная идея, как я хотел бы запрограммировать его,

data want;
set have;
array var_cha[*] _character_;
    do j=1 to dim(var_cha);
        var_cha(j) = upcase(var_cha(j));
/*      All of the if statements for the yes, no and IU */

        if var_cha[j] = ColumnNumerOfVar4 then do;
        /* where ColumnNumerOfVar4 is equal to the column number of var4*/
            if var_cha[j] =  'BIG'      then var_cha[j] = 'Big city';
            if var_cha[j] =  'SMALL'    then var_cha[j] = 'Small city';
            if var_cha[j] =  'IU'       then var_cha[j] = 'Unknow city size';
            if var_cha[j] =  '99999'    then var_cha[j] = 'Unknow city size';
        end;
    end;
run;

Ответы [ 2 ]

0 голосов
/ 05 ноября 2018

Возможно, я не совсем понимаю, что вы хотите, но похоже, что вы просто хотите создать макропеременную со списком имен переменных, к которым применяется цикл DO, и использовать его для определения массива.

%let yesnovars=var4 ;
array yesno &yesnovars;

Тогда вы ДЕЛАЕТЕ цикл выглядит так:

 do j=1 to dim(yesno);
    yesno(j) = upcase(yesno(j));
    if yesno[j]  = 'YES'     then yesno[j] = 'Yes';
    if yesno[j]  = 'NO'      then yesno[j] = 'No';
    if yesno[j]  = 'IU'      then yesno[j] = 'IU';
    if yesno[j]  = '99999'   then yesno[j] = 'IU';
    if yesno[j]  = ''        then yesno[j] = 'IU';
 end;

Но похоже, что вы просто хотите применить форматы к значениям.
Поэтому, если вы определили формат $ YESNO и формат $ CITYSIZE, вы можете сделать что-то подобное, чтобы преобразовать все символьные переменные из необработанных в форматированные значения. Просто не забудьте определить их как достаточно долго, чтобы хранить отформатированные значения, а не только необработанные значения.

format var2 $yesno. var4 $citysize.;
array _c _character_;
do j=1 to dim(_c);
  _c(j)=vvalue(_c(i));
end;

Или даже лучше определить IN-форматы и использовать их при чтении необработанных данных.

0 голосов
/ 05 ноября 2018

Если вам нужно получить имя переменной в массиве, вы можете использовать функцию vName:

    if (vName(var_cha[j]) = 'var4') then do;
    /* where ColumnNumberOfVar4 is equal to the column number of var4*/
        if var_cha[j] =  'BIG'      then var_cha[j] = 'Big city';
        if var_cha[j] =  'SMALL'    then var_cha[j] = 'Small city';
        if var_cha[j] =  'IU'       then var_cha[j] = 'Unknow city size';
        if var_cha[j] =  '99999'    then var_cha[j] = 'Unknow city size';
    end;

Как я понимаю, это решит вашу проблему. Но если вы также хотите получить номер столбца определенной переменной, вы можете сделать это, либо посмотрев в sasHelp.vColumns и поместив число в макропеременную. Или сделайте что-то подобное в начале вашего шага данных:

retain columnNumberOfVar4;
if (_n_ eq 1) then do;
    id = open("work.have","i");
    num = attrn(id,"nvars");
    columnNumberOfVar4 = varNum(id, 'var4');
    rc = close(id);
end;

Но я считаю, что это не то, что вам нужно делать в вашем случае.

...