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
*Ex1_proc_summary_proc_means_sum.sas (Part 1);
proc means data=sashelp.heart;
class BP_status;
var weight;
run;
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 |
%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
*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;
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)
proc means data=sashelp.class mean std Q1 Median Q3;
var weight;
run;
SAS Connection established. Subprocess id is 9896
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
- _TYPE_ (an automatic numeric variable) is automatically created
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;
| 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 |
*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;
| 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 |
*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;
| ACTUAL_Sum | PREDICT_Sum | QUARTER_Sum | YEAR_Sum | MONTH_Sum |
|---|---|---|---|---|
| $730,337 | $706,295 | $3,600 | $2,870,640 | $17,860,320 |
*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;
| 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.
*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;
| 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 |
proc summary data=heart;
class sex smoking_status;
var weight;
output out=stats
mean=meanWEIGHT/ levels ways;
run;
proc print data=stats; run;
| 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.
*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;
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.
title1 'One-Way Table';
title2 'MISSING option';
proc freq data=sashelp.heart;
tables weight_status / missing;
run;
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 |
title1 'One-Way Table';
title2 'MISSPRINT option in the TABLES statement';
proc freq data=sashelp.heart;
tables weight_status / missing;
run;
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.
title1 'Two-Way Table';
title2 ' ';
proc freq data=sashelp.heart;
tables weight_status*bp_status;
run;
The FREQ Procedure
|
|
||||||||||||||||||||||||||||||||||||||||
PROC FREQ¶
Use a WHERE statement in the PROC FREQ step when tabulations are desired for a subgroup of observations.
title1 'Two-Way Table';
title2 'WHERE statement';
proc freq data=sashelp.heart;
tables weight_status*bp_status;
where sex='Male';
run;
The FREQ Procedure
|
|
||||||||||||||||||||||||||||||||||||||||
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
title1 'Two-Way Table';
title2 'Suppress Percent';
proc freq data=sashelp.heart;
tables weight_status*bp_status/
norow nocol nopercent;
run;
The FREQ Procedure
|
|
||||||||||||||||||||||||||||||||||||||||
title1 'Two-Way Table';
title2 'Suppress Percent & Column Percent';
proc freq data=sashelp.heart;
tables weight_status*bp_status/
norow nocol nopercent;
run;
The FREQ Procedure
|
|
||||||||||||||||||||||||||||||||||||||||
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.
title1 'Two-Way Table';
title2 'LIST Option';
proc freq data=sashelp.heart;
tables weight_status*bp_status/LIST
norow nocol nopercent;
run;
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 |
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;
| 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 |
* 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;
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 |
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;
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 |
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;
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"
*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;
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
*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;
The FREQ Procedure
|
|
||||||||||||||||||||||||
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.
proc freq data=sashelp.class nlevels;
tables _all_ / noprint;
run;
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.
*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;
| 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 |
*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;
| 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 |
*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;
| Sex Female | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Sex Male | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| All | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*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;
| 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 | |
*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;
| 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 |
*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;
| 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 |
Below are PROC REPORT code examples from an unknown source (not mine).
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;
| 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 |
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;
| ______ 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 | |
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;
| ______ 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 |
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 ;
| Sex | N | % |
|---|---|---|
| F | 9 | 47.4% |
| M | 10 | 52.6% |
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;
| 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% | |
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;
| 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 |
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;
| 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 |
||||
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;
| 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 |