1

I am trying to implement a macro which will allow me to run several logistic regression models that have the same outcome but a different main explanatory variable (the covariates would be common for all models) for several datasets. I have written a scan and eval macro that scans two global variables but it's not quite working. The code is shown below:

%let numbers=5 7 8 9 10 12 13 14 16 18 19 24  26 
32 33  35 37  39  41  44 45  48 50 52 
55 56  58  66 67 68 ; 

%let list=voting national local safe street violence say free;

%macro logistic;    
%let j=1;
%let m=1;
%let first=%scan(&list,%eval(&j));
%let second=%scan(&numbers,%eval(&m));
%do %while (&first ne );
%do %while (&second ne );

proc logistic data=socialcapital&second. descending;
model depression= &first. agec married edu inc_2 inc_3 inc_4 inc_5/risklimits;
ods output ParameterEstimates=mv_model1&second._&first.;
run;

%let j=%eval(&j+1);
%let m=%eval(&m+1);
%let first=%scan(&list,%eval(&j));
%let second=%scan(&numbers,%eval(&m)); 
%end;
%end;
run;

%mend;  
%logistic;

The global variable numbers refers to the "socialcaptial" dataset that I am using. Each dataset represents a country and so each number in the "numbers" global variable refers to a dataset. The global variable list refers to the list of main explanatory variables that I want to include in the model, one main explanatory variable per model. What I am looking to get is 8 separate multivariable logistic regression results for each country.

However, it appears that the scan function is not working properly for me so I know that I have done something wrong, but I am not sure what. It seems that the macro assigns 1 variable from &list to 1 dataset from &numbers until it runs out of variables from &list and simply runs the model with just the covariates instead of running all 8 models using the dataset 5, then running all 8 models again using dataset 7, and so forth.

Basically, I have messed up something with the numbering and I am not quite sure how to proceed with this macro. I know that I can get rid of the &numbers global variable by using a "by statement" in proc logistic with a stacked dataset but I would really like to learn how to get this to work for future models where that might not be an option.

3 Answers 3

1

Maggie,

I believe the code below will do what you want. I commented out the LOGISTIC procedure and put in a PUT statement for testing, and it seems to resolve the way that I expect you think it should.

%let numbers=5 7 8 9 10 12 13 14 16 18 19 24  26 
32 33  35 37  39  41  44 45  48 50 52 
55 56  58  66 67 68 ; 

%let list=voting national local safe street violence say free;

%macro logistic;
   %let j=1;
   %let first=%scan(&list,%eval(&j));
   %do %while (&first ne );
      %let m=1;
      %let second=%scan(&numbers,%eval(&m));
      %do %while (&second ne );

        /*
         proc logistic data=socialcapital&second. descending;
         model depression= &first. agec married edu inc_2 inc_3 inc_4 inc_5/risklimits;
         ods output ParameterEstimates=mv_model1&second._&first.;
         run;
        */
         %put J=&j - M=&m - FIRST=&first - SECOND=&second;

         %let m=%eval(&m+1);
         %let second=%scan(&numbers,%eval(&m));
      %end;
      %let j=%eval(&j+1);
      %let first=%scan(&list,%eval(&j));
   %end;
   run;
%mend;

%logistic;
Sign up to request clarification or add additional context in comments.

Comments

1

Here's another way to do it: (if you end up with NUMBERS and LIST in data sets, we can alter the code to handle that too)

%let numbers=5 7 8 9 10 12 13 14 16 18 19 24  26 
 32 33  35 37  39  41  44 45  48 50 52 
 55 56  58  66 67 68 ; 

%let list=voting national local safe street violence say free;

%macro logistic(First=, Second=);    
 %Put FIRST= &first;
 %Put SECOND= &second;
 /*proc logistic data=socialcapital&second. descending;*/
 /*model depression= &first. agec married edu inc_2 inc_3 inc_4 inc_5/risklimits;*/
 /*ods output ParameterEstimates=mv_model1&second._&first.;*/
 /*run;*/

%mend logistic;  

%Macro Test;
 %do i = 1 %to %sysfunc(countw(&list));
  %Let first=%scan(&list,&i);
  %do j = 1 %to %sysfunc(countw(&numbers));
   %Let second=%scan(&numbers,&j);
   %logistic(First=&first,Second=&second)
  %end;
 %end;
%Mend test;
%test

Comments

1

Whoops, small correction. I should have used "numbers" not index "i" below.

You can do this with a macro but you also can do this in either a data step( using call execute ) or in Proc IML(with 9.22 or higher) with submit blocks nested in a loop. To get an idea please see below.

Data _Null_;
 Do numbers = 5, 7, 
                  8 to 10, 
                  12 to 14, 
                  16, 18, 19, 24, 26, 32, 
                  33 to 41 by 2, 
                  44, 45, 48, 50, 52, 55, 56, 58, 
                  66 to 68;  
   Do IndpVar = "voting", "national", "local", "safe", "street", "violence", "say", "free";
       call execute( '%Put '||strip(Indpvar)||strip(put(numbers,best.))||';');
      "Logistic Code Goes Here";
   End;
   End;
 Run;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.