0

In my data I define an array as all the variables starting with rev_:

data df;
set def;
    array vnames rev:;
run;

And now I want to repeat the means function over this array. For example, let's say each element in vnames is a different class variable i'd like part of my command.

Let's say rev: actually expands to rev1 rev2 rev3 revolution

So I want sas to do this:

proc means data=df;
var rev1;
run;

proc means data=df;
var rev2;
run;

proc means data=df;
var rev3;
run;

proc means data=df;
var revolution;
run;

Now the function I end up calling might be more complex. I thought I should set up a macro and then run the array and macro together, but I have no idea how to do this.

I don't really have any sample data, but the idea is to run the same command (or series of commands, ie a macro) over a named array.

6
  • Not clear what you mean by "means command over this array". There is a MEANS procedure (which can't run inside of a DATA step) and a MEANS function. Might help if you show sample input data and desired output. Or try proc means data=def ; var rev: ; run; Commented Feb 27, 2017 at 19:19
  • Is there some sample data in SAS EG i can call up, like mtcars? I've edited the question to show what I really want. Commented Feb 27, 2017 at 19:21
  • sashelp.class is the most used sample data. Sashelp library is full of sample datasets. That said, your edit makes the question clear. Commented Feb 27, 2017 at 19:24
  • Thank you. I'd love some help that doesn't involve some crazy SQL paramaters! Commented Feb 27, 2017 at 19:29
  • Can't help now, but will add an answer tonight if nobody has beat me to it. I see it as a generic macro language problem. You generate a list of variables from the data, then loop over that list, generating PROC steps. Commented Feb 27, 2017 at 19:32

4 Answers 4

1

Tom's answer is right if it solves your actual problem; generally, SAS provides a lot of ways to do things that don't require macros to brute force. One PROC step will undoubtedly be faster than multiple.

But, if you do need to, the answer is to look at dictionary.columns or sashelp.vcolumn or even proc contents output. Particularly since your list of rev variables is not just a numeric iterator (revolution), you can't just iterate numerically. The array you define doesn't persist past that data step, don't forget - they're data step programming tools but have no use in macro language or procs. revs: is still available in the proc of course, but vnames[1] is not.

Say your macro is:

%macro runmeans(data=, var=, out=);
  proc means data=&data.;
    var &var.;
    output out=&out. mean(&var.)=;
  run;
%mend runmeans;

Then you can do something like this:

proc sql;
  select cats('%runmeans(data=SASHELP.CLASS, var=',name,',out=M_',name,')')
     into :runmeanslist separated by ' '
     from dictionary.columns
     where libname='SASHELP' and memname='CLASS' and upcase(name) like '%EIGHT'; *weight height;
quit;

&runmeanslist.

If you don't feel comfortable in SQL, you can do the same thing in a data step using call execute and sashelp.vcolumn dataset, or proc contents output written to a file.

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

5 Comments

Can you edit your answer to give an example using something like sashelp.class?
My answer does use an example using sashelp.class.
OK I'll mark it as an answer and try to use it. It's disappointing to see how limited SAS's looping capabilities are.
@vashts85 Then I don't think you understood the answer at all. SAS has plenty of looping capabilities. It also has better ways to do things than looping, two of which you have here in answers. I still recommend Tom's answer as the primary one to use here, for example; it doesn't need to loop at all, and is the equivalent of doing something in r like indexing a vector using another vector (rather than looping through the two vectors).
Thank you, I will look at his answer closely! And I wouldn't disagree that my understanding of SAS is pretty limited :)
1

It sounds like you just want the WAYS statement in PROC MEANS. But your sample code doesn't match your description of what you want. If you really want to find the means for all numeric variables and run it separately for many different class variables then this is the code you want.

proc means data=have ;
  class rev: ;
  ways 1;
run;

3 Comments

What if the variables in the array are not tied together in any way? For example, they are test cat dog foo. How would I tell SAS to do the procs over that array?
@vashts85 Then you need some SQL or CALL SYMPUT or whatever to define the variable list in a macro variable. Obviously you need some way of defining that list or this is impossible, but whatever defines that list can be used to create a macro variable, using the dictionary.columns or other datasets as my answer describes - same general principle (just creating a macro variable to use in class statement vs. calling the whole proc).
@vashts85 You can use code generation. Either make a macro, use PROC SQL to generate code into macro variables, use a data step to generate code using CALL EXECUTE, or use a data step to generate code to a text file that you then run using %include.
0

Here's an example of using the ways in proc means to do this only once (rather than looping or multiply executing) without wildcard.

proc sql;
  select name into :varlist separated by ' '
    from dictionary.columns
    where libname='SASHELP' and memname='CLASS'
    and not (upcase(name) like '%EIGHT');
quit;

proc means data=sashelp.class;
  class &varlist.;
  ways 1;
run;

Something more like that. (I turn the class statement around here and use height/weight for VAR and class variables the non-numerics, as that makes more sense).

Comments

0

As the other answers suggest, there's probably a better way to get what you need in the larger context of your project. That being said, I thought call execute() was worth a mention as it comes close to what you were particularly looking for.

%macro SomeProc(dataset,variable);
    proc univariate data=&dataset.;
        var &variable.;
    run;
%mend SomeProc;

data _null_;
    set sashelp.Cars end=lastObs;
    array vnames[*] MPG_:;
    if lastObs then do i=1 to dim(vnames);
        call execute('%SomeProc(sashelp.Cars,'||vname(vnames[i])||')');
    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.