DATA Step, Macro, Functions and more

writing a macro to compute results for three variables

Reply
Contributor
Posts: 23

writing a macro to compute results for three variables

I want to write a macro for the following piece of code:

 


data nd;
set nd;
if in2016=1 then do;
    if road = 98 then air_a = 98; /*non*/
    else if road = 2 then air_a = 0;
end;

if road = 1 then do;
    if car_a in (10, 1) then bike_res_a = 0; /*withdrew or completed*/
end;

if car_a in (2,4) then do; * currently or deferred;
    if bike_a = 1 then bike_res_a = 0; *year12;
    else if bike_a in (2,3,4,5,6) then bike_res_a = bike_a - 1;
    else if bike_a in (7,8,9,10) then bike_res_a = 6;
    else if bike_a  =  11  then bike_res_a = 7;
    else if bike_a  in (12 13) then bike_res_a = 8;
    else if bike_a  =  14 then bike_res_a = 9;
    else if bike_a  >= 15 then bike_res_a = 0;
end;
      
run;

 

I want this to run through three times. One where there is _a, one where there is _b and one where there is _c. So I want to run through a,b,c. Just wandering how to do this in a macro?

Super User
Posts: 23,323

Re: writing a macro to compute results for three variables

You should use arrays not a macro here. 

 

https://stats.idre.ucla.edu/sas/seminars/sas-arrays/

 

Additionally you can consider using a format instead of IF/THEN statements. 

This paper has some good examples. 

 

http://www2.sas.com/proceedings/sugi30/001-30.pdf

Super User
Posts: 9,923

Re: writing a macro to compute results for three variables

Use array processing, as @Reeza already suggested.

And replace the if-then-else-if chain with a select block:

data nd;
set nd;
array bikes {3} bike_a bike_b bike_c;
array bikeres {3} bike_res_a bike_res_b bike_res_c;
if in2016=1 then do;
    if road = 98 then air_a = 98; /*non*/
    else if road = 2 then air_a = 0;
end;

if road = 1 then do;
    if car_a in (10, 1) then bike_res_a = 0; /*withdrew or completed*/
end;

if car_a in (2,4) then do; * currently or deferred;
  do i = 1 to 3;
    select (bikes{i});
      when (1) bike_res{i} = 0; *year12;
      when (2,3,4,5,6) bike_res{i} = bikes{i} - 1;
      when (7,8,9,10) bike_res{i} = 6;
      when (11) bike_res{i} = 7;
      when (12,13) bike_res{i} = 8;
      when (14) bike_res{i} = 9;
      otherwise bike_res{i} = 0;
    end; * select;
  end; * iterative do;
end;
drop i;
run;
---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
How to convert datasets to data steps
How to post code
Trusted Advisor
Posts: 1,831

Re: writing a macro to compute results for three variables

Posted in reply to KurtBremser

@KurtBremser, your code doesn't replace all   _a   variables as asked.   See lines:

 

/*-------------------------------------------------------------------------------------------------/

if in2016=1 then do;

   if road = 98 then air_a = 98; /*non*/

   else if road = 2 then air_a = 0; end;

if road = 1 then do;

   if car_a in (10, 1) then bike_res_a = 0; /*withdrew or completed*/

end;

if car_a in (2,4) then do;

/*-------------------------------------------------------------------------------------------------/

 

 

Therefore, I think it is easier to be done by a macro.

I too preffer the CASE instead IF-THEN-ELSE method.

So proposed code is:

 

%macro doit(suffix);
	if in2016=1 then do;
		if road = 98 then air&suffix. = 98; /*non*/
		else if road = 2 then air&suffix. = 0;
	end;

	if road = 1 then do;
		if car&suffix. in (10, 1) then bike_res&suffix. = 0; /*withdrew or completed*/
	end;

	if car&suffix. in (2,4) then do; * currently or deferred;
	   select (bikes&suffix.);
		  when (1) bike_res&suffix. = 0; *year12;
		  when (2,3,4,5,6) bike_res&suffix. = bikes&suffix. - 1;
		  when (7,8,9,10) bike_res&suffix. = 6;
		  when (11) bike_res&suffix. = 7;
		  when (12,13) bike_res&suffix. = 8;
		  when (14) bike_res&suffix. = 9;
		  otherwise bike_res&suffix. = 0;
	   end; * select;
	end;
%mend doit;

data nd;
set nd;
    %doit(_a);     
    %doit(_b);     
    %doit(_c); 
run;    
Super User
Posts: 9,923

Re: writing a macro to compute results for three variables

Yes, then the do loop needs to be moved out one level to cover all variables:

data nd;
set nd;
array airs {3} air_a air_b air_c;
array cars {3} car_a car_b car_c;
array bikes {3} bike_a bike_b bike_c;
array bikeres {3} bike_res_a bike_res_b bike_res_c;
do i = 1 to 3;
  in2016 = 1 then do;
    if road = 98 then airs{i} = 98; /*non*/
    else if road = 2 then airs{i} = 0;
  end;
  if road = 1 then do;
    if cars{i} in (10,1) then bikeres{i} = 0; /*withdrew or completed*/
  end;
  if car_a in (2,4) then do; * currently or deferred;
    select (bikes{i});
      when (1) bike_res{i} = 0; *year12;
      when (2,3,4,5,6) bike_res{i} = bikes{i} - 1;
      when (7,8,9,10) bike_res{i} = 6;
      when (11) bike_res{i} = 7;
      when (12,13) bike_res{i} = 8;
      when (14) bike_res{i} = 9;
      otherwise bike_res{i} = 0;
    end; * select;
  end;
end; * iterative do;
drop i;
run;
---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
How to convert datasets to data steps
How to post code
Super User
Super User
Posts: 7,938

Re: writing a macro to compute results for three variables

Just use arrays.  Take your code and replace _a with (i) and add the array statements and a DO loop.

data nd;
  set nd;
  array air air_a air_b air_c ;
  array car car_a car_b car_c ;
  array bike bike_a bike_b bike_c ;
  array bike_res bike_res_a bike_res_b bike_res_c;
  do i=1 to dim(air);
    if in2016=1 then do;
      if road = 98 then air(i) = 98; /*non*/
      else if road = 2 then air(i) = 0;
    end;

    if road = 1 then do;
      if car(i) in (10, 1) then bike_res(i) = 0; /*withdrew or completed*/
    end;

    if car(i) in (2,4) then do; * currently or deferred;
      if bike(i) = 1 then bike_res(i) = 0; *year12;
      else if bike(i) in (2,3,4,5,6) then bike_res(i) = bike(i) - 1;
      else if bike(i) in (7,8,9,10) then bike_res(i) = 6;
      else if bike(i)  =  11  then bike_res(i) = 7;
      else if bike(i)  in (12 13) then bike_res(i) = 8;
      else if bike(i)  =  14 then bike_res(i) = 9;
      else if bike(i)  >= 15 then bike_res(i) = 0;
    end;
  end;      
run;
Ask a Question
Discussion stats
  • 5 replies
  • 153 views
  • 0 likes
  • 5 in conversation