Lesson 7, Part 1: Reporting Procedures¶

In Base SAS, many procedures create reports. Here are a few of those procedures. One pertinent question is whether you need a detailed report or a summary report.

Detail Reports¶
  • PROC PRINT
  • PROC REPORT
  • PROC SQL

Detailed tabular reports have a report row for every observation in the data set or every observation in a subset of data.

Summary Tabular Reports¶
  • PROC FREQ
  • PROC TABULATE
  • PROC MEANS
  • PROC SUMMARY
  • PROC SQL

Summary tabular reports have a report row for a group of observations in the data set or a group of observations in a subset.

PROC MEANS¶

  • produces summary report with descriptive statistics
  • can include the VAR statement that identifies the (numeric) analysis variable (or variables whose statistics need to be comouted) and their in the output
  • can include classification variables (character or numeric) whose values define subgroups
    • classification variables have few discrete values
    • the data set does not need to be sorted or indexed by classification variables
In [1]:
*Ex1_proc_summary_proc_means_sum.sas (Part 1);
proc means data=sashelp.heart; 
class BP_status;
var weight;
run;
SAS Output

The SAS System

The MEANS Procedure

Analysis Variable : Weight
Blood Pressure Status N Obs N Mean Std Dev Minimum Maximum
High 2267 2265 161.8463576 29.6554011 71.0000000 300.0000000
Normal 2143 2141 149.1676787 26.7094684 67.0000000 276.0000000
Optimal 799 797 138.7202008 24.0523561 82.0000000 226.0000000
In [ ]:
%put %sysfunc(pathname(SASHELP));
  • N Obs - the number of observations with each unique combination of class variables
  • N - the number of observations with nonmissing values of the analysis variable or variables
  • The default statisrics include mean, standard deviation, minimum value and maximum value
In [2]:
*Ex1_proc_summary_proc_means_sum.sas (Part 1);
proc means data=sashelp.heart /*sum MEAN MEDIAN Q1 P25 maxdec=2*/; 
class BP_status;
var weight;
run;
SAS Output

The SAS System

The MEANS Procedure

Analysis Variable : Weight
Blood Pressure Status N Obs N Mean Std Dev Minimum Maximum
High 2267 2265 161.8463576 29.6554011 71.0000000 300.0000000
Normal 2143 2141 149.1676787 26.7094684 67.0000000 276.0000000
Optimal 799 797 138.7202008 24.0523561 82.0000000 226.0000000

You can use options in the PROC MEANS statement to request specific statistics, and the requested statistics override the default statistics.

The statistic keywords include

  • Descriptive statistic keywords (MEAN, MODE, SUM, SUMWGT, STDERR STDDEV, VAR)
  • Quantile statistic keywords (MEDIAN|P50, P1, P5, P10, Q1|P25, Q3|P75, P95, P99, QRANGE)
  • Hypothesis testing keywords (PROBT, T)
In [1]:
proc means data=sashelp.class mean std Q1 Median Q3;
   var weight;
run;
SAS Connection established. Subprocess id is 9896

Out[1]:
SAS Output

The SAS System

The MEANS Procedure

Analysis Variable : Weight
Mean Std Dev Lower Quartile Median Upper Quartile
100.0263158 22.7739335 84.0000000 99.5000000 112.5000000

PROC MEANS¶

  • can include NOPRINT option that suppresses all displayed output

  • can include MAXDEC= option to specifiy the number of decimal places to display

  • can include NONOBS option to suppress the N Obs column

  • can include multiple OUTPUT statements to create several OUT= data sets. In that case,

    • _TYPE_ (an automatic numeric variable) is automatically created
      • tracks the level of summarization
    • _FREQ_ (an automatic numeric variable) is automatically created
      • provides the number of observations at each level of summarization
In [5]:
proc means data=sashelp.class mean std Q1 Median Q3 noprint;
   var weight;
   class sex;
    output out=work.summary 
    Mean = Mean std =std
    Q1=Q1 Median=Median Q3=Q3;
run;

proc print data=work.summary noobs;
run;
Out[5]:
SAS Output

The SAS System

Sex _TYPE_ _FREQ_ Mean std Q1 Median Q3
  0 19 100.026 22.7739 84 99.50 112.5
F 1 9 90.111 19.3839 84 90.00 102.5
M 1 10 108.950 22.7272 85 107.25 128.0

In PROC SUMMARY, you can add¶

  • CLASS statement
  • VAR statement
  • OUTPUT statement to create OUT= SAS data set
Add the AUTONAME option to the output statement for PROC SUMMARY to automatically rename the conflicting variables¶
In [15]:
*Ex1_proc_summary_proc_means_sum.sas (Part 2);
proc summary data=sashelp.heart;
     class sex BP_Status;
     var _numeric_;
     output out=work.stats 
     mean=/autoname;
run;
proc print data=stats noobs;
run;
Out[15]:
SAS Output

The SAS System

Sex BP_Status _TYPE_ _FREQ_ AgeCHDdiag_Mean AgeAtStart_Mean Height_Mean Weight_Mean Diastolic_Mean Systolic_Mean MRW_Mean Smoking_Mean AgeAtDeath_Mean Cholesterol_Mean
    0 5209 63.3030 44.0687 64.8132 153.087 85.3586 136.910 119.958 9.3665 70.5364 227.417
  High 1 2267 63.3867 46.8496 64.7137 161.846 95.8844 155.735 127.237 8.6819 70.9505 236.503
  Normal 1 2143 63.4786 42.6934 65.0058 149.168 79.8292 127.114 116.124 9.8142 70.2864 222.954
  Optimal 1 799 62.0163 39.8673 64.5789 138.720 70.3242 109.767 109.567 10.1087 68.6647 213.498
Female   2 2873 65.6547 44.0515 62.5726 141.389 84.6464 136.886 120.771 5.4069 71.5670 228.542
Male   2 2336 61.5737 44.0899 67.5674 167.466 86.2346 136.938 118.957 14.2473 69.6932 226.051
Female High 3 1186 66.3370 48.2057 62.3237 150.990 96.0590 159.181 129.983 4.0255 73.1993 240.979
Female Normal 3 1166 65.5075 42.1921 62.7199 137.313 79.6415 126.616 116.701 5.8110 69.9730 223.954
Female Optimal 3 521 61.2600 38.7562 62.8090 128.590 69.8676 109.119 108.850 7.6397 65.8235 210.373
Male High 3 1081 60.9776 45.3617 67.3314 173.779 95.6929 151.955 124.219 13.7940 68.9484 231.636
Male Normal 3 977 62.1968 43.2917 67.7321 163.292 80.0532 127.709 115.437 14.5874 70.4961 221.782
Male Optimal 3 278 62.5342 41.9496 67.9079 157.633 71.1799 110.982 110.906 14.8199 71.4091 219.331
In [4]:
*Ex1_proc_summary_proc_means_sum.sas (Part 3);
 proc summary data=sashelp.prdsale;
     var _numeric_;
     output out=want_summary(drop=_type_ _freq_) 
     sum=/autoname;
   run;
proc print data=want_summary noobs;
format _numeric_ dollar12.;
run;
Out[4]:
SAS Output

The SAS System

ACTUAL_Sum PREDICT_Sum QUARTER_Sum YEAR_Sum MONTH_Sum
$730,337 $706,295 $3,600 $2,870,640 $17,860,320
In [12]:
*Ex1_proc_summary_proc_means_sum.sas (Part 4);
proc transpose data=want_summary 
      out=t_ws (rename=(col1=Amount))
      name=Var_Sum;
run;
proc print data=t_ws noobs;
format amount dollar12.;
run;
Out[12]:
SAS Output

The SAS System

Var_Sum _LABEL_ Amount
ACTUAL_Sum Actual Sales $730,337
PREDICT_Sum Predicted Sales $706,295
QUARTER_Sum Quarter $3,600
YEAR_Sum Year $2,870,640
MONTH_Sum Month $17,860,320

Code Explanation¶

  • The CLASS statement accepts one or more classification variables.

  • If a classification variable has a missing value, SAS will eliminate the entire observation from the analysis.

  • With the CLASS statement, you can use various options that include the ORDER= option, DESCENDING option, MISSING option. See SAS® documentation for details.

  • The VAR statement accepts the analysis variable as numeric.

  • The OUTPUT statements accepts the OUT= data set and allows to specify statistics.

  • TYPE is an automatic numeric variable, which can be used to help us track the level of summarization.

  • The LEVELS options adds to OUT= data set an automatic numeric variable LEVEL. This variable contains a sequential counter of rows within a given value of TYPE.

  • The WAYS option adds to OUT= data set an automatic numeric variable WAY. Here, this variable indicates a two-way interaction between the SEX and SMOKING_STATUS CLASSIFICATION variables.

In [2]:
*Ex1B_proc_summary_sum.sas;
options nonumber nodate  ps=58 ls=90;
data heart;
 set sashelp.heart;
if status= 'Alive' then death=0;
else death=1;

if status= 'Alive' then survived =1;
else survived =0;
run;
proc summary data=heart;
   class smoking_status;
   var death survived;
   output out=count_data
      sum(death)=death_count
      sum(survived)=survived_count;
run;
proc print data=count_data; run;
SAS Output

The SAS System

Obs Smoking_Status _TYPE_ _FREQ_ death_count survived_count
1   0 5173 1971 3202
2 Heavy (16-25) 1 1046 443 603
3 Light (1-5) 1 579 187 392
4 Moderate (6-15) 1 576 213 363
5 Non-smoker 1 2501 891 1610
6 Very Heavy (> 25) 1 471 237 234
In [30]:
proc summary data=heart;
   class sex smoking_status;
   var weight;
   output out=stats
      mean=meanWEIGHT/ levels ways;
run;
proc print data=stats; run;
Out[30]:
SAS Output

Relative Risk, and Odds Ratio Calculations

Obs Sex Smoking_Status _WAY_ _TYPE_ _LEVEL_ _FREQ_ meanWEIGHT
1     0 0 1 5173 153.088
2   Heavy (16-25) 1 1 1 1046 154.763
3   Light (1-5) 1 1 2 579 146.766
4   Moderate (6-15) 1 1 3 576 144.586
5   Non-smoker 1 1 4 2501 153.742
6   Very Heavy (> 25) 1 1 5 471 164.081
7 Female   1 2 1 2856 141.422
8 Male   1 2 2 2317 167.460
9 Female Heavy (16-25) 2 3 1 339 136.086
10 Female Light (1-5) 2 3 2 422 140.610
11 Female Moderate (6-15) 2 3 3 340 131.649
12 Female Non-smoker 2 3 4 1682 144.800
13 Female Very Heavy (> 25) 2 3 5 73 138.431
14 Male Heavy (16-25) 2 3 6 707 163.719
15 Male Light (1-5) 2 3 7 157 163.274
16 Male Moderate (6-15) 2 3 8 236 163.169
17 Male Non-smoker 2 3 9 819 172.119
18 Male Very Heavy (> 25) 2 3 10 398 168.733

The FREQ procedure¶

  • can be used on categorical or ordinal variables for

    • simple frequency distributions
    • 2-way cross-tabulations
    • 3-way tabulations
  • can include the variables in the TABLES statement for which counts and percentages are needed.

In [3]:
*Ex2_PROC_FREQ_SAS;
OPTIONS nocenter nonumber nodate ps=58 ls=90;
title1 'One-Way Table';
title2 'No option on the TABLES statement';
proc freq data=sashelp.heart;
tables sex weight_status bp_status;
run;
title;
SAS Output

One-Way Table

No option on the TABLES statement

The FREQ Procedure

Sex Frequency Percent Cumulative
Frequency
Cumulative
Percent
Female 2873 55.15 2873 55.15
Male 2336 44.85 5209 100.00
Weight Status
Weight_Status Frequency Percent Cumulative
Frequency
Cumulative
Percent
Frequency Missing = 6
Normal 1472 28.29 1472 28.29
Overweight 3550 68.23 5022 96.52
Underweight 181 3.48 5203 100.00
Blood Pressure Status
BP_Status Frequency Percent Cumulative
Frequency
Cumulative
Percent
High 2267 43.52 2267 43.52
Normal 2143 41.14 4410 84.66
Optimal 799 15.34 5209 100.00

The MISSING option in the TABLES statement¶

  • is used to tell SAS to include missing values in percentage calculations.
In [15]:
title1 'One-Way Table';
title2 'MISSING option';
proc freq data=sashelp.heart;
tables weight_status / missing;
run;
Out[15]:
SAS Output

One-Way Table

MISSING option

The FREQ Procedure

Weight Status
Weight_Status Frequency Percent Cumulative
Frequency
Cumulative
Percent
  6 0.12 6 0.12
Normal 1472 28.26 1478 28.37
Overweight 3550 68.15 5028 96.53
Underweight 181 3.47 5209 100.00
In [16]:
title1 'One-Way Table';
title2 'MISSPRINT option in the TABLES statement';
proc freq data=sashelp.heart;
tables weight_status / missing;
run;
Out[16]:
SAS Output

One-Way Table

MISSPRINT option in the TABLES statement

The FREQ Procedure

Weight Status
Weight_Status Frequency Percent Cumulative
Frequency
Cumulative
Percent
  6 0.12 6 0.12
Normal 1472 28.26 1478 28.37
Overweight 3550 68.15 5028 96.53
Underweight 181 3.47 5209 100.00
PROC FREQ¶

In the TABLES statement, use asterisk to separate variables when counts are desired for combination of variable categories.

In [17]:
title1 'Two-Way Table';
title2 ' ';
proc freq data=sashelp.heart;
tables weight_status*bp_status;
run;
Out[17]:
SAS Output

Two-Way Table

The FREQ Procedure

Frequency
Percent
Row Pct
Col Pct
Table of Weight_Status by BP_Status
Weight_Status(Weight Status) BP_Status(Blood Pressure Status)
High Normal Optimal Total
Normal
394
7.57
26.77
17.40
704
13.53
47.83
32.88
374
7.19
25.41
46.93
1472
28.29
 
 
Overweight
1839
35.34
51.80
81.19
1340
25.75
37.75
62.59
371
7.13
10.45
46.55
3550
68.23
 
 
Underweight
32
0.62
17.68
1.41
97
1.86
53.59
4.53
52
1.00
28.73
6.52
181
3.48
 
 
Total
2265
43.53
2141
41.15
797
15.32
5203
100.00
Frequency Missing = 6
PROC FREQ¶

Use a WHERE statement in the PROC FREQ step when tabulations are desired for a subgroup of observations.

In [19]:
title1 'Two-Way Table';
title2 'WHERE statement';
proc freq data=sashelp.heart;
tables weight_status*bp_status;
where sex='Male';
run;
Out[19]:
SAS Output

Two-Way Table

WHERE statement

The FREQ Procedure

Frequency
Percent
Row Pct
Col Pct
Table of Weight_Status by BP_Status
Weight_Status(Weight Status) BP_Status(Blood Pressure Status)
High Normal Optimal Total
Normal
187
8.01
29.87
17.33
317
13.58
50.64
32.45
122
5.23
19.49
43.88
626
26.82
 
 
Overweight
878
37.62
53.44
81.37
624
26.74
37.98
63.87
141
6.04
8.58
50.72
1643
70.39
 
 
Underweight
14
0.60
21.54
1.30
36
1.54
55.38
3.68
15
0.64
23.08
5.40
65
2.78
 
 
Total
1079
46.23
977
41.86
278
11.91
2334
100.00
Frequency Missing = 2

PROC FREQ¶

Use options in the TABLES statement to suppress the display of selected default statistics

  • NOROW - suppresses the dispaly the row percentages
  • NOCOL - suppresses the dispaly the column percentages
  • NOPERCENT - suppresses the percentage dispaly
  • NOFREQ - suppresses the frequency display
In [20]:
title1 'Two-Way Table';
title2 'Suppress Percent';
proc freq data=sashelp.heart;
tables weight_status*bp_status/
       norow nocol nopercent;
run;
Out[20]:
SAS Output

Two-Way Table

Suppress Percent

The FREQ Procedure

Frequency
Table of Weight_Status by BP_Status
Weight_Status(Weight Status) BP_Status(Blood Pressure Status)
High Normal Optimal Total
Normal
394
704
374
1472
Overweight
1839
1340
371
3550
Underweight
32
97
52
181
Total
2265
2141
797
5203
Frequency Missing = 6
In [21]:
title1 'Two-Way Table';
title2 'Suppress Percent & Column Percent';
proc freq data=sashelp.heart;
tables weight_status*bp_status/
       norow nocol nopercent;
run;
Out[21]:
SAS Output

Two-Way Table

Suppress Percent & Column Percent

The FREQ Procedure

Frequency
Table of Weight_Status by BP_Status
Weight_Status(Weight Status) BP_Status(Blood Pressure Status)
High Normal Optimal Total
Normal
394
704
374
1472
Overweight
1839
1340
371
3550
Underweight
32
97
52
181
Total
2265
2141
797
5203
Frequency Missing = 6
Optional statements for PROC FREQ¶
  • TABLES
  • WEIGHT

Use options in the TABLES statement when needed. Below is some of the common options.

  • LIST - displays values of multiple variables side by side rather than in tabular form.

  • CROSSLIST - displays two-way tables in column format, instead of cell format

  • CHISQ - generates chi-square statistic to test for significant differences.

  • MISSING - includes missing values in percntage calculations.

  • MISSPRINT - displays missing values in the table but excludes them in eercentage calculations.

  • NLEVELS - displays the number of levels for all variables without displaying frequency counts when _ALL_ keyword with the NOPRINT option is uses.

  • OUT= creates a SAS data set containing the output generated by the TABLES statement.

In [22]:
title1 'Two-Way Table';
title2 'LIST Option';
proc freq data=sashelp.heart;
tables weight_status*bp_status/LIST
       norow nocol nopercent;
run;
Out[22]:
SAS Output

Two-Way Table

LIST Option

The FREQ Procedure

Weight_Status BP_Status Frequency Cumulative
Frequency
Frequency Missing = 6
Normal High 394 394
Normal Normal 704 1098
Normal Optimal 374 1472
Overweight High 1839 3311
Overweight Normal 1340 4651
Overweight Optimal 371 5022
Underweight High 32 5054
Underweight Normal 97 5151
Underweight Optimal 52 5203
In [23]:
title1 'NOPRINT Option with the TABLE Statement';
title2 'Count and Percent';
proc sort data=sashelp.heart
       (where=(weight_status ne ' '))
       out=heart_x;
by weight_status; run;
proc freq data=heart_x;
 by weight_status; 
 tables bp_status/noprint out=heart_out;
run;
proc print data=heart_out; run;
Out[23]:
SAS Output

NOPRINT Option with the TABLE Statement

Count and Percent

Obs Weight_Status BP_Status COUNT PERCENT
1 Normal High 394 26.7663
2 Normal Normal 704 47.8261
3 Normal Optimal 374 25.4076
4 Overweight High 1839 51.8028
5 Overweight Normal 1340 37.7465
6 Overweight Optimal 371 10.4507
7 Underweight High 32 17.6796
8 Underweight Normal 97 53.5912
9 Underweight Optimal 52 28.7293
In [24]:
* Create formats, and the example-data;
proc format;
    value weight_fmt
       1 = 'Less than 90 lbs'
       2 = '90-<120 lbs'
       3 = '120-150 lbs';
run;
Data Class;
 SET sashelp.class;
    if weight <90 THEN weight_grp =1 ;
    else if 90<=weight<120 THEN weight_grp = 2;
    else if weight >= 120 THEN weight_grp = 3;
run;
title1 'One-Way Table No ORDER= Options';
title2 ' ';
proc freq data=class; 
 tables weight_grp;
 Format weight_grp weight_fmt.;
run;
Out[24]:
SAS Output

One-Way Table No ORDER= Options

The FREQ Procedure

weight_grp Frequency Percent Cumulative
Frequency
Cumulative
Percent
Less than 90 lbs 7 36.84 7 36.84
90-<120 lbs 9 47.37 16 84.21
120-150 lbs 3 15.79 19 100.00
In [25]:
title1 'One-Way Table ORDER= Formatted';
title2 'Formatted values appearing in the ascending order';
proc freq data=class ORDER= Formatted; 
 tables weight_grp;
 Format weight_grp weight_fmt.;
run;
Out[25]:
SAS Output

One-Way Table ORDER= Formatted

Formatted values appearing in the ascending order

The FREQ Procedure

weight_grp Frequency Percent Cumulative
Frequency
Cumulative
Percent
120-150 lbs 3 15.79 3 15.79
90-<120 lbs 9 47.37 12 63.16
Less than 90 lbs 7 36.84 19 100.00
In [26]:
title1 'One-Way Table ORDER= FREQ';
title2 'Order of categories based on frquencies'; 
title3 '(the category with the highest freqency appears first)';
proc freq data=class ORDER= FREQ; 
 tables weight_grp;
 Format weight_grp weight_fmt.;
run;
 /*cancel title2 and title3 */
 title2; title3;
Out[26]:
SAS Output

One-Way Table ORDER= FREQ

Order of categories based on frquencies

(the category with the highest freqency appears first)

The FREQ Procedure

weight_grp Frequency Percent Cumulative
Frequency
Cumulative
Percent
90-<120 lbs 9 47.37 9 47.37
Less than 90 lbs 7 36.84 16 84.21
120-150 lbs 3 15.79 19 100.00
PROC FREQ¶

The WEIGHT statement names a numeric variable that provides a weight for each observation in the input data set. The WEIGHT statement is most commonly used to input cell count data. (SAS Documentation"

In [27]:
*Adapted from SAS-L ;
*Contributed by data_null - 7/19/2016;
options nonumber nodate  ps=58 ls=90;
data Have;
  input Age   Regular_cnt;
datalines;
1    2814
2    2187
26   1976
51   345
52   678
;
proc format;
   value agegrp
      0-4 ='<5 Years'
      25-30 = '25-30 Years'
      51-High = '>50 Years';
   run;
title1 'WEIGHT Statement in PROC FREQ';
proc freq data=Have;
   tables age;
   format age agegrp.;
   weight regular_cnt;
   run;
Out[27]:
SAS Output

WEIGHT Statement in PROC FREQ

The FREQ Procedure

Age Frequency Percent Cumulative
Frequency
Cumulative
Percent
<5 Years 5001 62.51 5001 62.51
25-30 Years 1976 24.70 6977 87.21
>50 Years 1023 12.79 8000 100.00

PROC FREQ¶

RELRISK requests relative risk measures for 2 X 2 tables

In [28]:
*Calculations of relative Risk using PROC FREQ;
options nonumber nodate  ps=58 ls=90;
data have;
infile datalines firstobs=2;
Label cc='Exposed to Pancreas Cancer';
input Smoking_Status $ 1-10 cc $ 12-19 count 21-23;
datalines;
12345678901234567890123
Smokers    Cases     60
Smokers    Controls 100
Nonsmokers Cases     40
Nonsmokers Controls 300
;
title1 'Relative Risk, and Odds Ratio Calculations';
proc freq data=have;
tables smoking_status*cc /nocol nopercent relrisk;
weight count;
run;
Out[28]:
SAS Output

Relative Risk, and Odds Ratio Calculations

The FREQ Procedure

Frequency
Row Pct
Table of Smoking_Status by cc
Smoking_Status cc(Exposed to Pancreas Cancer)
Cases Controls Total
Nonsmokers
40
11.76
300
88.24
340
 
Smokers
60
37.50
100
62.50
160
 
Total
100
400
500

Statistics for Table of Smoking_Status by cc

Odds Ratio and Relative Risks
Statistic Value 95% Confidence Limits
Odds Ratio 0.2222 0.1403 0.3519
Relative Risk (Column 1) 0.3137 0.2204 0.4466
Relative Risk (Column 2) 1.4118 1.2445 1.6016

Sample Size = 500

PROC FREQ¶

NLEVELS option - displays the number of levels for all variables without displaying frequency counts when _ALL_ keyword with the NOPRINT option is uses.

In [5]:
proc freq data=sashelp.class nlevels;
  tables _all_ / noprint;
run;
Out[5]:
SAS Output

The SAS System

The FREQ Procedure

Number of Variable Levels
Variable Levels
Name 19
Sex 2
Age 6
Height 17
Weight 15

PROC TABULATE¶

The TABULATE can be used to

  • display descriptive statistics (e.g., N, SUM, and Mean) in tabular format
  • produce tables in up to three dimensions
  • report multiple variables one after another hierarchically within each dimension
  • label and format the variables as well as the statistics

This procedure is appropriate for summary reports, for example, when the row collapses or summarizes data based on the group or category variables (Zender, 2008). In contrast, the PROC PRINT is appropriate for detail reports in which every observation in the data is listed.

The CLASS statement should include¶

  • categorical variables (with a limited number of categories).

The TABLE statement¶

  • can have up to three dimension expressions as well as the table options.

The order of the dimensions is page, row, and column.

  • In this example, two dimensions are specified – weight_status variable in the row dimension, and the BP_Status in the column dimension. Options can be added at the end after a ‘/’.

In this example, no options are added. This is essentially a cross-table, and the code below requested two statistics, N and ROWPCTN. See SAS Documentation for the detailed list of statistics.

In [31]:
*Ex3_proc_tabulate.sas (Part 1);
options nonumber nodate ls=132 ps=58 ;
PROC TABULATE data=sashelp.heart format=comma7. ;
  TITLE1 'Two Dimensional TABLE';
  TITLE2 'N and Row Percentage';
  CLASS weight_status BP_status;
  TABLE weight_status all, (BP_Status all)*(N rowpctn*f=6.1);
run;
Out[31]:
SAS Output

Two Dimensional TABLE

N and Row Percentage

  Blood Pressure Status All
High Normal Optimal
N RowPctN N RowPctN N RowPctN N RowPctN
Weight Status 394 26.8 704 47.8 374 25.4 1,472 100.0
Normal
Overweight 1,839 51.8 1,340 37.7 371 10.5 3,550 100.0
Underweight 32 17.7 97 53.6 52 28.7 181 100.0
All 2,265 43.5 2,141 41.1 797 15.3 5,203 100.0
In [32]:
*Ex3_proc_tabulate.sas (Part 2);
PROC TABULATE data=sashelp.heart format=comma7. ;
TITLE1 'Two Dimensional TABLE';
  TITLE2 'Variable Labels Changed and KEYLABEL Statement Added';
  CLASS weight_status BP_Status;
  KEYLABEL N='Total' rowpctn = 'Row %';
  TABLE weight_status='Body Mass Index Category' all, 
        (BP_Status='Blood Pressure Category' all)*(N rowpctn*f=6.1);
run;
Out[32]:
SAS Output

Two Dimensional TABLE

Variable Labels Changed and KEYLABEL Statement Added

  Blood Pressure Category All
High Normal Optimal
Total Row % Total Row % Total Row % Total Row %
Body Mass Index Category 394 26.8 704 47.8 374 25.4 1,472 100.0
Normal
Overweight 1,839 51.8 1,340 37.7 371 10.5 3,550 100.0
Underweight 32 17.7 97 53.6 52 28.7 181 100.0
All 2,265 43.5 2,141 41.1 797 15.3 5,203 100.0
In [33]:
*Ex3_proc_tabulate.sas (Part 3);
PROC TABULATE data=sashelp.heart format=comma7. ;
TITLE1 'Three Dimensional TABLE';
  TITLE2 'Mean Weight';
  CLASS weight_status BP_Status sex;
  VAR  weight;
  KEYLABEL N='Total'  mean = 'Mean (lbs)';
  TABLE (sex all), weight_status='Body Mass Index Category' all, 
        (BP_Status='Blood Pressure Category' all)
        *(N weight*mean);
run;
Out[33]:
SAS Output

Three Dimensional TABLE

Mean Weight

Sex Female
  Blood Pressure Category All
High Normal Optimal
Total Weight Total Weight Total Weight Total Weight
Mean (lbs) Mean (lbs) Mean (lbs) Mean (lbs)
Body Mass Index Category 207 122 387 121 252 120 846 121
Normal
Overweight 961 158 716 149 230 142 1,907 153
Underweight 18 100 61 104 37 105 116 104
All 1,186 151 1,164 137 519 129 2,869 141

Three Dimensional TABLE

Mean Weight

Sex Male
  Blood Pressure Category All
High Normal Optimal
Total Weight Total Weight Total Weight Total Weight
Mean (lbs) Mean (lbs) Mean (lbs) Mean (lbs)
Body Mass Index Category 187 144 317 146 122 145 626 145
Normal
Overweight 878 181 624 174 141 172 1,643 178
Underweight 14 128 36 123 15 122 65 124
All 1,079 174 977 163 278 158 2,334 167

Three Dimensional TABLE

Mean Weight

All
  Blood Pressure Category All
High Normal Optimal
Total Weight Total Weight Total Weight Total Weight
Mean (lbs) Mean (lbs) Mean (lbs) Mean (lbs)
Body Mass Index Category 394 132 704 132 374 128 1,472 131
Normal
Overweight 1,839 169 1,340 161 371 154 3,550 164
Underweight 32 113 97 111 52 110 181 111
All 2,265 162 2,141 149 797 139 5,203 153
In [34]:
*Ex3_proc_tabulate.sas (Part 4);
PROC TABULATE data=sashelp.heart format=comma7.;
TITLE1 'Concatenated Rows - Two Dimensional TABLES';
  TITLE2 'Mean Weight';
  CLASS weight_status sex bp_status;
  VAR  weight;
  KEYLABEL N='Total'  mean = 'Mean (lbs)';
  TABLE (sex all)*weight_status='Body Mass Index Category' all, 
         (bp_status='Blood Pressure Category' all)
             *(N weight*mean);
  run;
Out[34]:
SAS Output

Concatenated Rows - Two Dimensional TABLES

Mean Weight

  Blood Pressure Category All
High Normal Optimal
Total Weight Total Weight Total Weight Total Weight
Mean (lbs) Mean (lbs) Mean (lbs) Mean (lbs)
Sex Body Mass Index Category 207 122 387 121 252 120 846 121
Female Normal
Overweight 961 158 716 149 230 142 1,907 153
Underweight 18 100 61 104 37 105 116 104
Male Normal 187 144 317 146 122 145 626 145
Overweight 878 181 624 174 141 172 1,643 178
Underweight 14 128 36 123 15 122 65 124
All Body Mass Index Category 394 132 704 132 374 128 1,472 131
Normal
Overweight 1,839 169 1,340 161 371 154 3,550 164
Underweight 32 113 97 111 52 110 181 111
All 2,265 162 2,141 149 797 139 5,203 153
In [4]:
*Ex4_Multilabel_Format.sas (Part 1);
options nodate nonumber;
proc format ;
 value m_agefmt (multilabel notsorted)
              low-34 = '25-34 Years'
              35-44 = '35-44 Years'
              45-54 = '45-54 Years'
              55-64 = '55-64 Years'
              low-49= '25-49 Years'
              50-64 ='50-64 Years';

    value m_agefmt_x (multilabel)
              low-34 = '25-34 Years'
              35-44 = '35-44 Years'
              45-54 = '45-54 Years'
              55-64 = '55-64 Years'
              low-49= '25-49 Years'
              50-64 ='50-64 Years';

proc tabulate data=sashelp.heart;
  class AgeAtStart/mlf preloadfmt order=data;  
  var AgeAtdeath;
  table AgeAtStart all, 
    n*format=5.0 all*(AgeAtdeath)*mean*format=4.1;
  Format AgeAtStart m_agefmt.;
  title1 'Value m_agefmt (multilabel notsorted)';
  title2 ' Class AgeAtStart/mlf preloadfmt order=data';
run;
SAS Output

Value m_agefmt (multilabel notsorted)

Class AgeAtStart/mlf preloadfmt order=data

  N All
Age at Death
Mean
Age at Start 850 55.2
25-34 Years
35-44 Years 1960 62.6
45-54 Years 1614 71.7
55-64 Years 785 78.6
25-49 Years 3618 64.1
50-64 Years 1591 76.3
All 5209 70.5
In [36]:
*Ex4_Multilabel_Format.sas (Part 2);
proc tabulate data=sashelp.heart;
  class AgeAtStart/mlf;  
  var AgeAtdeath;
  table AgeAtStart all, 
    n*format=5.0 all*(AgeAtdeath)*mean*format=4.1;
  Format AgeAtStart m_agefmt_x.;
  title1 'Value m_agefmt (multilabel)';
  title2 'Class AgeAtStart/mlf';
run;
Out[36]:
SAS Output

Value m_agefmt (multilabel)

Class AgeAtStart/mlf

  N All
Age at Death
Mean
Age at Start 850 55.2
25-34 Years
25-49 Years 3618 64.1
35-44 Years 1960 62.6
45-54 Years 1614 71.7
50-64 Years 1591 76.3
55-64 Years 785 78.6
All 5209 70.5

PROC REPORT SAS Code Examples

Using the COMPUTE Block in PROC REPORT by Jack Hamilton

Below are PROC REPORT code examples from an unknown source (not mine).

In [1]:
title '1.1a Continuous Data as a Summary Table';
proc report data=sashelp.class 
  nowindows nocenter missing headline headskip nofs list split='*';

  column ( Sex,
         ( ('__________ Age __________'
            age= agen age= agemean age= agestd age= agemin age=agemax)
          ));

  define sex /across center;
  define agen /analysis n format=3. 'N';
  define agemean /analysis mean format=5.3 'Mean';
  define agestd /analysis std format=5.3 'SD';
  define agemin /analysis min format=3. 'Min';
  define agemax /analysis max format=3. 'Max';
 run;
SAS Output

1.1a Continuous Data as a Summary Table

Sex
F M
_________ Age _________ _________ Age _________
N Mean SD Min Max N Mean SD Min Max
9 13.22 1.394 11 15 10 13.40 1.647 11 16
In [2]:
title '1.1b Continuous Data as a Summary Table by Sex';
proc report data=sashelp.class 
  nowindows nocenter missing headline headskip nofs list split='*';

  column Sex 
         ('_______ Age _______'
            age= agen age= agemean age= agestd age= agemin age=agemax);

  define sex /group center;
  define agen /analysis n format=3. 'N';
  define agemean /analysis mean format=5.3 'Mean';
  define agestd /analysis std format=5.3 'SD';
  define agemin /analysis min format=3. 'Min';
  define agemax /analysis max format=3. 'Max';

  break after sex / ol skip suppress summarize;
run;
SAS Output

1.1b Continuous Data as a Summary Table by Sex

  ______ Age ______
Sex N Mean SD Min Max
F 9 13.22 1.394 11 15
  9 13.22 1.394 11 15
M 10 13.40 1.647 11 16
  10 13.40 1.647 11 16
In [3]:
title '1.1c Continuous Data as a Summary Table by Sex Fill-In';
proc report data=sashelp.class 
  nowindows nocenter missing headline headskip nofs list split='*';

  column Sex 
         ('_______ Age _______'
            age= agen age= agemean age= agestd age= agemin age=agemax);

  define sex /group center;
  define agen /analysis n format=3. 'N';
  define agemean /analysis mean format=5.3 'Mean';
  define agestd /analysis std format=5.3 'SD';
  define agemin /analysis min format=3. 'Min';
  define agemax /analysis max format=3. 'Max';

  compute sex;
   if sex > ' ' then sexhld = sex;
   if sex = ' ' then sex = sexhld;
  endcomp;

  break after sex / ol skip suppress summarize;
run;
SAS Output

1.1c Continuous Data as a Summary Table by Sex Fill-In

  ______ Age ______
Sex N Mean SD Min Max
F 9 13.22 1.394 11 15
F 9 13.22 1.394 11 15
M 10 13.40 1.647 11 16
M 10 13.40 1.647 11 16
In [6]:
options FORMCHAR="|----|+|---+=|-/\<>*" ;
title ‘1.2a Categorical Data as a Percent Table’;
proc report data=sashelp.class nowindows nocenter missing
             headline headskip nofs list split='*';

 column sex N pctn; 

 define sex / group width=3; 
 define n / width=5 ; 
 define pctn / '%' format=percent7.1 ; 
run ;
SAS Output

‘1.2a Categorical Data as a Percent Table’

Sex N %
F 9 47.4%
M 10 52.6%
In [3]:
title ‘1.2b Categorical Data by Categorical Data as a Percent Table - 100% within a Region’;

 proc report data=sashelp.shoes nowindows nocenter missing
             headline headskip nofs list split='*';

 column product region, (n pctn); 

 define product/group "Product"; 
 define region/across order = internal "Region"; 
 define n/format =8. "N"; 
 define pctn / "%" format = percent8.1; 
 rbreak after/ ol summarize;
run;
SAS Output

‘1.2b Categorical Data by Categorical Data as a Percent Table -100% within a Region’

  Region
  Africa Asia Canada Central America/Caribbean Eastern Europe Middle East Pacific South America United States Western Europe
Product N % N % N % N % N % N % N % N % N % N %
Boot 8 14.3% 2 14.3% 5 13.5% 4 12.5% 4 12.9% 3 12.5% 6 13.3% 7 13.0% 5 12.5% 8 12.9%
Men's Casual 5 8.9% 1 7.1% 4 10.8% 4 12.5% 4 12.9% 3 12.5% 5 11.1% 6 11.1% 5 12.5% 8 12.9%
Men's Dress 7 12.5% 2 14.3% 4 10.8% 4 12.5% 4 12.9% 3 12.5% 6 13.3% 7 13.0% 5 12.5% 8 12.9%
Sandal 8 14.3% 2 14.3% 5 13.5% 4 12.5% 3 9.7% 3 12.5% 6 13.3% 7 13.0% 5 12.5% 6 9.7%
Slipper 8 14.3% 2 14.3% 5 13.5% 4 12.5% 4 12.9% 3 12.5% 6 13.3% 7 13.0% 5 12.5% 8 12.9%
Sport Shoe 8 14.3% 2 14.3% 5 13.5% 4 12.5% 4 12.9% 3 12.5% 5 11.1% 7 13.0% 5 12.5% 8 12.9%
Women's Casual 4 7.1% 2 14.3% 4 10.8% 4 12.5% 4 12.9% 3 12.5% 5 11.1% 6 11.1% 5 12.5% 8 12.9%
Women's Dress 8 14.3% 1 7.1% 5 13.5% 4 12.5% 4 12.9% 3 12.5% 6 13.3% 7 13.0% 5 12.5% 8 12.9%
  56 100.0% 14 100.0% 37 100.0% 32 100.0% 31 100.0% 24 100.0% 45 100.0% 54 100.0% 40 100.0% 62 100.0%
In [4]:
options nocenter ps=58 ls=132 nodate;

title '1.3a Data Listing - Africa and Asia regions and Boot, Sandal and Slippers';
proc report data=sashelp.shoes nowindows nocenter missing 
            headline headskip nofs list split='*';

 * Where condition excludes missing region and prodv values;
 where region in ('Africa' 'Asia') and product in ('Boot' 'Sandal' 'Slipper');

 column region product subsidiary stores sales inventory returns;

  define region /display;
  define product /display;
  define subsidiary/display;
  define stores /display;
  define sales/display;
  define inventory /display;
  define returns/display;
run;
SAS Output

1.3a Data Listing - Africa and Asia regions and Boot, Sandal and Slippers

Region Product Subsidiary Number of Stores Total Sales Total Inventory Total Returns
Africa Boot Addis Ababa 12 $29,761 $191,821 $769
Africa Sandal Addis Ababa 10 $62,819 $204,284 $1,861
Africa Slipper Addis Ababa 14 $68,641 $279,795 $1,771
Africa Boot Algiers 21 $21,297 $73,737 $710
Africa Sandal Algiers 25 $29,198 $84,447 $1,530
Africa Slipper Algiers 17 $64,891 $248,198 $1,823
Africa Boot Cairo 20 $4,846 $18,965 $229
Africa Sandal Cairo 9 $10,532 $50,430 $598
Africa Slipper Cairo 9 $13,732 $54,117 $1,216
Africa Boot Johannesburg 14 $8,365 $33,011 $483
Africa Sandal Johannesburg 13 $17,337 $63,003 $809
Africa Slipper Johannesburg 12 $39,452 $130,025 $1,565
Africa Boot Khartoum 24 $19,282 $105,370 $700
Africa Sandal Khartoum 18 $26,427 $81,825 $1,281
Africa Slipper Khartoum 11 $43,452 $143,015 $1,573
Africa Boot Kinshasa 16 $13,921 $70,736 $553
Africa Sandal Kinshasa 10 $16,662 $104,438 $611
Africa Slipper Kinshasa 11 $52,807 $183,937 $1,440
Africa Boot Luanda 8 $6,081 $51,572 $325
Africa Sandal Luanda 9 $11,145 $19,900 $657
Africa Slipper Luanda 5 $19,146 $97,060 $701
Africa Boot Nairobi 25 $16,282 $66,017 $844
Africa Sandal Nairobi 19 $16,289 $47,406 $1,175
Africa Slipper Nairobi 12 $34,955 $87,438 $1,320
Asia Boot Bangkok 1 $1,996 $9,576 $80
Asia Sandal Bangkok 1 $3,230 $15,087 $120
Asia Slipper Bangkok 1 $3,019 $16,075 $127
Asia Boot Seoul 17 $60,712 $160,589 $1,296
Asia Sandal Seoul 3 $4,978 $21,483 $105
Asia Slipper Seoul 21 $149,013 $469,007 $2,941
In [10]:
options nocenter nodate ps=58 ls=132;
title '1.3c Data Listing with Section Heading and SubTotals';
proc report data=sashelp.shoes nowindows nocenter missing 
            headline headskip nofs list split='*';

 * Where condition excludes missing region and prodv values;
 where region in ('Africa' 'Asia') and product in ('Boot' 'Sandal' 'Slipper');

 column region product subsidiary stores sales inventory returns;

  define region /order noprint;
  define product /order noprint;
  define subsidiary/display;
  define stores /sum;
  define sales/sum;
  define inventory /sum;
  define returns/sum;

  compute before product;
   line @10 'Region = ' region $10. +5 'Product =' product $15.;
   line @10 75*'=';
  endcomp;

  compute after product;
   line @10 15*'=';
   line @10 'SubTotal for ' product $15. +30  stores.sum 3.;
  endcomp;

run;
SAS Output

1.3c Data Listing with Section Heading and SubTotals

Subsidiary Number of Stores Total Sales Total Inventory Total Returns
         Region = Africa         Product =Boot
         ===========================================================================
Addis Ababa 12 $29,761 $191,821 $769
Algiers 21 $21,297 $73,737 $710
Cairo 20 $4,846 $18,965 $229
Johannesburg 14 $8,365 $33,011 $483
Khartoum 24 $19,282 $105,370 $700
Kinshasa 16 $13,921 $70,736 $553
Luanda 8 $6,081 $51,572 $325
Nairobi 25 $16,282 $66,017 $844
         ===============
         SubTotal for Boot                                         140
         Region = Africa         Product =Sandal
         ===========================================================================
Addis Ababa 10 $62,819 $204,284 $1,861
Algiers 25 $29,198 $84,447 $1,530
Cairo 9 $10,532 $50,430 $598
Johannesburg 13 $17,337 $63,003 $809
Khartoum 18 $26,427 $81,825 $1,281
Kinshasa 10 $16,662 $104,438 $611
Luanda 9 $11,145 $19,900 $657
Nairobi 19 $16,289 $47,406 $1,175
         ===============
         SubTotal for Sandal                                       113
         Region = Africa         Product =Slipper
         ===========================================================================
Addis Ababa 14 $68,641 $279,795 $1,771
Algiers 17 $64,891 $248,198 $1,823
Cairo 9 $13,732 $54,117 $1,216
Johannesburg 12 $39,452 $130,025 $1,565
Khartoum 11 $43,452 $143,015 $1,573
Kinshasa 11 $52,807 $183,937 $1,440
Luanda 5 $19,146 $97,060 $701
Nairobi 12 $34,955 $87,438 $1,320
         ===============
         SubTotal for Slipper                                       91
         Region = Asia           Product =Boot
         ===========================================================================
Bangkok 1 $1,996 $9,576 $80
Seoul 17 $60,712 $160,589 $1,296
         ===============
         SubTotal for Boot                                          18
         Region = Asia           Product =Sandal
         ===========================================================================
Bangkok 1 $3,230 $15,087 $120
Seoul 3 $4,978 $21,483 $105
         ===============
         SubTotal for Sandal                                         4
         Region = Asia           Product =Slipper
         ===========================================================================
Bangkok 1 $3,019 $16,075 $127
Seoul 21 $149,013 $469,007 $2,941
         ===============
         SubTotal for Slipper                                       22
In [12]:
title '1.3e Data Listing - Name and Age from Summary Input Data';
data classfreq;
 set sashelp.class;
 freqcnt=5;
run;

proc report data=classfreq nowindows nocenter missing 
            headline headskip nofs list split='*';
 column name age;
 freq freqcnt; 
  /*The above statement treats observations as if they appear
  multiple times (i.e. five times in the input data set.*/
run;

ods rtf close;
SAS Output

1.3e Data Listing - Name and Age from Summary Input Data

Name Age
Alfred 70
Alice 65
Barbara 65
Carol 70
Henry 70
James 60
Jane 60
Janet 75
Jeffrey 65
John 60
Joyce 55
Judy 70
Louise 60
Mary 75
Philip 80
Robert 60
Ronald 75
Thomas 55
William 75