To see the original design specification for %unistats, click here.
%unistats calls other macros. For a list of original dependencies, click here.
Note: If you see a misalignment of the columns in any example of the output shown below then this is caused by the html editor I am using and is not caused by a bug in the reporting macro.
- Calculates summary statistics (for numeric variables) and category counts with percentages for categorical variables.
- Supply an output dataset containing the calcualted values
- By default, prints a report unless print=no is set.
- Can produce a correctly formatted report with only two parameters set
- Automatically displays the total for all treatment arms if total=yes is set.
- Will by default fit the page width if a print is requested.
- Will plug missing values with zeroes.
- Percentages for categories will be based on the treatment arm population by default. Percentages based on total category counts can be requested using pctcalc=cat.
- Indentation can be adjusted.
- Spacing between treatment arms can be adjusted.
- Will produce a transposed output datasets if requested.
- Allows the number of decimal places to be set for different numeric variables.
- Aligns decimal points for descriptive statistics unless dpalign=no specified
- Automatically maps free-style statistics labels to their statistics keyword.
- Allows for pairing of descriptive statistics on the same line
- Will display categories in format order if a format is applied.
- Will turn the second character onwards to lower case if requested for variables defined to lowcasevarlist= parameter.
- Page flow can be controlled.
- Will display all format values with missing ones having a zero count for individual or all variables.
- Will calculate p-values for Fisher's Exact test and Chi-square test for categorical variables, F-test and Student's t test for numeric variables and Kruskal-Wallis test or the Wilcoxon rank sum test for non-parametric numeric variables.
- Writes p-values to global macro variables so that they can be used in footnotes instead of displayed in a column.
- Will allow the user to place statistical values from ods tables in the body of the report without further programming
- Allows for more than 10 footnotes
- Can easily be used to generate ISS reports
There are several demonstrations and each of them will build on the previous demonstrations. It would be a very good idea if you tried this out yourself using an interactive SAS® software session.
If you are using a laptop for these demonstrations or your PC at home
then the following code will function using SAS®
Learning Edition. You will learn more if you actually submit the code
and see the results and SAS Learning Edition is an inexpensive and worthwhile
alternative to owning a full copy of SAS software.
First the Formats
First we need to set up some formats and informats that we will be using to create the output. You should always run this before running any of the demos below - but you only have to do it once per SAS session. You might need to refer back to this code so that you can see what the formats contain. I have set up some system options as well. If you take a look at my "sasautos" option you will see I have all my macros in one folder. Normally the clinical macros and utility macros go in different folders but I do all my macro development in one folder and split them later.
/* %unistats: Pre-demo formats and system options */ options noovp nodate nonumber center missing=" " formchar='|_---|+|---+=|-/\<>*'
sasautos=("C:\spectre\macros" SASAUTOS) ls=78 ps=63;title1;
proc format;
value racecd
1="CAUCASIAN"
2="BLACK"
3="ASIAN"
4="HISPANIC"
5="OTHER"
;
value sexcd
1="MALE"
2="FEMALE"
;
value trtcd
1="Ambident (1g/day)"
2="Betamax (500mg/day)"
3="No treatment"
;
*- 1-9 = study 101+102, 11-19 = study 301+302 -;
value trtcdx
1="Placebo"
2="Drug A"
3="Drug B"
9="Total"
11="Placebo"
12="Drug A"
13="Drug B"
19="Total"
;
value trtnarr
1="Ambident@(1g/day)"
2="Betamax@(500mg/day)"
3="No@treatment"
;
*- 1-9 = Female, 11-19 = Male -;
value trtsex
1="Ambident@(1g/day)"
2="Betamax@(500mg/day)"
9="Total"
11="Ambident@(1g/day)"
12="Betamax@(500mg/day)"
19="Total"
;
value NY
0="NO"
1="YES"
;
value intensity
1="Mild"
2="Moderate"
3="Severe"
;
invalue socord
"General disorders and administration site conditions"=1
"Gastrointestinal disorders"=2
"Nervous system disorders"=3
"Vascular disorders"=4
"Respiratory, thoracic and mediastinal disorders"=5
"Musculoskeletal and connective tissue disorders"=6
OTHER=99
;
value agecat
0-15="<16 yrs"
16-25=" 16 - 25 yrs"
26-40=" 26 - 40 yrs"
41-65=" 41 - 65 yrs"
66-high=">65 years"
;
run;
Demo 1
The first demonstration is a very basic one. You will see a very simple call to the macro and the output it produces. Please try all these demonstrations yourself by submitting the code in an interactive SAS session. You will have to make sure that sasautos is locating the macros. In the code below we set only two macro parameters and allow it to default for the descriptive statistics.
/* Demonstrate %unistats: program 1 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%unistats(dsin=demog,
varlist=sexcd racecd age weight height);Here is the output produced by this very simple call. It could be better. The labels are all in capital letters because the macro uses the variable labels and since these were set to capital letters then it uses them. The gender code and race code are the coded values and these values are in capitals because the format it uses maps these codes to capital letter descriptions. Looking at the output you can see one clever feature of the macro. It has used information from the call to %popfmt to set the column widths. We will use a narrower treatment arm format later to reduce the width of the columns but it is a useful feature of the macro that it chooses the column widths for you (although you can overide this if you need to). This leads to better automation of producing reports.
______________________________________________________________________________ Ambident (1g/day) Betamax (500mg/day)
(N=9) (N=8)
______________________________________________________________________________GENDER CODE
MALE 4 ( 44.4) 3 ( 37.5)
FEMALE 5 ( 55.6) 5 ( 62.5)RACE CODE
CAUCASIAN 5 ( 55.6) 1 ( 12.5)
BLACK 2 ( 22.2) 3 ( 37.5)
ASIAN 2 ( 22.2) 3 ( 37.5)
HISPANIC 0 ( 0.0) 0 ( 0.0)
OTHER 0 ( 0.0) 1 ( 12.5)AGE (YEARS)
N 9 8
Mean 26.3 24.0
S.D. 8.03 8.49
Median 26.0 23.0
Minimum 16.0 16.0
Maximum 40.0 36.0WEIGHT (KG)
N 9 8
Mean 76.6 70.8
S.D. 4.36 5.69
Median 78.1 70.4
Minimum 65.5 65.5
Maximum 79.6 78.1HEIGHT (CM)
N 9 8
Mean 197.2 182.3
S.D. 11.94 9.00
Median 200.0 180.5
Minimum 175.0 175.0
Maximum 212.0 200.0
Demo 2
Here is the code again modified to address the points made about the report in the first demonstration plus we will add a treatment arm label. I will change the descriptive statistics for this. The %unistats macro calls a macro called %unimap to map statistics labels to statistics keywords and in most cases will be able to map your labels to keywords. If not you can make a copy of %unimap and amend it to suit your needs. The modified code is highlighted.
/* Demonstrate %unistats: program 2 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%unistats(dsin=demog,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min. Mean Max. STD.,
varlist=sexcd racecd age weight height);Here is the new output. It is looking better.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident (1g/day) Betamax (500mg/day)
(N=9) (N=8)
______________________________________________________________________________GENDER CODE
Male 4 ( 44.4) 3 ( 37.5)
Female 5 ( 55.6) 5 ( 62.5)RACE CODE
Caucasian 5 ( 55.6) 1 ( 12.5)
Black 2 ( 22.2) 3 ( 37.5)
Asian 2 ( 22.2) 3 ( 37.5)
Hispanic 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5)AGE (YEARS)
N 9 8
Min. 16.0 16.0
Mean 26.3 24.0
Max. 40.0 36.0
STD. 8.03 8.49WEIGHT (KG)
N 9 8
Min. 65.5 65.5
Mean 76.6 70.8
Max. 79.6 78.1
STD. 4.36 5.69HEIGHT (CM)
N 9 8
Min. 175.0 175.0
Mean 197.2 182.3
Max. 212.0 200.0
STD. 11.94 9.00
Demo 3
It is very easy to add a "Total" column. This just involves setting the parameter "total=yes". This will be done next. You can change the label from "Total" to something else by setting a parameter in the %popfmt macro but I will leave it as it is. I will give new labels for the variables to that they appear in proper case.
/* Demonstrate %unistats: program 3 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
label sexcd="Gender"
racecd="Race"
age="Age (yrs)"
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%unistats(dsin=demog,total=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min. Mean Max. STD.,
varlist=sexcd racecd age weight height);Here is the output. The report is more cramped. What if the drug names were longer? The report might not fit if that were the case. We can get round this by using a narrower format. There is one already defined named trtnarr which you can see in the formats code at the top of the page.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident (1g/day) Betamax (500mg/day) Total
(N=9) (N=8) (N=17)
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2)
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3)
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
N 9 8 17
Min. 16.0 16.0 16.0
Mean 26.3 24.0 25.2
Max. 40.0 36.0 40.0
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min. 65.5 65.5 65.5
Mean 76.6 70.8 73.8
Max. 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min. 175.0 175.0 175.0
Mean 197.2 182.3 190.2
Max. 212.0 200.0 212.0
STD. 11.94 9.00 12.89
Demo 4
The treatment columns can be made narrower if you use a different format. It is the %popfmt macro that creates the column labels so if we apply this narrower format to the treatment variable before %popfmt is called then it will solve the problem.
/* Demonstrate %unistats: program 4 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
format trtcd trtnarr.;
label sexcd="Gender"
racecd="Race"
age="Age (yrs)"
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,sasuser.demog(where=(fascd=1)),uniqueid=patno invid)
%unistats(dsin=demog,total=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min. Mean Max. STD.,
varlist=sexcd racecd age weight height);Here is the new output. You can see that the treatment columns are narrower. Have a closer look at the "Race" categories. "Hispanic" is shown as all zeroes. It is not a mistake. There is a very good reason for that - there were no Hispanic patients in the study. But if "Hispanic" were a category on the Case Report Form then it would be better to see this as zeroes rather than not see it at all. Showing all the categories is the default action of the %unistats macro. If you do not want this then you can set allcat=no to deactivate it.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17)
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2)
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3)
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
N 9 8 17
Min. 16.0 16.0 16.0
Mean 26.3 24.0 25.2
Max. 40.0 36.0 40.0
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min. 65.5 65.5 65.5
Mean 76.6 70.8 73.8
Max. 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min. 175.0 175.0 175.0
Mean 197.2 182.3 190.2
Max. 212.0 200.0 212.0
STD. 11.94 9.00 12.89
Demo 5
The call to the macro is now changed to use the "allcat=no" to show just the categories we find in the data.
/* Demonstrate %unistats: program 5 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
format trtcd trtnarr.;
label sexcd="Gender"
racecd="Race"
age="Age (yrs)"
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,sasuser.demog(where=(fascd=1)),uniqueid=patno invid)
%unistats(dsin=demog,total=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min. Mean Max. STD.,
varlist=sexcd racecd age weight height,
allcat=no);Here is the new output. Note that "Hispanic" has gone. Note another thing - the races are in format order. This is why it is better to use variables with formats attached, so you can keep this order. If it were a decoded race field then there is no way the macro would know which order to display them in and would display them in alphabetical order. You usually want to display in the order shown on the Case Report Form so it is better to store this as a numeric variable and to use a format for this to keep the order the same as in the CRF. %unistats will know that although it is a numeric variable then it is a categorical variable because it has a user-defined format assigned to it.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17)
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2)
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3)
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
N 9 8 17
Min. 16.0 16.0 16.0
Mean 26.3 24.0 25.2
Max. 40.0 36.0 40.0
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min. 65.5 65.5 65.5
Mean 76.6 70.8 73.8
Max. 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min. 175.0 175.0 175.0
Mean 197.2 182.3 190.2
Max. 212.0 200.0 212.0
STD. 11.94 9.00 12.89
Demo 6
Looking at all the outputs so far, displaying the minimum and maximum age with a decimal point is not a good idea as age is an integer number of years. The format for MIN and MAX can be changed to an integer format by setting minfmt=3. and maxfmt=3. . This has an effect on all the numeric values, though, so we will need to adjust this for weight and height. We have more than one way of handling this. You have to be aware of these options so you can choose the best one for your report. Here is the first attempt at this. We will see that it is not ideal. Look in the macro call for the "/+1" added onto the end of the weight and height variables.
/* Demonstrate %unistats: program 6 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
format trtcd trtnarr.;
label sexcd="Gender"
racecd="Race"
age="Age (yrs)"
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%unistats(dsin=demog,total=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min. Mean Max. STD.,
minfmt=3.,maxfmt=3.,
varlist=sexcd racecd age weight/+1 height/+1);This is the new output. Look what has happened to the number of decimal places for weight and height compared to age. The age format is now correct but weight and height show too many decimal places. We will see that there is a better way of adjusting the number of decimal places shown in the next demo.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17)
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2)
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3)
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
N 9 8 17
Min. 16 16 16
Mean 26.3 24.0 25.2
Max. 40 36 40
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min. 65.5 65.5 65.5
Mean 76.56 70.75 73.82
Max. 79.6 78.1 79.6
STD. 4.357 5.687 5.706Height (cm)
N 9 8 17
Min. 175.0 175.0 175.0
Mean 197.22 182.25 190.18
Max. 212.0 200.0 212.0
STD. 11.935 9.004 12.885
Demo 7
Fortunately there is another way to adjust the number of decimal places for variables and that is using "/m". This makes the "mean" format apply to the Min and Max as well. Look for the "/m" in the call to the macro. Just to show you the use of some other parameters, I will change the indentation of the categories and stats words to three spaces using indent=3 and change the spacing between the treatment columns to six spaces using trtspace=6. I will also change the alignment of the treatment column headers.
/* Demonstrate %unistats: program 7 */
proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
format trtcd trtnarr.;
label sexcd="Gender"
racecd="Race"
age="Age (yrs)"
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%unistats(dsin=demog,total=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min. Mean Max. STD.,
minfmt=3.,maxfmt=3.,
indent=3,trtspace=6,trtalign=left,
varlist=sexcd racecd age weight/m height/m);Here is the new output. Weight and height are back to how they were displayed originally. The indentation, column spacing and column header alignment have changed.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17)
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2)
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3)
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
N 9 8 17
Min. 16 16 16
Mean 26.3 24.0 25.2
Max. 40 36 40
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min. 65.5 65.5 65.5
Mean 76.6 70.8 73.8
Max. 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min. 175.0 175.0 175.0
Mean 197.2 182.3 190.2
Max. 212.0 200.0 212.0
STD. 11.94 9.00 12.89
Demo 8
Sometimes you will want to look at a value two ways. In our example, we might want to show age as categories and to have all these categories displayed, followed by the summary statistics. This can be done by setting up an extra variable. It would also be good if we could keep these two sets of results close together separated by a single line instead of two. This can be done by setting the variable label to the "A0"x character. Look for the highlighted changes to the code.
/* Demonstrate %unistats: program 8 */ proc format;
value agecat
0-15="<16 yrs"
16-25=" 16 - 25 yrs"
26-40=" 26 - 40 yrs"
41-65=" 41 - 65 yrs"
66-high=">65 years"
;
run;proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
agecat=age;
format trtcd trtnarr. agecat agecat.;
label sexcd="Gender"
racecd="Race"
agecat="Age (yrs)"
age="A0"x
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%unistats(dsin=demog,total=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min. Mean Max. STD.,
minfmt=3.,maxfmt=3.,
indent=3,trtspace=6,
varlist=sexcd racecd agecat age weight/m height/m);This is the new output with the age categories added. Note that there is only one line between the age category and the age variable as a result of using the "A0"x character as the variable label for "age".
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17)
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2)
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3)
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
<16 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
16 - 25 yrs 4 ( 44.4) 4 ( 50.0) 8 ( 47.1)
26 - 40 yrs 5 ( 55.6) 4 ( 50.0) 9 ( 52.9)
41 - 65 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
>65 years 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)N 9 8 17
Min. 16 16 16
Mean 26.3 24.0 25.2
Max. 40 36 40
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min. 65.5 65.5 65.5
Mean 76.6 70.8 73.8
Max. 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min. 175.0 175.0 175.0
Mean 197.2 182.3 190.2
Max. 212.0 200.0 212.0
STD. 11.94 9.00 12.89
Demo 9
The %unistats macro can calculate p-values using a call to its submacro %unipvals. Let us ask for p-values to be calculated for all these variables to see what it gives us. It will create an extra column so I will remove the trtspace=6 setting and allow it to default, as there will not be enough room otherwise.
/* Demonstrate %unistats: program 9 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
agecat=age;
format trtcd trtnarr. agecat agecat.;
label sexcd="Gender"
racecd="Race"
agecat="Age (yrs)"
age="A0"x
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%unistats(dsin=demog,total=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min Mean Max STD.,
minfmt=3.,maxfmt=3.,indent=3,
varlist=sexcd racecd agecat age weight/m height/m,
statvarlist=sexcd racecd agecat age weight height);Here is the output with p-values added. Note the symbols after the p-value. You can see "^" and "#" being used. "^" is for Fisher's Exact test, "#" is for the ANOVA F-test. The "Total" treatment arm is excluded from the p-value calculation. These symbols used after the p-values need to be explained somewhere and it is assumed you will explain them in footnotes. You can change these symbols if you wish as they are defaults defined to parameters when you call the macro.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17) p-value
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2) >0.999^
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3) 0.239^
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
<16 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0) >0.999^
16 - 25 yrs 4 ( 44.4) 4 ( 50.0) 8 ( 47.1)
26 - 40 yrs 5 ( 55.6) 4 ( 50.0) 9 ( 52.9)
41 - 65 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
>65 years 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)N 9 8 17
Min 16 16 16
Mean 26.3 24.0 25.2 0.569#
Max 40 36 40
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min 65.5 65.5 65.5
Mean 76.6 70.8 73.8 0.031#
Max 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min 175.0 175.0 175.0
Mean 197.2 182.3 190.2 0.011#
Max 212.0 200.0 212.0
STD. 11.94 9.00 12.89
Now we have seen the p-values column for the first time I will show another two small demos. The p-values are in the STAT1 column. There is a STAT0 column that by default is not shown. This contains the original test value that gets mapped to the p-value. This is not normally required but showing it is a regulatory requirements for China's State Food and Drug Administration (the SFDA) so it is a simple matter to activate this column using the showstat0=yes setting.
options ls=90; %unistats(dsin=demog,total=yes,showstat0=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min Mean Max STD.,
minfmt=3.,maxfmt=3.,indent=3,
varlist=sexcd racecd agecat age weight/m height/m,
statvarlist=sexcd racecd agecat age weight height);options ls=78;
Here you see the output with the extra "Value" column showing the F-test values (there is no corresponding test value for the Fisher exact test).
__________________________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17) Value p-value
__________________________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2) >0.999^
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3) 0.239^
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
<16 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0) >0.999^
16 - 25 yrs 4 ( 44.4) 4 ( 50.0) 8 ( 47.1)
26 - 40 yrs 5 ( 55.6) 4 ( 50.0) 9 ( 52.9)
41 - 65 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
>65 years 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)N 9 8 17
Min 16 16 16
Mean 26.3 24.0 25.2 0.34 0.569#
Max 40 36 40
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min 65.5 65.5 65.5
Mean 76.6 70.8 73.8 5.66 0.031#
Max 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min 175.0 175.0 175.0
Mean 197.2 182.3 190.2 8.34 0.011#
Max 212.0 200.0 212.0
STD. 11.94 9.00 12.89
The p-value for the F-test will be the same as the t-Test in most cases. You can specifically ask to use the t-Test instead of the ANOVA F-test so that you see the t-Test value (which will be the square root of the F-test values). Also, if you request the t-Test, you can change the default sattcond=<0.1 setting to show the Satterthwaite approximation of the p-values where there is an inequality of variances. Here is the same call again but asking for the t-Test.
options ls=90; %unistats(dsin=demog,total=yes,showstat0=yes,usettest=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min Mean Max STD.,
minfmt=3.,maxfmt=3.,indent=3,
varlist=sexcd racecd agecat age weight/m height/m,
statvarlist=sexcd racecd agecat age weight height);options ls=78;
You will see that the p-values are the same but the t-values are shown instead of the F-values (which are the square root of the F-values).
__________________________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17) Value p-value
__________________________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2) >0.999^
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3) 0.239^
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
<16 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0) >0.999^
16 - 25 yrs 4 ( 44.4) 4 ( 50.0) 8 ( 47.1)
26 - 40 yrs 5 ( 55.6) 4 ( 50.0) 9 ( 52.9)
41 - 65 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
>65 years 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)N 9 8 17
Min 16 16 16
Mean 26.3 24.0 25.2 0.58 0.569#
Max 40 36 40
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min 65.5 65.5 65.5
Mean 76.6 70.8 73.8 2.38 0.031#
Max 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min 175.0 175.0 175.0
Mean 197.2 182.3 190.2 2.89 0.011#
Max 212.0 200.0 212.0
STD. 11.94 9.00 12.89
Demo 10
Note that in Demo 9, Fisher's Exact test was chosen for all the categorical variables. This was done automatically by the macro using a decision algorithm known as "Cochran's Recommendation" based on "expected" cell counts. The default is to use the Chi-Squared test but because of the low expected cell counts detected it decided to use Fisher's Exact test in all cases. You can force tests on variables instead of allowing the macro to decide for you and you will want to do this in most cases. I will force Gender to use the chi-square test and the others to use Fisher's Exact test. I will also add the footnotes explaining the symbols at the end of the p-values.
/* Demonstrate %unistats: program 10 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
agecat=age;
format trtcd trtnarr. agecat agecat.;
label sexcd="Gender"
racecd="Race"
agecat="Age (yrs)"
age="A0"x
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%lafootnote(1,"%sysfunc(repeat(_,200))")
%lafootnote(2,"~ Chi-square test")
%lafootnote(3,"^ Fisher's Exact test")
%lafootnote(4,"# Student's t test")%unistats(dsin=demog,total=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd,
descstats=N Min. Mean Max. STD.,
minfmt=3.,maxfmt=3.,indent=3,
varlist=sexcd racecd agecat age weight/m height/m,
statvarlist=sexcd racecd agecat age weight height,
chisqvarlist=sexcd,
fishervarlist=racecd agecat);Here is the new output with the Chi-square test used for Gender and footnotes added to explain the p-value symbols.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17) p-value
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2) 0.772~
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3) 0.239^
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
<16 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0) >0.999^
16 - 25 yrs 4 ( 44.4) 4 ( 50.0) 8 ( 47.1)
26 - 40 yrs 5 ( 55.6) 4 ( 50.0) 9 ( 52.9)
41 - 65 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
>65 years 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)N 9 8 17
Min. 16 16 16
Mean 26.3 24.0 25.2 0.569#
Max. 40 36 40
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min. 65.5 65.5 65.5
Mean 76.6 70.8 73.8 0.031#
Max. 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min. 175.0 175.0 175.0
Mean 197.2 182.3 190.2 0.011#
Max. 212.0 200.0 212.0
STD. 11.94 9.00 12.89
______________________________________________________________________________
~ Chi-square test
^ Fisher's Exact test
# Student's t test
Demo 11
When using Fisher's Exact test for Race, each category counted. Sometimes you will want to compare the main category with the other categories combined, in this case "Caucasian" compared to all others, while at the same time displaying all the minor categories. First of all, I have changed the code to set up an extra variable.
/* Demonstrate %unistats: program 11 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
agecat=age;
racecd2=racecd;
if racecd2 ne 1 then racecd2=5;
format trtcd trtnarr. agecat agecat. racecd2 racecd.;
label sexcd="Gender"
racecd="Race"
racecd2="Race"
agecat="Age (yrs)"
age="A0"x
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%lafootnote(1,"%sysfunc(repeat(_,200))")
%lafootnote(2,"~ Chi-square test")
%lafootnote(3,"^ Fisher's Exact test")
%lafootnote(4,"# Student's t test")%unistats(dsin=demog,total=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd racecd2,
descstats=N Min. Mean Max. STD.,
minfmt=3.,maxfmt=3.,indent=3,
varlist=sexcd racecd racecd2 agecat age weight/m height/m,
statvarlist=sexcd racecd racecd2 agecat age weight height,
chisqvarlist=sexcd,
allcat=no,allcatvars=racecd agecat,
fishervarlist=racecd racecd2 agecat);Here is the new output with the second race variable added directly after the original race code variable. Somehow, we want to display the "0.131" value with a new symbol in the "Caucasian" line above and to get rid of the second race code variable. Fortunately, that is easy to do using the filtercode= parameter. You have seen a single line of filtercode= code in demo 10.5 but you are not limited to one line of code.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17) p-value
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2) 0.772~
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3) 0.239^
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3) 0.131^
Other 4 ( 44.4) 7 ( 87.5) 11 ( 64.7)Age (yrs)
<16 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0) >0.999^
16 - 25 yrs 4 ( 44.4) 4 ( 50.0) 8 ( 47.1)
26 - 40 yrs 5 ( 55.6) 4 ( 50.0) 9 ( 52.9)
41 - 65 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
>65 years 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)N 9 8 17
Min. 16 16 16
Mean 26.3 24.0 25.2 0.569#
Max. 40 36 40
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min. 65.5 65.5 65.5
Mean 76.6 70.8 73.8 0.031#
Max. 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min. 175.0 175.0 175.0
Mean 197.2 182.3 190.2 0.011#
Max. 212.0 200.0 212.0
STD. 11.94 9.00 12.89
______________________________________________________________________________
~ Chi-square test
^ Fisher's Exact test
# Student's t test
Demo 12
Here is the change to the code to display the "0.131" value in the first race variable and to delete the second race variable. Also, the footnote symbol will be changed and a new footnote added.
/* Demonstrate %unistats: program 12 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
agecat=age;
racecd2=racecd;
if racecd2 ne 1 then racecd2=5;
format trtcd trtnarr. agecat agecat. racecd2 racecd.;
label sexcd="Gender"
racecd="Race"
racecd2="Race"
agecat="Age (yrs)"
age="A0"x
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%lafootnote(1,"%sysfunc(repeat(_,200))")
%lafootnote(2,"~ Chi-square test")
%lafootnote(3,"° Fisher's Exact test comparing Caucasian with all other categories combined")
%lafootnote(4,"° Fisher's Exact test")
%lafootnote(5,"# Student's t test")%unistats(dsin=demog,total=yes,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
lowcasevarlist=sexcd racecd racecd2,
descstats=N Min. Mean Max. STD.,
minfmt=3.,maxfmt=3.,indent=3,
varlist=sexcd racecd racecd2 agecat age weight/m height/m,
statvarlist=sexcd racecd racecd2 agecat age weight height,
chisqvarlist=sexcd,
filtercode=
if _varord=2 and _statord=1 then delete;
else if _varord=3 then do;
if _statord ne 1 then delete;
else do;
_varord=2;
substr(STAT1,7,1)="°";
end;
end;
allcat=no,allcatvars=racecd agecat,
fishervarlist=racecd racecd2 agecat);
Here is the new output and you can see that we have combined the two "race" variables.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17) p-value
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2) 0.772~
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3) 0.131°
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
<16 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0) >0.999^
16 - 25 yrs 4 ( 44.4) 4 ( 50.0) 8 ( 47.1)
26 - 40 yrs 5 ( 55.6) 4 ( 50.0) 9 ( 52.9)
41 - 65 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
>65 years 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)N 9 8 17
Min. 16 16 16
Mean 26.3 24.0 25.2 0.569#
Max. 40 36 40
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min. 65.5 65.5 65.5
Mean 76.6 70.8 73.8 0.031#
Max. 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min. 175.0 175.0 175.0
Mean 197.2 182.3 190.2 0.011#
Max. 212.0 200.0 212.0
STD. 11.94 9.00 12.89
______________________________________________________________________________
~ Chi-square test
° Fisher's Exact test comparing Caucasian with all other categories combined
° Fisher's Exact test
# Student's t test
Demo 13
You can control the way p-values are displayed. It will display them in a column by default but it is easy to override this. The p-values are written to global macro variables named _pvalue1_ , _pvalue2_ etc. where the number is the same as the _varord value. Suppose I only wanted to show a few p-values in the footnotes? It is easy enough to do but you have to remember that the p-values will be created within the macro so you can't define your footnotes before the macro and try to resolve the p-values since they won't have been calculated at that stage. Or if you forgot this then you would end up resolving the p-values from the previous call of the macro which would give you the wrong result. There are two ways to get around this problem. One is to break the flow of the %unistats macro and define your footnotes before it does its final print. This is the hard way of doing it that is not recommended. The second way is to define a titles and footnotes macro and tell the name of the macro to the tfmacro= parameter (this macro can have parameters itself if you like).The following example makes the filtercode= easier than the previous example now that I will be displaying p-values in the footnotes. I can just delete the _varord=3 observations as it will have already calculated the p-values and placed the results in _pvalue3_ so I don't need those observations any more. The macro %unicatrep is the one that produces the report and the internal dataset to %unistats is called _unitran.
/* Demonstrate %unistats: program 13 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
agecat=age;
racecd2=racecd;
if racecd2 ne 1 then racecd2=5;
format trtcd trtnarr. agecat agecat. racecd2 racecd.;
label sexcd="Gender"
racecd="Race"
racecd2="Race"
agecat="Age (yrs)"
age="A0"x
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%unistats(dsin=demog,total=yes,print=no,
lowcasevarlist=sexcd racecd racecd2,
descstats=N Min Mean Max STD.,
minfmt=3.,maxfmt=3.,
varlist=sexcd racecd racecd2 agecat age weight/m height/m,
statvarlist=sexcd racecd racecd2 agecat age weight height,
chisqvarlist=sexcd,
fishervarlist=racecd racecd2 agecat,
allcat=no,allcatvars=racecd agecat,
filtercode=if _varord=3 then delete);
%lafootnote(1,"%sysfunc(repeat(_,200))")
%lafootnote(2,"Chi-square test for gender: &_pvalue1_")
%lafootnote(3,"Fisher's Exact test comparing Caucasian with all other categories: &_pvalue3_")
%lafootnote(4,"Fisher's Exact test for age categories: &_pvalue4_")
%lafootnote(5,"Student's t test for weight: &_pvalue6_")
%unicatrep(dsin=_unitran,indent=3,showstat1=no,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ");Here is the output with p-values displayed in footnotes.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17)
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2)
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3)
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
<16 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
16 - 25 yrs 4 ( 44.4) 4 ( 50.0) 8 ( 47.1)
26 - 40 yrs 5 ( 55.6) 4 ( 50.0) 9 ( 52.9)
41 - 65 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
>65 years 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)N 9 8 17
Min. 16 16 16
Mean 26.3 24.0 25.2
Max. 40 36 40
STD. 8.03 8.49 8.07Weight (kg)
N 9 8 17
Min. 65.5 65.5 65.5
Mean 76.6 70.8 73.8
Max. 79.6 78.1 79.6
STD. 4.36 5.69 5.71Height (cm)
N 9 8 17
Min. 175.0 175.0 175.0
Mean 197.2 182.3 190.2
Max. 212.0 200.0 212.0
STD. 11.94 9.00 12.89______________________________________________________________________________
Chi-square test for gender: 0.772
Fisher's Exact test comparing Caucasian with all other categories: 0.131
Fisher's Exact test for age categories: >0.999
Student's t test for weight: 0.031
Demo 14
Defining a titles and footnotes macro and giving the name of the macro to the tfmacro= parameter is the preferred method to use rather than breaking the flow of the %unistats macro. I will show you the code to do that next but I want to show you another feature as well that will also be dealt with elsewhere. For the descriptive statistics, you have seen one per line. It is actually possible to have two per line, although you would lose decimal point alignment. In the next example I will combine Min. and Max. and the Mean and standard deviation. No spaces are allowed between paired statistics but if you want to show a space, sucn as between the mean and the S.D. in the following brackets, then you can use a "^" character and it will be converted to a space both in the label and the displayed values. The macro does not know how many columns you need to display the two values so you need to tell it with the mincolw= (minimum column width) parameter. I know I am going to lose decimal point alignment so I will set dpalign=no.My titles and footnotes macro is very simple and does not have parameters but parameters are allowed. Note that when you give its name to tfmacro= then you do not use the "%" sign.
(If you normally create footnotes using a proc report compute block so that you can exceed the 10 footnote limit when required then this is not a problem as there are parameters endmacro= and pagemacro= that allow for macros that generate compute block syntax code for generating footnotes. It is explained here).
/* Demonstrate %unistats: program 14 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
agecat=age;
racecd2=racecd;
if racecd2 ne 1 then racecd2=5;
format trtcd trtnarr. agecat agecat. racecd2 racecd.;
label sexcd="Gender"
racecd="Race"
racecd2="Race"
agecat="Age (yrs)"
age="A0"x
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid);
%macro tf;
%lafootnote(1,"%sysfunc(repeat(_,200))")
%lafootnote(2,"Chi-square test for gender: &_pvalue1_")
%lafootnote(3,"Fisher's Exact test comparing Caucasian with all other categories: &_pvalue3_")
%lafootnote(4,"Fisher's Exact test for age categories: &_pvalue4_")
%lafootnote(5,"Student's t test for weight: &_pvalue6_")
%mend tf;%unistats(dsin=demog,total=yes,tfmacro=tf,mincolw=13,dpalign=no,
lowcasevarlist=sexcd racecd racecd2,
descstats=N Min-Max Mean^(STD.),
minfmt=3.,maxfmt=3.,
indent=3,showstat1=no,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
varlist=sexcd racecd racecd2 agecat age weight/m height/m,
statvarlist=sexcd racecd racecd2 agecat age weight height,
chisqvarlist=sexcd,
fishervarlist=racecd racecd2 agecat,
allcat=no,allcatvars=racecd agecat,
filtercode=if _varord=3 then delete);
And here is the output.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17)
______________________________________________________________________________Gender
Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2)
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race
Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3)
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs)
<16 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
16 - 25 yrs 4 ( 44.4) 4 ( 50.0) 8 ( 47.1)
26 - 40 yrs 5 ( 55.6) 4 ( 50.0) 9 ( 52.9)
41 - 65 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
>65 years 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)N 9 8 17
Min-Max 16-40 16-36 16-40
Mean (STD.) 26.3 (8.03) 24.0 (8.49) 25.2 (8.07)Weight (kg)
N 9 8 17
Min-Max 65.5-79.6 65.5-78.1 65.5-79.6
Mean (STD.) 76.6 (4.36) 70.8 (5.69) 73.8 (5.71)Height (cm)
N 9 8 17
Min-Max 175.0-212.0 175.0-200.0 175.0-212.0
Mean (STD.) 197.2 (11.94) 182.3 (9.00) 190.2 (12.89)
______________________________________________________________________________
Chi-square test for gender: 0.772
Fisher's Exact test comparing Caucasian with all other categories: 0.131
Fisher's Exact test for age categories: >0.999
Student's t test for weight: 0.031
Demo 15
You can change the style of the output report so that the variable labels have their own column by using style 2. If calling unistats then you can set this style using unicatstyle=2 (%unicatrep is the name of the macro that does the print hence the name of the parameter) but if you are calling %unicatrep directly, as in demo 13, then you just set style=2 when you call %unicatrep.
/* Demonstrate %unistats: program 15 */ proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;data demog;
set demog;
agecat=age;
racecd2=racecd;
if racecd2 ne 1 then racecd2=5;
format trtcd trtnarr. agecat agecat. racecd2 racecd.;
label sexcd="Gender"
racecd="Race"
racecd2="Race"
agecat="Age (yrs)"
age="A0"x
weight="Weight (kg)"
height="Height (cm)"
;
run;%popfmt(demog,trtcd,uniqueid=patno invid);
%macro tf;
%lafootnote(1,"%sysfunc(repeat(_,200))")
%lafootnote(2,"Chi-square test for gender: &_pvalue1_")
%lafootnote(3,"Fisher's Exact test comparing Caucasian with all other categories: &_pvalue3_")
%lafootnote(4,"Fisher's Exact test for age categories: &_pvalue4_")
%lafootnote(5,"Student's t test for weight: &_pvalue6_")
%mend tf;%unistats(dsin=demog,total=yes,tfmacro=tf,mincolw=13,unicatstyle=2,trtalign=left,
lowcasevarlist=sexcd racecd racecd2,
descstats=N Min-Max Mean^(STD.),
minfmt=3.,maxfmt=3.,
indent=3,showstat1=no,
trtlabel="Number of Patients (%) /" "Descriptive Statistics" " ",
varlist=sexcd racecd racecd2 agecat age weight/m height/m,
statvarlist=sexcd racecd racecd2 agecat age weight height,
chisqvarlist=sexcd,
fishervarlist=racecd racecd2 agecat,
allcat=no,allcatvars=racecd agecat,
filtercode=if _varord=3 then delete);Here you see the separate columns that result. I left aligned the treatment columns as well to remind you that this can be done.
______________________________________________________________________________ Number of Patients (%) /
Descriptive StatisticsAmbident Betamax
(1g/day) (500mg/day) Total
(N=9) (N=8) (N=17)
______________________________________________________________________________Gender Male 4 ( 44.4) 3 ( 37.5) 7 ( 41.2)
Female 5 ( 55.6) 5 ( 62.5) 10 ( 58.8)Race Caucasian 5 ( 55.6) 1 ( 12.5) 6 ( 35.3)
Black 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Asian 2 ( 22.2) 3 ( 37.5) 5 ( 29.4)
Hispanic 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
Other 0 ( 0.0) 1 ( 12.5) 1 ( 5.9)Age (yrs) <16 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
16 - 25 yrs 4 ( 44.4) 4 ( 50.0) 8 ( 47.1)
26 - 40 yrs 5 ( 55.6) 4 ( 50.0) 9 ( 52.9)
41 - 65 yrs 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)
>65 years 0 ( 0.0) 0 ( 0.0) 0 ( 0.0)N 9 8 17
Min-Max 16-40 16-36 16-40
Mean (STD.) 26.3 (8.03) 24.0 (8.49) 25.2 (8.07)Weight (kg) N 9 8 17
Min-Max 65.5-79.6 65.5-78.1 65.5-79.6
Mean (STD.) 76.6 (4.36) 70.8 (5.69) 73.8 (5.71)Height (cm) N 9 8 17
Min-Max 175.0-212.0 175.0-200.0 175.0-212.0
Mean (STD.) 197.2 (11.94) 182.3 (9.00) 190.2 (12.89)______________________________________________________________________________
Chi-square test for gender: 0.772
Fisher's Exact test comparing Caucasian with all other categories: 0.131
Fisher's Exact test for age categories: >0.999
Student's t test for weight: 0.031
Demo 16
You have seen how flexible %unistats is for matching statistics labels with keywords and displaying them correctly. Sometimes, however, you need more than what is can automatically handle such that "CSS", for example, is given a better label such as "Corr. SSQ" (Corrected sum of squares) and "SIGNRANK" gets displayed as "Sign Rank". There is a macro named %unistatlabel that does this that %unistats calls. You are free to copy it and make your own version to suit your site standards, just as for %unimap. The current code that does these label mappings is as follows:
%macro unistatlabel;
if upcase(_statlabel) EQ "PROBN" then _statlabel="Prob Norm";
else if upcase(_statlabel) EQ "PROBM" then _statlabel="Prob >=|M|";
else if upcase(_statlabel) EQ "PROBS" then _statlabel="Prob >=|S|";
else if upcase(_statlabel) EQ "PROBT" then _statlabel="Prob > |t|";
else if upcase(_statlabel) EQ "MSIGN" then _statlabel="M(Sign)";
else if upcase(_statlabel) EQ "SIGNRANK" then _statlabel="Sign Rank";
else if upcase(_statlabel) EQ "USS" then _statlabel="Uncorr. SSQ";
else if upcase(_statlabel) EQ "CSS" then _statlabel="Corr. SSQ";
else if upcase(_statlabel) EQ "SUMWGT" then _statlabel="Sum of weights";
else if upcase(_statlabel) EQ "QRANGE" then _statlabel="Q3 - Q1";
else if upcase(_statlabel) EQ "(LCLM75,UCLM75)" then _statlabel="75% CIs (Mean)";
else if upcase(_statlabel) EQ "(LCLM90,UCLM90)" then _statlabel="90% CIs (Mean)";
else if upcase(_statlabel) EQ "(LCLM92,UCLM92)" then _statlabel="92% CIs (Mean)";
else if upcase(_statlabel) EQ "(LCLM,UCLM)" then _statlabel="95% CIs (Mean)";
else if upcase(_statlabel) EQ "(LCLM95,UCLM95)" then _statlabel="95% CIs (Mean)";
else if upcase(_statlabel) EQ "(LCLM97,UCLM97)" then _statlabel="97% CIs (Mean)";
else if upcase(_statlabel) EQ "(LCLM98,UCLM98)" then _statlabel="98% CIs (Mean)";
else if upcase(_statlabel) EQ "(LCLM99,UCLM99)" then _statlabel="99% CIs (Mean)";
else if upcase(_statlabel) EQ "(LCL75,UCL75)" then _statlabel="75% CIs";
else if upcase(_statlabel) EQ "(LCL90,UCL90)" then _statlabel="90% CIs";
else if upcase(_statlabel) EQ "(LCL92,UCL92)" then _statlabel="92% CIs";
else if upcase(_statlabel) EQ "(LCL,UCL)" then _statlabel="95% CIs";
else if upcase(_statlabel) EQ "(LCL95,UCL95)" then _statlabel="95% CIs";
else if upcase(_statlabel) EQ "(LCL97,UCL97)" then _statlabel="97% CIs";
else if upcase(_statlabel) EQ "(LCL98,UCL98)" then _statlabel="98% CIs";
else if upcase(_statlabel) EQ "(LCL99,UCL99)" then _statlabel="99% CIs";
%mend unistatlabel;You always have the option of using the filtercode= parameter to change statistics labels into something better but more often you will find it more convenient to rely on the %unistatlabel macro.
Here is a very simple call to %unistats using a few of these parameters using just the "weight" variable. Note that for some of these terms you have to ask for the standard deviation.
/* Demonstrate %unistats: program 16 */ footnote1;
proc sort data=sasuser.demog(where=(fascd=1))
out=demog(drop=fascd);
by patno invid;
run;%popfmt(demog,trtcd,uniqueid=patno invid)
%unistats(dsin=demog,
descstats=N Mean^(S.D.) probm probt uss (lclm,uclm) (lcl,ucl),
varlist=weight);And here is the output.
______________________________________________________________________________ Ambident (1g/day) Betamax (500mg/day)
(N=9) (N=8)
______________________________________________________________________________WEIGHT (KG)
N 9 8
Mean (S.D.) 76.6 (4.36) 70.8 (5.69)
Prob >=|M| 0.004 0.008
Prob > |t| <0.001 <0.001
Uncorr. SSQ 52899 40271
95% CIs (Mean) (73.2,79.9) (66.0,75.5)
95% CIs (66.5,86.6) (57.3,84.2)
Of most concern to you will be having enough width for the column that lists the categories and the descriptive statistics labels. This was anticipated, so this macro gives you the maximum width available that is the rest of the defined line size once all the other columns have had their share. You can actually give a value to the width using the catw= parameter but this is to reduce the width from the maximum. It does not guarantee that width since it can not be taken away from the other widths. If you set it to more than is available it will be reduced to the maximum permissible. You may think you would never need to reduce the width but if you look at the demo output directly above you can see that there is a large gap between the descriptive statistics labels and the values and it is here you would use catw= to reduce the width of the column so as to bring the values closer to their labels.
If you need more room for your category column then you have to make room elsewhere. If you look at the output above you can see the treatment arm columns are quite wide because the dose is shown alongside the drug name. We can use a "narrow format" instead, with a split character between the drug name and dose, like I did in demo 4 and this will save valuable space. By default, a gap of 4 spaces is left between treatment arms due to the default setting trtspace=4. Try reducing it to 2 if you need more room. Sometimes you will be able to use trtspace=1 and where two columns look uncomfortably close together you can adjust the individual gap before the second column using the trtsp1-19 parameters to set the one you need to the value 2 to give you more separation. If you are using a byrow which is restricting space then by default, byroww=12 (the byrow column width) so perhaps you can set this to a smaller value.
Individual treatment arm column widths can be set using the trtw1-19 parameters. Additionally there is mincolw= that sets the minimum width of all the treatment arm columns but this is mainly intended when you are pairing statistic values and so you need to tell the macro how wide the columns will be as the macro can not work it out itself.
Of course, there is always the option of increasing the line size to make more room, but you may be restricted by your site standards.
Freqsept parameters in %unistats
Use the "Back" button of your browser to return to the previous page.
SAS and all other SAS Institute Inc. product or service names are registered trademarks or trademarks of SAS Institute Inc. in the USA and other countries. ® indicates USA registration.