BookmarkSubscribeRSS Feed
monsieur
Obsidian | Level 7

Hi everyone, 

 

I've been trying to write a macro using DOSUBL to return a string so I can use it directly in DATA Step. Inside the DOSUBL block, I call another macro using CALL EXECUTE which will return 2 macro variables.

 

Here is the macro which returns 2 macro variables :

%macro Binomial_p(r,n,alpha=0.05);

/* Create data set param6 */
data param6;
	r = &r.;
    n = &n.;
    alpha = &alpha.;
    p = r/n;
	q = 1 - p;
    z = probit(1-alpha/2);
    output;
    max_idx = alpha/2;
	min_idx = 1 - alpha/2;

	do j = 0.000001 to 0.999999 by 0.00001;
		if (r > 0 and r < n) then a2 = 0.5*probbnml(j,n,r-1) + 0.5*probbnml(j,n,r);
		output;
	end;
run;

/* Create data set min & max */
proc sql;
	create table max as
	select max(j) as upper6
	from param6		
	where a2 > max_idx and r > 0 and r < n;

	create table min as
	select min(j) as lower6
	from param6		
	where a2 <= min_idx and r > 0 and r < n;
quit;

/* Store lower6 & upper6 into macro variables for future use */
%global lower6 upper6;
data ci6;
	merge param6(obs=1) min max;
	if r = 0 then do;
		lower6 = 0;
		upper6 = 1 - alpha**(1/n);
	end;
	if r = n then do;
		lower6 = alpha**(1/n);
		upper6 = 1;
	end;
	call symputx("lower6",lower6);
	call symputx("upper6",upper6);
run;

/* Delete unnecessary data sets */
proc datasets nolist; 
	delete param6 min max ci6; 
run;

%mend Binomial_p;

/*
%Binomial_p(r=81,n=263,alpha=0.05);
%put lower6=&lower6. upper6=&upper6.;
*/

 Here is the main DOSUBL block :

%macro CI_Proportion(r,n,method,alpha=0.05);

%local ci;
%let rc = %sysfunc(dosubl(%str(

data _null_;
	/* Define some values */
    r = &r.;
    n = &n.;
    alpha = &alpha.;
    p = r/n;
	q = 1 - p;
    z = probit(1-alpha/2);
	/* 6.  Binomial-based, Mid-p (Binomial_p) */
	if &method. = "Binomial_p" then do;
		call execute('%Binomial_p(r=&r.,n=&n.,alpha=&alpha.);');
		lower = &lower6.;
		upper = &upper6.;
	end;
	/* Store ci into macro variable */
	ci = strip(put(r,10.)) || " " || strip(put(p,10.4)) || "(" || strip(put(lower,10.4)) || "-" || strip(put(upper,10.4)) || ")";
	call symputx("ci",ci);
run;

)));
/* Return macro variable ci */
&ci.

%mend CI_Proportion;

%put %CI_Proportion(r=81,n=263,method="Binomial_p",alpha=0.05);

I ran into 2 errors :

ERROR 386-185: Expecting an arithmetic expression.
ERROR 200-322: The symbol is not recognized and will be ignored.
386: LINE and COLUMN cannot be determined.
WARNING: Apparent symbolic reference LOWER6 not resolved.
WARNING: Apparent symbolic reference UPPER6 not resolved.

For the second error, I think I can't use 2 macro variables after CALL EXECUTE because they don't exist yet. Is it correct ? 

For the first one, I couldn't find where is the error.

 

Thanks in advance for any input !!!

3 REPLIES 3
FriedEgg
SAS Employee
You cannot use call execute with a macro like this. You would have to run it as a dosubl also. You should really rethink your entire design here. Not good.
Tom
Super User Tom
Super User

Watch out for inteaction between local and global symbol tables when using DOSSUBL.

See this thread.

https://communities.sas.com/t5/Base-SAS-Programming/DOSUBL-scope-of-returned-macro-variables/m-p/138...

 

FriedEgg
SAS Employee

To build, somewhat, on your post from yesterday, try using PROC FCMP

 

proc fcmp;

subroutine Binomial_p(r, n, alpha, upper6, lower6);
   outargs upper6, lower6;
   p = r/n;
   q = 1 - p;
   z = probit(1-alpha/2);

   if r = 0 then do;
      lower6 = 0;
	  upper6 = 1 - alpha**(1/n);
   end;
   else if r = n then do;
      lower6 = alpha**(1/n);
	  upper6 = 1;
   end;
   else do;
      length max_idx min_idx rc j a2 8;
      max_idx = alpha/2;
      min_idx = 1 - alpha/2;
      
      declare hash h(ordered:'d');
      declare hiter hi('h');
         rc = h.definekey('j');
         rc = h.definedata('a2');
      rc = h.definedone();

      do j = 0.000001 to 0.999999 by 0.00001;
         if (r > 0 and r < n) then do;
	        a2 = 0.5*probbnml(j,n,r-1) + 0.5*probbnml(j,n,r);
		    if a2 <= a2 > max_idx then rc = h.add();
	     end;
      end;

      rc = hi.first();
      if a2 > max_idx then upper6 = j;
      rc = hi.last();
	  if a2 <= min_idx then lower6 = j;
   end;
endsub;

function CI_Proportion(r, n, method $, alpha) $;
   p = r/n;
   q = 1 - p;
   z = probit(1-alpha/2);

   length upper lower 8;
   if method = "Binomial_p" then call Binomial_p(r,n,alpha,upper,lower);

   ci = strip(put(r,10.)) || " " || strip(put(p,10.4)) || "(" || strip(put(lower,10.4)) || "-" || strip(put(upper,10.4)) || ")";
   return(ci);
endsub;

ci_proportion = CI_Proportion(81,263,"Binomial_p",0.05);
put ci_proportion=;

quit;

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 3 replies
  • 995 views
  • 0 likes
  • 3 in conversation