My problem has two questions:
1. Can a macro be called in a data step?
2. If so, how can I loop through in a single data step that will add a new line to the data table and use a value in the table as an input parameter to that macro?
Here is a general example of what I want to do:
ITERATION = the number of times I have gone through the loop
COMPARE = the variable used to compare with RESULT
MINVAL = the minimum possible value of VALUE; set at 0 on first iteration. On all other iterations, if RESULT[i-1] < COMPARE[i-1], then MINVAL = MINVAL[i-1]; else MINVAL = VALUE[i-1]
MAXVAL = the maximum possible value of VALUE; set at 1 on first iteration. On all other iterations, if RESULT[i-1] > COMPARE[i-1], then MAXVAL = MAXVAL[i-1]; else MAXVAL = VALUE[i-1]
VALUE = the midpoint between MINVAL and MAXVAL (derived as: MINVAL + (MAXVAL-MINVAL) / 2)
RESULT = The returned value from a macro call using VALUE as an input parameter
ITERATION | COMPARE | MINVAL | MAXVAL | VALUE | RESULT |
---|---|---|---|---|---|
1 | 0.90000 | 0 | 1 | 0.5 | 0.00088 |
2 | 0.90000 | 0 | 0.5 | 0.25 | 0.46054 |
3 | 0.90000 | 0 | 0.25 | 0.125 | 0.93546 |
4 | 0.90000 | 0.125 | 0.25 | 0.1875 | 0.75793 |
5 | 0.90000 | 0.125 | 0.1875 | 0.15625 | 0.86567 |
6 | 0.90000 | 0.125 | 0.15625 | 0.140625 | 0.90512 |
7 | 0.90000 | 0.140625 | 0.15625 | 0.1484375 | 0.88658 |
8 | 0.90000 | 0.140625 | 0.1484375 | 0.14453125 | 0.89614 |
9 | 0.90000 | 0.140625 | 0.14453125 | 0.142578125 | 0.90070 |
10 | 0.90000 | 0.142578125 | 0.14453125 | 0.143554688 | 0.89844 |
11 | 0.90000 | 0.142578125 | 0.143554688 | 0.143066406 | 0.89958 |
12 | 0.90000 | 0.142578125 | 0.143066406 | 0.142822266 | 0.90014 |
13 | 0.90000 | 0.142822266 | 0.143066406 | 0.142944336 | 0.89986 |
14 | 0.90000 | 0.142822266 | 0.142944336 | 0.142883301 | 0.90000 |
In the end, I just need the last value stored in VALUE. I don't need this data table, although it would be nice to retain to make sure that it is doing what I want it to do.
Here is my code so far. It will give me the first line, but I am at a loss as to where to go from here. I am not sure how to implement the DO loop with what I am trying to do.
/*** Find the power ***/
%macro kappa_power(rate1=,rate2=,kappa=,kappa0=,n=,alpha=0.05,sided=2);
data kappa;
p1_=&rate1.;
p_1=&rate2.;
p2_=1-p1_;
p_2=1-p_1;
pe=p1_*p_1+p2_*p_2;
p0=&kappa.*(1-pe)+pe;
p22=(p0-p1_+p_2)/2;
p11=p0-p22;
p12=p1_-p11;
p21=p_1-p11;
A=(p11*((1-pe)-(p1_+p_1)*(1-p0))**2)+(p22*((1-pe)-(p2_+p_2)*(1-p0))**2);
B=(1-p0)**2*(p12*(p_1+p2_)**2+p21*(p_2+p1_)**2);
C=(p0*pe-2*pe+p0)**2;
Q=(1-pe)**-4*(A+B-C);
output;
call symputx("Q1",Q);
run;
data kappa0;
set kappa (keep=p1_ p_1 p2_ p_2 pe);
p0=&kappa0.*(1-pe)+pe;
p22=(p0-p1_+p_2)/2;
p11=p0-p22;
p12=p1_-p11;
p21=p_1-p11;
A=(p11*((1-pe)-(p1_+p_1)*(1-p0))**2)+(p22*((1-pe)-(p2_+p_2)*(1-p0))**2);
B=(1-p0)**2*(p12*(p_1+p2_)**2+p21*(p_2+p1_)**2);
C=(p0*pe-2*pe+p0)**2;
Q=(1-pe)**-4*(A+B-C);
output;
call symputx("Q0",Q);
run;
%global power;
data _null_;
Zb=(((&kappa.-&kappa0.)*sqrt(&n.)) - (quantile('NORMAL',1-(&alpha./&sided.))*sqrt(&Q0.))) / sqrt(&Q1.);
power=probnorm(Zb);
call symputx("power",power);
run;
%put Power = &power.;
%mend kappa_power;
data iteration;
i=1;
phat=.90000;
minkap=0;
maxkap=1;
kappa0=minkap+(maxkap-minkap)/2;
output;
run;
proc sql;
select kappa0 into :kappa0 from iteration having i=max(i);
quit;
%kappa_power(rate1=0.8,rate2=0.8,kappa=0.375,kappa0=&kappa0.,n=200,alpha=0.05,sided=1);
data power;
i=1;
power=&power.;
run;
data converge;
merge iteration power;
by i;
run;
You're doing a binomial search for maximum power?
I think something like the following would work, it's only sketched out, but hopefully gives you an idea. I have to actually do some work today :smileyconfused:
Given the code you already have I think it would work, but wasn't sure how to reset the parameters for each iteration in the loop based on your data, mostly because I don't have time...
I also added in a maxiteration so you don't loop forever and good for testing. There's also a while condition to test when you get close enough to a value to determine when to stop.
Good luck.
%macro kappa_power(rate1=,rate2=,kappa=,kappa0=,n=,alpha=0.05,sided=2, maxiter=20);
%do i=1 %to &maxiter %while (error bounds here);
%if &i=1 %then %do;
data iteration;
i=1;
phat=.90000;
minkap=0;
maxkap=1;
kappa0=minkap+(maxkap-minkap)/2;
run;
%end;
%else %do;
data iteration;
i=&i;
*determine new testing value here/macro parameters here;
run;
%end;
data kappa;
p1_=&rate1.;
p_1=&rate2.;
p2_=1-p1_;
p_2=1-p_1;
pe=p1_*p_1+p2_*p_2;
p0=&kappa.*(1-pe)+pe;
p22=(p0-p1_+p_2)/2;
p11=p0-p22;
p12=p1_-p11;
p21=p_1-p11;
A=(p11*((1-pe)-(p1_+p_1)*(1-p0))**2)+(p22*((1-pe)-(p2_+p_2)*(1-p0))**2);
B=(1-p0)**2*(p12*(p_1+p2_)**2+p21*(p_2+p1_)**2);
C=(p0*pe-2*pe+p0)**2;
Q=(1-pe)**-4*(A+B-C);
output;
call symputx("Q1",Q);
run;
data kappa0;
set kappa (keep=p1_ p_1 p2_ p_2 pe);
p0=&kappa0.*(1-pe)+pe;
p22=(p0-p1_+p_2)/2;
p11=p0-p22;
p12=p1_-p11;
p21=p_1-p11;
A=(p11*((1-pe)-(p1_+p_1)*(1-p0))**2)+(p22*((1-pe)-(p2_+p_2)*(1-p0))**2);
B=(1-p0)**2*(p12*(p_1+p2_)**2+p21*(p_2+p1_)**2);
C=(p0*pe-2*pe+p0)**2;
Q=(1-pe)**-4*(A+B-C);
output;
call symputx("Q0",Q);
run;
data power;
Zb=(((&kappa.-&kappa0.)*sqrt(&n.)) - (quantile('NORMAL',1-(&alpha./&sided.))*sqrt(&Q0.))) / sqrt(&Q1.);
power=probnorm(Zb);
call symputx("power",power); * you may not need this as a macro variable anymore.
run;
*merge the values to get the data you need for values table;
data converge;
merge iteration power;
run;
*append for each run;
proc append base=value data=converge;
run;
%end;
%mend kappa_power;
%kappa_power(rate1=0.8,rate2=0.8,kappa=0.375,kappa0=&kappa0.,n=200,alpha=0.05,sided=1, maxiter=20);
call execute will call macro's within a datastep.
Or you can loop through using another macro.
Another option is to use a function, ie FCMP instead of a macro.
I don't see any do loop, so not sure where you're trying to iterate, in the second last datastep (data power?)
I will give you suggestions a try and see what I can come up with. I have never heard of FCMP, but I found some documentation on it that I can read up on.
I have not tried to run the DO loop in my code yet because I wasn't sure how to implement it. That's why you couldn't find it in my code.
You're doing a binomial search for maximum power?
I think something like the following would work, it's only sketched out, but hopefully gives you an idea. I have to actually do some work today :smileyconfused:
Given the code you already have I think it would work, but wasn't sure how to reset the parameters for each iteration in the loop based on your data, mostly because I don't have time...
I also added in a maxiteration so you don't loop forever and good for testing. There's also a while condition to test when you get close enough to a value to determine when to stop.
Good luck.
%macro kappa_power(rate1=,rate2=,kappa=,kappa0=,n=,alpha=0.05,sided=2, maxiter=20);
%do i=1 %to &maxiter %while (error bounds here);
%if &i=1 %then %do;
data iteration;
i=1;
phat=.90000;
minkap=0;
maxkap=1;
kappa0=minkap+(maxkap-minkap)/2;
run;
%end;
%else %do;
data iteration;
i=&i;
*determine new testing value here/macro parameters here;
run;
%end;
data kappa;
p1_=&rate1.;
p_1=&rate2.;
p2_=1-p1_;
p_2=1-p_1;
pe=p1_*p_1+p2_*p_2;
p0=&kappa.*(1-pe)+pe;
p22=(p0-p1_+p_2)/2;
p11=p0-p22;
p12=p1_-p11;
p21=p_1-p11;
A=(p11*((1-pe)-(p1_+p_1)*(1-p0))**2)+(p22*((1-pe)-(p2_+p_2)*(1-p0))**2);
B=(1-p0)**2*(p12*(p_1+p2_)**2+p21*(p_2+p1_)**2);
C=(p0*pe-2*pe+p0)**2;
Q=(1-pe)**-4*(A+B-C);
output;
call symputx("Q1",Q);
run;
data kappa0;
set kappa (keep=p1_ p_1 p2_ p_2 pe);
p0=&kappa0.*(1-pe)+pe;
p22=(p0-p1_+p_2)/2;
p11=p0-p22;
p12=p1_-p11;
p21=p_1-p11;
A=(p11*((1-pe)-(p1_+p_1)*(1-p0))**2)+(p22*((1-pe)-(p2_+p_2)*(1-p0))**2);
B=(1-p0)**2*(p12*(p_1+p2_)**2+p21*(p_2+p1_)**2);
C=(p0*pe-2*pe+p0)**2;
Q=(1-pe)**-4*(A+B-C);
output;
call symputx("Q0",Q);
run;
data power;
Zb=(((&kappa.-&kappa0.)*sqrt(&n.)) - (quantile('NORMAL',1-(&alpha./&sided.))*sqrt(&Q0.))) / sqrt(&Q1.);
power=probnorm(Zb);
call symputx("power",power); * you may not need this as a macro variable anymore.
run;
*merge the values to get the data you need for values table;
data converge;
merge iteration power;
run;
*append for each run;
proc append base=value data=converge;
run;
%end;
%mend kappa_power;
%kappa_power(rate1=0.8,rate2=0.8,kappa=0.375,kappa0=&kappa0.,n=200,alpha=0.05,sided=1, maxiter=20);
This actually makes obvious sense. I guess I was trying to avoid using the same code that I had already written (since I often try to find the power of a Kappa statistic). I suppose it won't take me long to copy and past it into a new macro and just loop through it rather than calling the macro over and over. Thank you!
Don't miss out on SAS Innovate - Register now for the FREE Livestream!
Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.