22S:172

advertisement
22S:172
The SAS Output Delivery System
Lab 10
July 25, 2005
Kellie Poulin Bach
kellie-poulin@uiowa.edu

The SAS Output Delivery System (ODS) was created to increase the number of ways we can
view SAS output and interact with it.

The most common uses are:
o To automatically create output that can be directly passed to clients
o Take part of all of the output and send it to an external program (such as Word or
Excel)
o To take parts of the output and use them as input into future SAS programs or SAS
datasets

SAS Output typically shows up in the output window. It can also go into
o HTML files
o CSV files
o RTF files (for Word)
o PDF files
o PS files
o SAS datasets
o WML (wireless markup language – I have not used this new option yet)
o Latex and Colorlatex (experimental meaning it will usually work, but it is not yet fully
working or supported by SAS)

We will go through examples it illustrate how to use ODS. You can copy and paste the code
from this document into your SAS program editor to follow along. Note you will need to
change the location of the input data in your editor.
/*
1. CREATING OUTPUT THAT CAN BE DIRECTLY PASSED TO CLIENTS
*/
/* Read in the patient dataset from earlier this semester */
DATA PATIENTS;
INFILE "D:\s172\patients.dat" PAD;
*you will need to change this infile statement;
INPUT @1 PATNO
$3.
@4 GENDER
$1.
@5 VISIT
MMDDYY10.
@15 HR
3.
@18 SBP
3.
@21 DBP
3.
@24 DX
$3.
@27 AE
$1.;
LABEL PATNO
GENDER
VISIT
HR
SBP
DBP
DX
AE
=
=
=
=
=
=
=
=
"Patient Number"
"Gender"
"Visit Date"
"Heart Rate"
"Systolic Blood Pressure"
"Diastolic Blood Pressure"
"Diagnosis Code"
"Adverse Event?";
FORMAT VISIT MMDDYY10.;
RUN;
/* The standard way to produce a table */
proc tabulate data=patients format=7.3;
title "statitics for numeric variables";
var hr sbp dbp;
tables hr sbp dbp,
N*F=7.0 NMISS*F=7.0 MEAN MIN MAX /RTSPACE=18;
keylabel
N ='Number'
NMISS='Missing'
MEAN='Mean'
MIN='Lowest'
MAX='Highest';
run;
/* Producing the same table in HTML */
ods html ;
proc tabulate data=patients format=7.3;
title "statitics for numeric variables";
var hr sbp dbp;
tables hr sbp dbp,
N*F=7.0 NMISS*F=7.0 MEAN MIN MAX /RTSPACE=18;
keylabel
N ='Number'
NMISS='Missing'
MEAN='Mean'
MIN='Lowest'
MAX='Highest';
run;
ods html close;
/* Saving the HTML file so that you can send it to a client */
ods html file = 'Pat_Stat.html'
path = 'c:\temp\' (url=none)
;
* (url=none) makes it so SAS does not hard code the URL. This is important if you
will pass this file to others via email. If you will post the file on a web site then
you can put the url of the output here ;
proc tabulate data=patients format=7.3;
title "statitics for numeric variables";
var hr sbp dbp;
tables hr sbp dbp,
N*F=7.0 NMISS*F=7.0 MEAN MIN MAX /RTSPACE=18;
keylabel
N ='Number'
NMISS='Missing'
MEAN='Mean'
MIN='Lowest'
MAX='Highest';
run;
ods html close;
/* You can send the output from several procedures to the same HTML file. To make it easier to
navigate, use a contents tab on the left of the output */
ods html file = 'Pat_Stat.html'
path = 'c:\temp\' (url=none)
contents='contents.html'
frame='frame.html'
style = default
;
proc tabulate data=patients format=7.3;
title "statitics for numeric variables";
var hr sbp dbp;
tables hr sbp dbp,
N*F=7.0 NMISS*F=7.0 MEAN MIN MAX /RTSPACE=18;
keylabel
N ='Number'
NMISS='Missing'
MEAN='Mean'
MIN='Lowest'
MAX='Highest';
run;
proc univariate data=patients ;
var hr sbp dbp;
run;
ods html close;
/* Go to the c:\temp directory and double click on the frame.html file to see how the table of
contents works */
/* NOTE: AVAILABLE SAS STYLES ARE
BarretsBlue, Beige, Brick, Brown, D3D, Default, fancyPrinter, Minimal, Printer, RTF,
SASWeb, Theme
and more.... You can also create your own using proc template
You can also create your own css style sheets and use them*/
ods html file = 'Pat_Stat.html'
path = 'c:\temp\' (url=none)
contents='contents.html'
frame='frame.html'
style = Brown
;
proc tabulate data=patients format=7.3;
title "statitics for numeric variables";
var hr sbp dbp;
tables hr sbp dbp,
N*F=7.0 NMISS*F=7.0 MEAN MIN MAX /RTSPACE=18;
keylabel
N ='Number'
NMISS='Missing'
MEAN='Mean'
MIN='Lowest'
MAX='Highest';
run;
proc univariate data=patients ;
var hr sbp dbp;
run;
ods html close;
/* The ODS htmlcss statement will output a css file that you can edit in notepad to make custom
output */
ods htmlcss file = 'Pat_Stat2.html'
path = 'c:\temp\' (url=none)
contents='contents2.html'
frame='frame2.html'
style = Brown
STYLESHEET= 'Style.css'
;
proc tabulate data=patients format=7.3;
title "statitics for numeric variables";
var hr sbp dbp;
tables hr sbp dbp,
N*F=7.0 NMISS*F=7.0 MEAN MIN MAX /RTSPACE=18;
keylabel
N ='Number'
NMISS='Missing'
MEAN='Mean'
MIN='Lowest'
MAX='Highest';
run;
proc univariate data=patients ;
var hr sbp dbp;
run;
ods htmlcss close;
/* You can find the color codes here http://www.immigration-usa.com/html_colors.html and
http://jeff-lab.queensu.ca/stat/sas/sasman/sashtml/gref/zgscheme.htm
The code below shows how to reference your new style sheet
*/
ods html file = 'Pat_Stat3.html'
path = 'c:\temp\' (url=none)
contents='contents3.html'
frame='frame3.html'
STYLESHEET= (url='Style.css')
;
proc tabulate data=patients format=7.3;
title "statitics for numeric variables";
var hr sbp dbp;
tables hr sbp dbp,
N*F=7.0 NMISS*F=7.0 MEAN MIN MAX /RTSPACE=18;
keylabel
N ='Number'
NMISS='Missing'
MEAN='Mean'
MIN='Lowest'
MAX='Highest';
run;
proc univariate data=patients ;
var hr sbp dbp;
run;
ods html close;
/* modifying templates using proc template is beyond the scope of this talk, but to view the
templates you have to get an idea of the syntax you can right click on the word results. Then select
templates, scroll down to styles and view the code that makes the different styles. If you want to
edit a style you should make a copy first. Do not edit any of the styles on UIOWA computers, use
CSS instead */
/* Clients may prefer PDS files. Here is example code for creating a PDF file */
%let PDFReport= c:\temp\report.pdf;
ods pdf file="&PDFReport." uniform startpage=no;
*startpage=no stops SAS from starting a new page at the beginning of each proc
Uniform provides uniformity from page to page within a single table when tables span
pages.
;
proc tabulate data=patients format=7.3;
title "statitics for numeric variables";
var hr sbp dbp;
tables hr sbp dbp,
N*F=7.0 NMISS*F=7.0 MEAN MIN MAX /RTSPACE=18;
keylabel
N ='Number'
NMISS='Missing'
MEAN='Mean'
MIN='Lowest'
MAX='Highest';
run;
proc univariate data=patients ;
var hr sbp dbp;
run;
ods pdf close;
/* Suppose your client does not want all of the Univariate output. You can select what parts to
include in the file you send them. You first need to find out the name of the output section you
want. To do that you use ODS trace */
ods trace on /label;
proc univariate data=patients plots;
var hr sbp dbp;
run;
ods trace off;
/* the log window will show you the names of the output sections */
/* Suppose the client only wants to see the extreme obs for data checking purposes */
ods html file = 'Pat_Stat3.html'
path = 'c:\temp\' (url=none)
contents='contents3.html'
frame='frame3.html'
style = beige
;
ods html select extremeobs;
proc univariate data=patients plots;
var hr sbp dbp;
run;
ods html close;
/* Suppose the client only wants to see the extreme obs for hr */
ods html file = 'Pat_Stat3.html'
path = 'c:\temp\' (url=none)
contents='contents3.html'
frame='frame3.html'
style = beige
;
ods html select hr.extremeobs;
proc univariate data=patients plots;
var hr sbp dbp;
run;
ods html close;
/* Lastly this code removes all of the SAS language from the output and creates a report for the
client to review invalid records. We use the ods proclabel statement to name our proc and the
contents statement to change what is shown on the table of contents */
ods html file = ‘report.html’
path = ‘c:\temp\’(url=none)
contents=’contents.html’
frame=’frame.html’
style = d3d;
ods proclabel="Patient Data Table";
proc print data=patients split='*' NOOBS contents="Invalid Records";
ID PATNO;
VAR GENDER DX AE;
label
gender='Gender'
dx='Diagnosis Code'
ae='Indicator of*Adverse Event';
WHERE GENDER NOT IN ('M' 'F' ' ')
VERIFY(DX,' 0123456789') NE 0
AE NOT IN ('0' '1' ' ');
OR
OR
TITLE "LISTING OF INVALID CHARACTER VALUES";
run;
ods html close ;
/* note this whole time we have also been sending the default output to the output window. You
can turn that off using ODS listing close; And turn it back on just submit ODS listing; */
/*
2. Taking part of the output and sending it to Word or Excel. This may also be for a client or for
your own review and manipulation.
*/
/* here is an example of sending the extreme observations output to a word doc. */
ods rtf file = 'Pat_Stat3.doc'
path = 'c:\temp\' (url=none)
style = beige
;
ods rtf select hr.extremeobs;
proc univariate data=patients plots;
var hr sbp dbp;
run;
ods rtf close;
/* here is an example of sending the extreme obs output to an excel file. */
ods csvall file = 'Pat_Stat_all.csv'
path = 'c:\temp\' (url=none)
;
ods csvall select hr.extremeobs;
proc univariate data=patients ;
var hr sbp dbp;
run;
ods csvall close;
********************************;
ods csv file = 'Pat_Stat.csv'
path = 'c:\temp\' (url=none)
;
ods csv select hr.extremeobs;
proc univariate data=patients ;
var hr sbp dbp;
run;
ods csv close;
/* the first set of code will also put the headings and titles in the excel file. The second set of code
will not */
/* For the next few examples we will use the dataset you used for Lab 8 */
data bpd ;
infile 'd:\s172\bpd.dat' firstobs = 2 ;
input bpd birthwt gestage toxemia @50 steroid 1. ;
run ;
/* Comparing models in Excel */
ods csvall
path="c:\temp\"
body='logistic.csv' ;
ods select
LackFitPartition
LackFitChiSq;
proc logistic data= bpd;
model bpd = birthwt
/lackfit;
ods select
LackFitChiSq;
LackFitPartition
proc logistic data= bpd;
model bpd = gestage /lackfit;
ods select
LackFitPartition
LackFitChiSq;
proc logistic data= bpd;
model bpd = steroid /lackfit;
ods select
LackFitPartition
LackFitChiSq;
proc logistic data= bpd;
model bpd = birthwt gestage
ods select
LackFitPartition
/lackfit;
LackFitChiSq;
proc logistic data= bpd;
model bpd = birthwt steroid /lackfit;
ods select LackFitPartition
LackFitChiSq;
proc logistic data= bpd;
model bpd = gestage steroid
/lackfit;
ods select
LackFitPartition
LackFitChiSq;
proc logistic data= bpd;
model bpd = birthwt gestage steroid
run ;
ods csvall close;
/lackfit;
/* note this code could be greatly improved and generalized by creating a macro and using macro
variables. Also adding titles will help us keep the models straight in the output */
/*
3. Taking part of the output and using it as a program input or putting into a SAS dataset.
*/
/* A simple example use ODS output to put the output in a dataset. Note you have to tell SAS what
part of the output to put in each file. */
/* This puts the extreme obs from each variable into different datasets */
ods output extremeobs(match_all)=extobs;
proc univariate data=patients;
var hr sbp dbp;
run;
/* This puts the extreme obs from each variable into a single dataset */
ods output extremeobs=extobs_all;
proc univariate data=patients;
var hr sbp dbp;
run;
/* Now a more complicated example. Since we probably will not have time to cover this in detail, I
refer you to CC05-Warner.pdf which covers Jen Warner Freeman’s code.
The basic steps are to use the ODS output statement to select parts of output and send them to
datasets (see highlighted sections below). Then if you need to use a value from the output in a
program, you can create a macro variable from the data set using the call symput function. You can
then use these macro variable in later SAS code.
A very good example of this is a program written by a colleague of mine to reformat the proc ttest
output. We needed to do this because we often had thousands of variables to examine and this
code made it easy for us to find the ones that were most significant.
FOR THIS PROGRAM DOWNLOAD CAMPAIGN_DATA.ZIP and unzip into your SAS library. */
libname s172 'd:\s172';
/**START OF JEN WARNER FREEMANS CODE */
%let lib1 =work;
%let lib2 = s172;
%let fileorg =campaign_sample;
%let pre = temp;
%let buyind=buy_ind;
ods output "Statistics" = &lib1..&pre.stats
"T-Tests" = &lib1..&pre.ttests
"Equality of Variances" = &lib1..&pre.vars;
proc ttest data=&lib2..&fileorg;
class &buyind;
var _numeric_;
run;
ods output close;
data &lib1..&pre.stats1 (keep = variable class mean_nonbuyers mean_buyers);
set &lib1..&pre.stats (rename=(mean=avg));
if class = '
0'
then mean_nonbuyers = avg;
if class = '
1'
then mean_buyers = avg;
run;
data &lib1..&pre.buyers(drop = class mean_nonbuyers)
&lib1..&pre.nonbuyers(drop = class mean_buyers);
set &lib1..&pre.stats1;
if class = '
0' then output &lib1..&pre.nonbuyers;
if class = '
1' then output &lib1..&pre.buyers;
run;
proc sort data = &lib1..&pre.buyers;
by variable;
run;
proc sort data = &lib1..&pre.nonbuyers;
by variable;
run;
data &lib1..&pre.statsfinal;
merge &lib1..&pre.buyers
&lib1..&pre.nonbuyers;
by variable;
run;
data &lib1..&pre.ttests1;
set &lib1..&pre.ttests;
length difference $10.;
if probt le .0001 then difference = 'highly';
else if probt le .005 then difference = 'somewhat';
else if probt le .05 then difference = 'weak';
else difference = 'not at all';
run;
proc freq data = &lib..&pre.ttests1;
tables difference;
run;
data &lib1..&pre.vars;
set &lib1..&pre.vars (rename=(probf=probv));
run;
proc sort data = &lib1..&pre.vars;
by variable;
run;
proc sort data = &lib1..&pre.ttests1;
by variable difference;
run;
data &lib1..&pre.merged;
merge &lib1..&pre.ttests1 (in=a)
&lib1..&pre.vars (in=b keep = variable probv);
by variable;
if a;
run;
data &lib1..&pre.diffsame;
set &lib1..&pre.merged;
if probv le .0050 and variances = 'Unequal'
then output;
if probv gt .0050 and variances = 'Equal'
then output;
run;
proc sort data = &lib1..&pre.diffsame;
by variable;
run;
data &lib2..&pre.ttest;
merge &lib1..&pre.statsfinal
&lib1..&pre.diffsame (drop = method variances df probv);
by variable;
run;
proc sort data = &lib2..&pre.ttest;
by probt;
run;
proc print data = &lib2..&pre.ttest;
run;
/**END OF JEN WARNER FREEMANS CODE */
/* START OF MY CODE TO DEMONSTRATE USING ODS TO CREATE MACRO VARIABLES */
/* This macro will create plots of each predictor variable with the target variable of a logistic
regression. This will help us determine if the predictor is linear in the logit. We need to run this code
for each possible predictor on our file. Sometimes we have hundreds of predictors. */
%macro varplot(var);
proc rank data=&lib2..&fileorg. groups=10 out=ranks;
var &var.;
ranks rank;
proc means data=ranks;
class rank;
var &buyind. &var.;
output out=&lib1..temp sum(&buyind.)=buyers mean(&var.)=mean_&var.;
data &lib1..&var.;
set &lib1..temp;
if _type_=1;
percent=buyers/_freq_;
lnmean=log(mean_&var.)
;
logit=log((buyers+1)/(_freq_-buyers+1));
meansq=mean_&var.**2;
sqrtx=sqrt(mean_&var.);
proc plot data=&lib1..&var.;
plot percent*mean_&var.;
plot percent*lnmean;
plot logit*mean_&var.;
plot percent*meansq;
plot percent*sqrtx;
plot logit*lnmean;
plot logit*sqrtx;
plot logit*meansq;
run;
%mend;
/* But, I do not want to type the names of all of my possible predictor variables into macro calls. So
I wrote this code to pull the names of the numeric variables out of the dataset created by the ods
output statement (and later manipulated by Jen’s code). I then use a little do loop to call the macro
once for each numeric variable. */
data _null_;
set &lib1..&pre.statsfinal end=last;
num+1;
call symput("var"!!left(num),variable);
if last then call symput("NUM",left(num));
run;
%put _user_;
* this is so I can make sure I made the variables correctly.
run;
%macro temp;
Look in the log;
%do i = 1 %to &NUM ;
%Varplot( &&VAR&i );
%end;
%mend;
%Temp;
/*
4. Another cool thing I want to mention 
A new experimental module is now available in SAS. It is called ODS Graphics. It creates a lot of
new cool graphics in many of the SAS Proceedures.
*/
/* Example an ROC Curve is now displayed in the html output. Note this is not available in the
standard output without calling proc gplot. */
ods html
path="c:\temp\"
body='logistic.html';
ods graphics on;
proc logistic data= bpd;
model bpd = birthwt gestage steroid /lackfit outroc=temp selection=stepwise
slentry=.1 slstay=.1;
run ;
ods html close;
ods graphics off;
/* Many cool diagnostic plots come out of proc timeseries. */
/*Read in the soccho dataset */
data soccho ;
infile 'd:\s172\soccho2002.dat' delimiter = ',' ; /* data file has
commas rather than spaces betw cols */
input acct $ unitval date $10. ;
if mod(_n_, 7) > 1 ; /* eliminate weekend days */
run ;
data soccho_num;
set soccho;
* convert the date to a numeric variable from character;
num_date=input(date,mmddyy10.);
format num_date mmddyy10.;
*example of converting numeric to character;
char_date_with_fmt=put(num_date,mmddyy10.);
char_date_no_fmt=put(num_date,$10.);
run;
*goptions device=activex;
goptions device=java;
ods html
path="c:\temp\"
body='timeseries';
ods graphics on;
proc timeseries data= soccho_num
print=(descstats trends decomp)
plot=(series corr acf pacf iacf wn tc sc ic cc);
var unitval;
id num_Date interval=weekday accumulate=none;
run;
ods html close;
ods graphics off;
ods listing;
/* lets see what the univariate output would look like with this option */
ods html file = 'Pat_Stat3.html'
path = 'c:\temp\' (url=none)
contents='contents3.html'
frame='frame3.html'
style = beige
;
ods graphics on;
proc univariate data=patients plots;
var hr sbp dbp;
run;
ods graphics off;
ods html close;
Download