BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
djbateman
Lapis Lazuli | Level 10

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

ITERATIONCOMPAREMINVALMAXVALVALUERESULT
10.90000010.50.00088
20.9000000.50.250.46054
30.9000000.250.1250.93546
40.900000.1250.250.18750.75793
50.900000.1250.18750.156250.86567
60.900000.1250.156250.1406250.90512
70.900000.1406250.156250.14843750.88658
80.900000.1406250.14843750.144531250.89614
90.900000.1406250.144531250.1425781250.90070
100.900000.1425781250.144531250.1435546880.89844
110.900000.1425781250.1435546880.1430664060.89958
120.900000.1425781250.1430664060.1428222660.90014
130.900000.1428222660.1430664060.1429443360.89986
14

0.90000

0.1428222660.1429443360.1428833010.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;

1 ACCEPTED SOLUTION

Accepted Solutions
Reeza
Super User

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);

View solution in original post

4 REPLIES 4
Reeza
Super User

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?)

djbateman
Lapis Lazuli | Level 10

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.

Reeza
Super User

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);

djbateman
Lapis Lazuli | Level 10

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!

sas-innovate-wordmark-2025-midnight.png

Register Today!

Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.


Register now!

How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 4 replies
  • 1525 views
  • 0 likes
  • 2 in conversation