DATA Step, Macro, Functions and more

problem with sas code

Accepted Solution Solved
Reply
Contributor
Posts: 38
Accepted Solution

problem with sas code

Hello guys,

 

I am writing the below macro code to increase the number of cyl, such that the cars having hp > 150, cyl starts increasing till the time it gets equal to 10. Also, i have to reflect the magnitude by which the cyl has increased. 

Problem: In each of the cyl value, 10 is getting added.

 

%macro do_loop (var1,var2);
%if &var1 > 150 %then
%do i=1%to 10%by 1;
&var2=&var2+1;
%if &var2=10 %then leave;%end;;
%mend do_loop;

 

data macro_iterloop;
set loopcars;
%do_loop(hp,cyl);
proc print data=macro_iterloop;run;

 

The dataset is attached for reference. Please help

Attachment

Accepted Solutions
Solution
a week ago
Super User
Super User
Posts: 7,401

Re: problem with sas code

Without examples how can I tell?  First write code which actually runs on one dataset, then look at how to change this to run on multiple datasets.  A quick change to my code:

%macro A (ds=,var=,oth=);
data want; set &ds.; &var.=ifn($oth. > 150,&var.=&var.+(10-&var.),&var.); run;
%mend A;
%A (ds=loopds,var=cyl,oth=hp);

And it becomes a macro.  But I started with Base SAS - which is the programming language - then I looked to see how it would be repeated, not the other way of writing macro code to try to force things.

View solution in original post


All Replies
Super User
Super User
Posts: 7,401

Re: problem with sas code

2 things, as mentioned before:

- Post test data in the form of a datastep in the post using the {i} code window.

- Macro is not needed.  From what I cans see here you doing a simple addition, so:

data want;
  set loopcars;
  cyl=ifn(hp > 150,cyl=cyl+(10-cyl),cyl);
run;

So if the condition is true, set cycl to add 10 up to 10, otherwise leave as is.  That is all thats needed (although I can't test as I will not download files and you haven't shown required output.

Also, make the Subject line a bit moore descriptive.

Contributor
Posts: 38

Re: problem with sas code

I want the code to be wriiten in macros 

as i have different sets of observations with same varibale and same task is to be done for all of them.

Solution
a week ago
Super User
Super User
Posts: 7,401

Re: problem with sas code

Without examples how can I tell?  First write code which actually runs on one dataset, then look at how to change this to run on multiple datasets.  A quick change to my code:

%macro A (ds=,var=,oth=);
data want; set &ds.; &var.=ifn($oth. > 150,&var.=&var.+(10-&var.),&var.); run;
%mend A;
%A (ds=loopds,var=cyl,oth=hp);

And it becomes a macro.  But I started with Base SAS - which is the programming language - then I looked to see how it would be repeated, not the other way of writing macro code to try to force things.

Super User
Posts: 6,938

Re: problem with sas code


atulsingh wrote:

I want the code to be wriiten in macros 

as i have different sets of observations with same varibale and same task is to be done for all of them.


First of all, you DO NOT write "code" in macros. But you can make code dynamic for easier writing:

%macro set_max(var1,var2);
if &var1 > 150 then &var2 = max(&var2,10);
%mend;

data want;
set have;
%set_max(hp,cyl)
run;

Note that no macro code is inside the macro, just data step code with dynamic variable names.

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Super User
Posts: 6,938

Re: problem with sas code

[ Edited ]

Total misunderstanding of the macro preprocessor. The macro preprocessor is for creating dynamic code, NOT for handling data!

And there is a MUCH simpler solution than tediously counting up to a value:

data want;
set have;
if hp > 150 then cyl = max(cyl,10);
run;

 

 

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
Super User
Super User
Posts: 6,500

Re: problem with sas code

[ Edited ]

You can turn on MPRINT and MLOGIC to see what is happening.  Take a look at your macro, let's reformat it so that the macro logic steps are indented, but the SAS statements that it is generating are not.  

%macro do_loop (var1,var2);
  %if &var1 > 150 %then %do i=1 %to 10 %by 1;
&var2=&var2+1;
    %if &var2=10 %then leave;
  %end; 
; 
%mend do_loop;

So now let's look at the call  

%do_loop(hp,cyl)

And step through the macro logic and see what we expect it to do.  So if &VAR1 is replaced the hp and &VAR2 is replaced with cyl we get this body of the macro. 

  %if hp> 150 %then %do i=1 %to 10 %by 1;
cyl=cyl+1;
    %if cyl=10 %then leave;
  %end;
;

So let's check the logic. So the string "hp" is always greater than the string "150" so the %DO loop will run. And the string "cyl" is never equal to the string "10" so it never leaves early.  

 

So the macro will generate 10 assignment statements and one extra null statement.

 

As to your stated requirement:

 increase the number of cyl, such that the cars having hp > 150, cyl starts increasing till the time it gets equal to 10. Also, i have to reflect the magnitude by which the cyl has increased

 

To find the number of cylinders to add you will need some subtraction. To test value of HP you will need an IF statement. 

if hp > 150 and cyl > 10 then added_cyl = 10-cyl;
else added_cyl=0;
cyl=cyl+added_cyl;

Not sure how you could change this into a macro. What is it that varies?  Your example assumed it was the variable names, but to me it makes more sense that the values 150 and 10 would be the values that vary.

%macro add_cyl(hp_cutoff,max_cyl);
if hp > &hp_cutoff and cyl > &max_cyl then added_cyl = &max_cyl-cyl;
else added_cyl=0;
cyl=cyl+added_cyl;
%mend add_cyl;

 

 

Contributor
Posts: 38

Re: problem with sas code

how the hp string will always be greater than 150. I think it will check first whether it's greater than 150 or smaller
Super User
Super User
Posts: 6,500

Re: problem with sas code


atulsingh wrote:
how the hp string will always be greater than 150. I think it will check first whether it's greater than 150 or smaller

In the macro statement 

%if hp > 150 %then ...

The letters hp are just that, the letters hp.  They have nothing to do with any dataset variable that might be named using the same string of letters.

 

A lowercase H is always greater than the digit 1 in the ASCII coding system that SAS uses to store characters so hp is always greater than 150 in the lexigraphical ordering that SAS uses to compare strings.

 

 

Contributor
Posts: 38

Re: problem with sas code

So how to refer hp to the 'hp variable in the csv dataset?

Super User
Super User
Posts: 6,500

Re: problem with sas code


atulsingh wrote:

So how to refer hp to the 'hp variable in the csv dataset?


Use normal SAS statements like:

data ... ;
  set ... .;
if hp > 150 then ...

The SAS macro processor is for generating SAS code.

Super User
Posts: 6,938

Re: problem with sas code


atulsingh wrote:
how the hp string will always be greater than 150. I think it will check first whether it's greater than 150 or smaller


You still suffer from a misunderstanding of what the macro processor is, what it does and when it does it.

The macro processor is invoked when a macro trigger (% or &) is encountered in the code while the code is read. It then produces text which is fed back to the "main" SAS interpreter for interpretation (or compilation in case of a data step). Since it does its work long before a data step runs, it has never access to the values present in the step.

Another feature of the macro processor is that it deals only with text; it has no datatype numeric. Your condition, translated to data step code, is therefore equivalent to

if "hp" > "150"

which is always true.

 

 

---------------------------------------------------------------------------------------------
Maxims of Maximally Efficient SAS Programmers
☑ This topic is SOLVED.

Need further help from the community? Please ask a new question.

Discussion stats
  • 11 replies
  • 235 views
  • 2 likes
  • 4 in conversation