How do I simplify the below statements with a loop in SAS? - sas

I need to repeat the below proc sort from int1 to int10. What is an efficient way to code this?
Proc sort data=sourceh.average_metric_Jan2009_int1;
by time rank;
run;
Proc sort data=sourceh.average_metric_Jan2009_int2;
by time rank;
run;

You can use a %do loop inside a macro program:
%macro multisort();
%do i = 1 %to 10;
proc sort data = sourceh.average_metric_jan2009_int&i;
by time rank;
run;
%end;
%mend;
%multisort()

Depending on what you're doing after you've sorted all the datasets, it might be easier to concatenate them all together, and then sort them.
data int1_to_10 ;
set sourceh.average_metric_Jan2009_int1-sourceh.average_metric_Jan2009_int10 ;
run ;
proc sort data=int1_to_10 ;
by time rank ;
run ;

Related

running sas program for multiple parameters in loop

Very new to sas, need to perform export procedure for many datasets called data1, data2, data3 ... data10.
Is there a way to operationalize this? I've tried the following without success
LIBNAME input '/home/.../input';
LIBNAME output '/home/.../output';
%macro anynumber(number);
proc export data=input.data&number file="/home/.../output/data&number..dta" dbms=dta replace;
run;
%mend;
do i = 1 to 10;
%anynumber(i)
end;
run;
CALL EXECUTE is the recommended option but a macro loop is also a good option here.
You could loop it within the same macro as well. All options are illustrated below.
Usually when I see this type of coding though, my first thought is that someone isn't familiar with BY group processing.
data demo;
do i=1 to 10;
*make sure this string matches macro call;
str = catt('%anynumber(', i, ');');
*write records to log to check;
put str;
call execute(str);
end;
run;
Another option is a macro loop itself.
%macro loop_export(numLoops=10);
%do i=1 %to &numLoops;
%anywhere(&i);
%end;
%mend;
%loop_export(numLoops=10);
Putting them together:
%macro anynumber(number);
%do i=1 %to &number;
proc export data=input.data&number file="/home/.../output/data&i..dta" dbms=dta
replace;
run;
%end;
%mend;
*will export all 10;
%anyNumber(10);

Do loop for creating new variables in SAS

I am trying to run this code
data swati;
input facility_id$ loan_desc : $50. sys_name :$50.;
cards;
fac_001 term_loan RM_platform
fac_001 business_loan IQ_platform
fac_002 business_loan BUSES_termloan
fac_002 business_loan RM_platform
fac_003 overdrafts RM_platform
fac_003 RCF IQ_platform
fac_003 term_loan BUSES_termloan
;
proc contents data=swati out=contents(keep=name varnum);
run;
proc sort data=contents;
by varnum;
run;
data contents;
set contents ;
where varnum in (2,3);
run;
data contents;
set contents;
summary=catx('_',name, 'summ');
run;
data _null_;
set contents;
call symput ("name" || put(_n_ , 10. -L), name);
call symput ("summ" || put (_n_ , 10. -L), summary);
run;
options mlogic symbolgen mprint;
%macro swati;
%do i = 1 %to 2;
proc sort data=swati;
by facility_id &&name&i.;
run;
data swati1;
set swati;
by facility_id &&name&i.;
length &&summ&i. $50.;
retain &&summ&i.;
if first.facility_id then do;
&&summ&i.="";
end;
if first.&&name&i. = last.&&name&i. then &&summ&i.=catx(',',&&name&i., &&summ&i.);
else if first.&&name&i. ne last.&&name&i. then &&summ&i.=&&name&i.;
run;
if last.facility_id ;
%end;
%mend;
%swati;
This code will create two new variables loan_desc_summ and sys_name_summ which has values of the all the loans_desc in one line and the sys_names in one line seprated by comma example (term_loan, business_loan), (RM_platform, IQ_platform) But if a customer has only one loan_desc the loan_summ should only have its value twice.
The problem while running the do loop is that after running this code, I am getting the dataset with only the sys_name_summ and not the loan_desc_summ. I want the dataset with all the five variables facility_id, loan_desc, sys_name, loan_desc_summ, sys_name_summ.
Could you please help me in finding out if there is a problem in the do loop??
Your loop is always starting with the same input dataset (swati) and generating a new dataset (SWATI1). So only the last time through the loop has any effect. Each loop would need to start with the output of the previous run.
You also need to fix your logic for eliminating the duplicates.
For example you could change the macro to:
%macro swati;
data swati1;
set swati;
run;
%do i = 1 %to 2;
proc sort data=swati1;
by facility_id &&name&i.;
run;
data swati1;
set swati1;
by facility_id &&name&i ;
length &&summ&i $500 ;
if first.facility_id then &&summ&i = ' ' ;
if first.&&name&i then catx(',',&&summ&i,&&name&i);
if last.facility_id ;
run;
%end;
%mend;
Also your program could be a lot smaller if you just used arrays.
data want ;
set have ;
by facility_id ;
array one loan_desc sys_name ;
array two $500 loan_desc_summ sys_name_summ ;
retain loan_desc_summ sys_name_summ ;
do i=1 to dim(one);
if first.facility_id then two(i)=one(i) ;
else if not findw(two(i),one(i),',','t') then two(i)=catx(',',two(i),one(i));
end;
if last.facility_id;
drop i loan_desc sys_name ;
run;
If you want to make it more flexible you can put the list of variable names into a macro variable.
%let varlist=loan_desc sys_name;
You could then generate the list of new names easily.
%let varlist2=%sysfunc(tranwrd(&varlist,%str( ),_summ%str( )))_summ ;
Then you can use the macro variables in the ARRAY, RETAIN and DROP statements.

SAS - Sort Multiple Dataset using loops

I have a list of SAS datasets which I want to sort by the same variable.
I do not want to use the PROC Sort statement for each one of them,
is there a way to use loops to shorten the entire code?
I am new to SAS so please help!
%let prim =sasdata.qc_no_rx ;
%let other_removals = sasdata.qc_other_removals;
%let drops =sasdata.droplist;
Array data_1(3) $ sasdata.qc_no_rx sasdata.qc_other_removals
sasdata.droplist ;
do over data_1;
Proc sort data = data_1 ;
by ims_ref;
end;
Assuming you have a data set, called dname_list, with the data set names, and they're called dname. Call execute will generate the code and execute it.
I usually create my command in a string and then pass that to call execute. This is a data _null_ step so it doesn't generate a data set but you can generate the data set to test at first if necessary.
You don't need to loop because SAS loops through the records in a data set by itself.
If you're sorting data in a library make sure to include the library name as well.
data _null_;
*data dname_execute;
set dname_list;
string = catt('proc sort data=', dname, '; by age; run;');
call execute(string);
run;
This should help:
%macro multsort(indlist,outdlist,byvarlist,ndata);
%do i = 1 %to &ndata.;
%let indata = %scan("&indlist.",&i.," ");
%let outdata = %scan("&outdlist.",&i.," ");
%let byvars = %scan("&byvarlist.",&i.," ");
proc sort data = &indata. out=&outdata.;by &byvars. ;run;
%end;
%mend;
%multsort(indlist=sashelp.Air sashelp.Buy,outdlist=Sa Sb,byvarlist=Air amount,ndata=2);

loop through variables to create interaction terms

I seek to loop through variables (can be contained in a macro variable or a data set) to create a macro variable with interaction terms that I can use in a regression. Here is an example.
Let’s say the original variables are in a macro variable.
%let predictors = age sex bmi;
I seek to loop through these variables and create a macro variable that I can use in a regression.
In the first iteration, we have age. I seek to create:
% interactions = age sex bmi sex*age bmi*age
Fit a regression.
Then use sex in the next iteration.
% interactions = age sex bmi age*sex bmi*sex;
And so on. Thanks!
The model statement of many SAS PROCs supports a syntax for that. The pipe is all crossings while #2 limits the interactions to 2 way. Leave off the # for all.
proc glm data=sashelp.class;
class sex;
model age=sex|height|weight#2;
run;
quit;
Note really sure how you are using this, but a simple %do loop should handle your request.
%macro test(predictors);
%local n i j ;
%let n=%sysfunc(countw(&predictors));
%do i=1 %to &n;
%let interactions=&predictors;
%do j=1 %to &n;
%if &i^=&j %then %let interactions=
&interactions %scan(&predictors,&i)*%scan(&predictors,&j)
;
%end;
%put &=i &=interactions;
%end;
%mend ;
%test(age sex bmi);
Which produces this list to the log.
I=1 INTERACTIONS=age sex bmi age*sex age*bmi
I=2 INTERACTIONS=age sex bmi sex*age sex*bmi
I=3 INTERACTIONS=age sex bmi bmi*age bmi*sex

merge 6000 variables with the merge command line

I've got the following issue and I'm not sure on how to do this.
I'm trying to merge 6000 variables through the code below
Please find below the piece of code I've written for two of the variables
data big_aat_1;
merge Aat_1(rename=(var14=var14_t0 var28=var28_t_0))
Aat_2(rename=(var14=var14_t_1 var28=var28_t_1))
Aat_3(rename=(var14=var14_t_2 var28=var28_t_2))
Aat_4(rename=(var14=var14_t_3 var28=var28_t_3))
Aat_5(rename=(var14=var14_t_4 var28=var28_t_4))
Aat_6(rename=(var14=var14_t_5 var28=var28_t_5));
by nouv_date;
run;
My aim is to try to automate my piece of code for the 6000 variables I have and keep the way I'm doing it e.g. with the merge.
The result will all the variables would be like the one below. The ...represent the rest of the variables
data big_aat_1;
merge Aat_1(rename=(var14=var14_t0 var28=var28_t_0 var37=var37_t_0 ...))
Aat_2(rename=(var14=var14_t_1 var28=var28_t_1 var37=var37_t_1 ...))
Aat_3(rename=(var14=var14_t_2 var28=var28_t_2 var37=var37_t_2 ...))
Aat_4(rename=(var14=var14_t_3 var28=var28_t_3 var37=var37_t_3 ...))
Aat_5(rename=(var14=var14_t_4 var28=var28_t_4 var37=var37_t_4 ...))
Aat_6(rename=(var14=var14_t_5 var28=var28_t_5 var37=var37_t_5 ...));
by nouv_date;
run;
There are 2 things I need to state
1) I have a dataset / table that contains all the distinct variable names (e.g. var14, var28 ...). It would be great if I can use it. The name of the dataset is dicoAg
2) I need to keep the merge for some reasons I cannot talk about here.
If you have any insight
I started creating test data sets (you obviously already have them):
%MACRO P;
%DO I=1 %TO 6;
data aat_&I;
%DO J=1 %TO 6000;
var&J=&J;
%END;
nouv_date=1;output;
run;
%END;
%MEND;
%P;
and then I used proc contents to have a list of the variables (you can skip this step and use dicoAg):
proc contents data=aat_1 varnum out=vars;run;
and then you have sas write the rename code for you:
data _NULL_;
set vars /*dicoAg*/(where=(NAME^="nouv_date")) end=fine;
file "MyPath\Rename.sas";
if _N_=1 then do;
put '%MACRO RENAME(J=); ';
put '(rename=( ';
end;
/*intead of NAME use the variable in dicoAg which contains all the variables' names*/
put ' ' NAME '=' NAME +(-1) '_&J';
if fine then do;
put ' )) ';
put '%MEND; ';
end;
run;
you include the code:
%include "MyPath\Rename.sas";
and at the end you write the macro to do the merge:
%MACRO P;
data big_aat_1;
merge
%DO D=1 %TO 6;
aat_&D. %RENAME(J=&D)
%END;
;
by nouv_date;
run;
%MEND;
%P;
Everyone,
Without going into full details, my man-a and I did that
data big_aat_1;
merge %do j=1 %to 6 ; Aat_&j(rename=(%do i=1 %to &&&&nvar&&pays&l ; &&&&var&&pays&l.._&i=&&&&var&&pays&l.._&i.._t%eval(&j-1) %end ; )) %end ; ;
by nouv_date;
run;
Not perfect nor superbly efficient but doing the trick.
Explanation :
&&&&nvar&&pays&lis the max number of variables
&&&&var&&pays&l.._&iis the variable
The results will give you something like this
merge Aat_1(rename=( var1=var1_t0 var31=var31_t0 var60=var60_t0 var90=var90_t0 var119=var119_t0 ...
Aat_6(rename=( var1=var1_t5 var31=var31_t5 var60=var60_t5 var90=var90_t5 var119=var119_t5...
Best.