7
votes

I'm a beginner in SAS and I have the following problem.

I need to calculate counts and percents of several variables (A B C) from one dataset and save the results to another dataset. my code is:

proc freq data=mydata; tables A B C / out=data_out ; run;

the result of the procedure for each variable appears in the SAS output window, but data_out contains the results only for the last variable. How to save them all in data_out? Any help is appreciated.

5

5 Answers

5
votes

ODS OUTPUT is your answer. You can't output directly using the OUT=, but you can output them like so:

ods output OneWayFreqs=freqs;
proc freq data=sashelp.class;
  tables age height weight;
run;
ods output close;

OneWayFreqs is the one-way tables, (n>1)-way tables are CrossTabFreqs:

ods output CrossTabFreqs=freqs;
ods trace on;
proc freq data=sashelp.class;
  tables age*height*weight;
run;
ods output close;

You can find out the correct name by running ods trace on; and then running your initial proc whatever (to the screen); it will tell you the names of the output in the log. (ods trace off; when you get tired of seeing it.)

1
votes

Lots of good basic sas stuff to learn here

1) Run three proc freq statements (one for each variable a b c) with a different output dataset name so the datasets are not over written.

2) use a rename option on the out = statement to change the count and percent variables for when you combine the datasets

3) sort by category and merge all datasets together

(I'm assuming there are values that appear in in multiple variables, if not you could just stack the data sets)

data mydata;
    input a $ b $ c$;
    datalines;
r r g
g r b
b b r
r r r
g g b
b r r
;
run;

proc freq noprint data = mydata; 
    tables a / out = data_a 
    (rename = (a = category count = count_a percent = percent_a)); 
run;
proc freq noprint data = mydata; 
    tables b / out = data_b 
    (rename = (b = category count = count_b percent = percent_b)); 
run;
proc freq noprint data = mydata; 
    tables c / out = data_c 
    (rename = (c = category count = count_c percent = percent_c)); 
run;

proc sort data = data_a; by category; run;
proc sort data = data_b; by category; run;
proc sort data = data_c; by category; run;

data data_out;
    merge data_a data_b data_c;
    by category;
run;
0
votes

This is a question I've dealt with many times and I WISH SAS had a better way of doing this.

My solution has been a macro that is generalized, provide your input data, your list of variables and the name of your output dataset. I take into consideration the format/type/label of the variable which you would have to do

Hope it helps:

https://gist.github.com/statgeek/c099e294e2a8c8b5580a

/* Description: Creates a One-Way Freq table of variables including percent/count Parameters: dsetin - inputdataset varlist - list of variables to be analyzed separated by spaces dsetout - name of dataset to be created

Author: F.Khurshed Date: November 2011

*/

%macro one_way_summary(dsetin, varlist, dsetout);

proc datasets nodetails nolist;
    delete &dsetout;
quit;

*loop through variable list;
%let i=1;
%do %while (%scan(&varlist, &i, " ") ^=%str());
%let var=%scan(&varlist, &i, " ");  

%put &i &var; 

    *Cross tab;
    proc freq data=&dsetin noprint;
    table &var/ out=temp1;
    run;

    *Get variable label as name;
    data _null_;
        set &dsetin (obs=1);
        call symput('var_name', vlabel(&var.));
    run;
    %put &var_name;

    *Add in Variable name and store the levels as a text field;
    data temp2;
        keep variable value count percent;
        Variable = "&var_name";
        set temp1;
        value=input(&var, $50.);
        percent=percent/100; * I like to store these as decimals instead of numbers;
        format percent percent8.1;
        drop &var.;
    run;

    %put &var_name;
    *Append datasets;
    proc append data=temp2 base=&dsetout force;
    run;

    /*drop temp tables so theres no accidents*/
    proc datasets nodetails nolist;
        delete temp1 temp2;
    quit;

*Increment counter;
%let i=%eval(&i+1);
%end;

%mend;

%one_way_summary(sashelp.class, sex age, summary1);

proc report data=summary1 nowd;
    column variable value count percent;
    define variable/ order 'Variable';
    define value / format=$8. 'Value';
    define count/'N';
    define percent/'Percentage %';
run;
0
votes

As ever, there are lots of different ways of doing this sort of thing in SAS. Here are a couple of other options:

1. Use proc summary rather than proc freq:

proc summary data = sashelp.class;
    class age height weight;
    ways 1;
    output out = freqs;
run;

2. Use multiple table statements in a single proc freq

This is more efficient than running 3 separate proc freq statements, as SAS only has to read the input dataset once rather than 3 times:

proc freq data = sashelp.class noprint;
    table age       /out = freq_age;
    table height    /out = freq_height;
    table weight    /out = freq_weight;
run;

data freqs;
    informat age height weight count percent;
    set freq_age freq_height freq_weight;
run;
0
votes

The option STACKODS(OUTPUT) added to PROC MEANS in 9.3 makes this a much simpler task.

proc means data=have n nmiss stackods;
  ods output summary=want;
run;

| Variable | N     | NMiss |
| ------   | ----- | ----- |
|        a |     4 |     3 |
|        b |     7 |     0 |
|        c |     6 |     1 |