%unistats (v9.x)

Last Updated: 06 Nov 2011

Introduction

There are two major reporting macros in Spectre - %npcttab and %unistats. These two macros do the bulk of safety and demography tables and %unistats is intended to do the bulk of efficacy reporting as well. This page is about %unistats. Its name gives a clue as to what it does; the "uni" comes from "proc univariate" and the "stats" are the statistics it calculates. These are "descriptive statistics" such as "N", "Min", "Mean", "Median", "Max" and "Standard Deviation". It also calculates category counts and percentages that you will be used to seeing in demography tables. Features of the macro are listed below.

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.

Automation using %unistats

The macro is aimed at making automatic reporting possible so it is designed to be extremely easy to call. By setting only two parameters, dsin= and varlist= it will produce a report. Though the macro has 100+ parameters that can be set, you are expected to use the minimum. Most of the parameters are there to fine tune the layout and most of these you will never use. Because of the large number of parameters, learning how to use the macro from reading the header is impossible, just as it is for the %npcttab macro. You will need a simple introduction to the macro and that is what you will find on this page. Once you have learned to use the macro in the simple cases explained then you will be able to benefit from reading the macro header to learn about its other capabilities. Once you feel you would like to look at the macro in more detail, you can link to it below as well as the major sub-macros it calls to calculate p-values and produce a report.
%unistats
%unipvals
%unicatrep

%popfmt and %unistats

The macro %popfmt has to be called before %unistats. These two macro are connected. When you calculate percentages for categorical variables, this percentage will be based on the treatment population by default, rather than overall counts. For this it will use the _popfmt dataset created by the %popfmt macro call. To calculate percentages based on overall category counts instead, you will have to use the setting pctcalc=cat.
 

Features of %unistats

Demonstrating %unistats

You will be introduced to the features of %unistats using demonstrations showing you code and output. You must have already set up two datasets in your sasuser area as described on this page. If you have not done this then please exit this page and do so before returning.

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.0 

WEIGHT (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.1 

HEIGHT (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 Statistics

                                      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 
    Min.                                  16.0                  16.0 
    Mean                                  26.3                  24.0 
    Max.                                  40.0                  36.0 
    STD.                                   8.03                  8.49 

WEIGHT (KG)
    N                                      9                     8 
    Min.                                  65.5                  65.5 
    Mean                                  76.6                  70.8 
    Max.                                  79.6                  78.1 
    STD.                                   4.36                  5.69 

HEIGHT (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 Statistics

                       Ambident (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.07 

Weight (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.71 

Height (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 Statistics

                                      Ambident        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.07 

Weight (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.71 

Height (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 Statistics

                                      Ambident        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.07 

Weight (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.71 

Height (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 Statistics

                                      Ambident        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.07 

Weight (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.706 

Height (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 Statistics

                                 Ambident         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.07 

Weight (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.71 

Height (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 Statistics

                                  Ambident          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.07 

Weight (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.71 

Height (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 Statistics

                          Ambident        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.07 

Weight (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.71 

Height (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 Statistics

                            Ambident        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.07 

Weight (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.71 

Height (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 Statistics

                            Ambident        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.07 

Weight (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.71 

Height (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 Statistics

                          Ambident        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.07 

Weight (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.71 

Height (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 Statistics

                          Ambident        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.07 

Weight (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.71 

Height (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 Statistics

                          Ambident        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.07 

Weight (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.71 

Height (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 Statistics

                                      Ambident        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.07 

Weight (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.71 

Height (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 Statistics

                                 Ambident          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 Statistics

                               Ambident         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)

 

Controlling column widths

One of the things that will consume your time if you use this macro is controlling the column widths. This section explains the ideas behind it to give you an understanding of what is the best approach.

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.

ISS Reporting

This concludes the demos for %unistats on this page. Another important field is ISS Reporting. %unistats works in the same way as %npcttab for ISS Reporting so I would just like to state that on this page and for you to use the documentation provided with %npcttab to show you how to organise the data for this. Once you know how %npcttab works for ISS Reporting then the same applies to %unistats.

Further statistical functionality

You have seen that %unistats can calculate p-values for you. Sometimes this is not enough. On the following page you will see how you can place statistical values from ods tables anywhere you like in the report. In this way, %unistats can do the bulk of efficacy reporting for you. This is a very advanced topic and you may want to skip this page.

Freqsept parameters in %unistats

Conclusion

You have been introduced to the power of the %unistats macro through these demonstration programs and their output. There is still a great deal to learn about this very powerful macro. Having reached this stage you should be able to learn how to use the macro further from reading its header and the headers of its submacros. You can view these macro below.
%unistats
%unipvals
%unicatrep
 


 

Use the "Back" button of your browser to return to the previous page.

contact the author





























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.