Подтвердить что ты не робот

Макрос возвращает значение

Я создал следующий макрос. Proc power возвращает таблицу pw_cout, содержащую столбец Power. Шаг data _null_ присваивает значение в столбце Power pw_out макропеременной tpw. Я хочу, чтобы макрос возвращал значение tpw, поэтому в основной программе я могу вызвать его на шаге DATA, например:

data test;
   set tmp;
   pw_tmp=ttest_power(meanA=a, stdA=s1, nA=n1, meanB=a2, stdB=s2, nB=n2);
run;

Вот код макроса:

%macro ttest_power(meanA=, stdA=, nA=, meanB=, stdB=, nB=);


proc power; 
   twosamplemeans test=diff_satt 
   groupmeans = &meanA | &meanB 
   groupstddevs = &stdA | &stdB
   groupns = (&nA &nB)
   power = .;    
   ods output Output=pw_out;
run;

data _null_;
    set pw_out;
    call symput('tpw'=&power);
run;

&tpw
%mend ttest_power;
4b9b3361

Ответ 1

@itzy правильно указывает, почему ваш подход не будет работать. Но есть решение, поддерживающее дух вашего подхода: вам нужно создать функцию вычисления мощности uisng PROC FCMP. На самом деле, AFAIK, чтобы вызвать процедуру из функции в PROC FCMP, вам нужно обернуть вызов в макрос, так что вы почти там.

Вот ваш макрос - слегка измененный (в основном для исправления инструкции symput):

%macro ttest_power;

  proc power; 
     twosamplemeans test=diff_satt 
     groupmeans = &meanA | &meanB 
     groupstddevs = &stdA | &stdB
     groupns = (&nA &nB)
     power = .;    
     ods output Output=pw_out;
  run;

  data _null_;
      set pw_out;
      call symput('tpw', power);
  run;

%mend ttest_power;

Теперь мы создаем функцию, которая будет ее называть:

proc fcmp outlib=work.funcs.test;

  function ttest_power_fun(meanA, stdA, nA, meanB, stdB, nB);
    rc = run_macro('ttest_power', meanA, stdA, nA, meanB, stdB, nB, tpw);
    if rc = 0 then return(tpw);
    else return(.);
   endsub;

run; 

И, наконец, мы можем попробовать использовать эту функцию на шаге данных:

options cmplib=work.funcs;

data test;
   input a s1 n1 a2 s2 n2;
   pw_tmp=ttest_power_fun(a, s1, n1, a2, s2, n2);
 cards;
0 1 10 0 1 10
0 1 10 1 1 10
;
run;

proc print data=test;

Ответ 2

Вы не можете делать то, что вы пытаетесь сделать таким образом. Макросы в SAS немного отличаются от типичного языка программирования: они не являются подпрограммами, которые вы можете назвать, а скорее просто кодом, который генерирует другой код SAS, который выполняется. Поскольку вы не можете запустить proc power внутри шага данных, вы также не можете запустить этот макрос с шага данных. (Просто представьте, что вы копируете весь код внутри макроса в шаг данных - это не сработает. Это то, что делает макрос в SAS.)

Один из способов сделать то, что вы хотите, - это прочитать каждое наблюдение из tmp по одному за раз, а затем запустить proc power. Я бы сделал что-то вроде этого:

/* First count the observations */
data _null_;
  call symputx('nobs',obs);
  stop;
  set tmp nobs=obs;
run;

/* Now read them one at a time in a macro and call proc power */
%macro power;
  %do j=1 %to &nobs;
    data _null_;
       nrec = &j;
       set tmp point=nrec;
       call symputx('meanA',meanA);
       call symputx('stdA',stdA);
       call symputx('nA',nA);
       call symputx('meanB',meanB);
       call symputx('stdB',stdB);
       call symputx('nB',nB);
       stop;
    run;

   proc power; 
     twosamplemeans test=diff_satt 
     groupmeans = &meanA | &meanB 
     groupstddevs = &stdA | &stdB
     groupns = (&nA &nB)
     power = .;    
    ods output Output=pw_out;
  run;

  proc append base=pw_out_all data=pw_out; run;
 %end;
%mend;

%power;

Используя proc append, вы можете сохранить результаты каждого раунда вывода.

Я не проверял этот код, поэтому у него может быть ошибка, но этот подход будет работать.

Ответ 3

Вы можете вызвать макрос, который вызывает процедуры и т.д. (например, пример) из datastep с помощью вызова execute(), но он может немного запутаться и с трудом отлаживаться.