помещать значения в файл, используя функции без создания новых переменных - PullRequest
1 голос
/ 04 марта 2020

Я обрабатываю набор данных, содержание которого я не знаю заранее. Мой целевой экземпляр SAS - 9.3, и я не могу использовать SQL, поскольку у него есть определенные «зарезервированные» имена (например, «user»), которые нельзя использовать в качестве имен столбцов.

Пазл выглядит так:

data _null_;

  set some.dataset;  file somefile;

  /* no problem can even apply formats */
  put name age;

  /* how to do this without making new vars? */
  put somefunc(name) max(age);

run;

Я не могу поставить var1=somefunc(name); put var1;, так как это может означать sh с исходной переменной с именем var1.

Я предполагаю, что ответ состоит в том, чтобы сделать некоторую функцию макроса который прочитает заголовок набора данных и вернет мне «безопасную» (не конфликтующую) переменную или функцию fcmp в формате, но я решил проверить с сообществом, есть ли какой-то «старый школьный» способ непосредственно из функции, на шаге данных?

Ответы [ 3 ]

2 голосов
/ 05 марта 2020

Временный массив?

34         data _null_;
35            set sashelp.class;
36            array _n[*] _numeric_;
37            array _f[3] _temporary_;
38            put _n_ @;
39            do _n_ = 1 to dim(_f);
40               _f[_n_] = log(_n[_n_]);
41               put _f[_n_]= @;
42               end;
43            put ;
44            run;

1 _f[1]=2.6390573296 _f[2]=4.2341065046 _f[3]=4.7229532216
2 _f[1]=2.5649493575 _f[2]=4.0342406382 _f[3]=4.4308167988
3 _f[1]=2.5649493575 _f[2]=4.1789920363 _f[3]=4.5849674787
4 _f[1]=2.6390573296 _f[2]=4.1399550735 _f[3]=4.6298627986
5 _f[1]=2.6390573296 _f[2]=4.1510399059 _f[3]=4.6298627986
6 _f[1]=2.4849066498 _f[2]=4.0483006237 _f[3]=4.4188406078
7 _f[1]=2.4849066498 _f[2]=4.091005661 _f[3]=4.4367515344
8 _f[1]=2.7080502011 _f[2]=4.1351665567 _f[3]=4.7229532216
9 _f[1]=2.5649493575 _f[2]=4.1351665567 _f[3]=4.4308167988
1 голос
/ 05 марта 2020

Оператор PUT не принимает вызов функции в качестве допустимого элемента для вывода.

Шаг DATA не выполняет столбцовые функции, как вы указали с помощью max(age) (так что было бы даже с меньшей вероятностью использовать такую ​​функцию в PUT; -)

Избегать конфликтов имен

Моя рекомендация - использовать имя переменной, которое вряд ли столкнется.

_temp_001 = somefunc(<var>);
_temp_002 = somefunc2(<var2>);
put _temp_001 _temp_002;

drop _temp_:;

или

%let tempvar = _%sysfunc(rand(uniform, 1e15),z15.);
&tempvar = somefunc(<var>);
put &tempvar;

drop &tempvar;
%symdel tempvar;

Повторное использование

Вы можете повторно назначить любую автоматическую переменную c, которая не важна для работы шаг. Некоторые вездесущие кандидаты включают в себя:

  • цифра c переменные:
    • _n_
    • _iorc_
    • _threadid_
    • _nthreads_
    • first.<any-name> (только настройка после first. logi c, связанная с оператором BY)
    • last.<any-name>
  • символьные переменные:
    • _infile_ (требуется пустой datalines;)
    • _hostname_
  • избегать
    • _file_
    • _error_
0 голосов
/ 05 марта 2020

Я думаю, что вы были бы в достаточной безопасности, выбирая несколько маловероятных имен. Простой способ создать их и сделать код несколько читабельным - просто набрать строку sh, чтобы создать допустимое имя SAS-переменной, и использовать ссылку на макрос, чтобы сделать код читабельным. Примерно так:

%macro get_low_collision_varname(iSeed=);
  %local try cnt result;  
  %let cnt = 0;
  %let result = ;
  %do %while ("&result" eq "");
    %let try = %sysfunc(md5(&iSeed&cnt),hex32.);
    %if %sysfunc(anyalpha(%substr(&try,1,1))) gt 0 %then %do;
      %let result = &try;
    %end;
    %let cnt = %eval(&cnt + 1);
  %end;  
  &result
%mend;

Приведенный выше код берет начальную строку и просто добавляет число в конец. Он повторяет число до тех пор, пока не получит действительное имя SAS-переменной в качестве вывода из функции md5 (). Вы даже можете проверить имя целевого набора данных, чтобы убедиться, что переменная еще не существует. Если он встроит эту логику c в вышеуказанную функцию.

Протестируйте ее:

%let my_var = %get_low_collision_varname(iSeed=this shouldnt collide);    
%put &my_var;

data _null_;
  set sashelp.class;
  &my_var = 1;
  put _all_;
run;

Результаты:

Name=Alfred Sex=M Age=14 Height=69 Weight=112.5 C34FD80ED9E856160E59FCEBF37F00D2=1 _ERROR_=0 _N_=1
Name=Alice Sex=F Age=13 Height=56.5 Weight=84 C34FD80ED9E856160E59FCEBF37F00D2=1 _ERROR_=0 _N_=2

Это не отвечает конкретно на вопрос о том, как этого добиться, не создавая новые имена, но это дает практический обходной путь.

...