my code stock.com

Richard Baxter

Percentages for non-mutually exclusive groups
by Richard Baxter

A simple way to output figures on non-mutually exclusive groups (e.g. co-morbidities, therapy groups).
Also takes into account patients without data for groups.

An advantage of this method is that you don't need to create patient level count variable
for each level of the group variable.  This approach allows you to use the event tables directly.

Snippet options

Download: Download snippet as percentages-for-non-mutually-exclusive-groups.txt.
Copy snippet: For this you need a free my code stock.com account.
Embed code : You will find the embed code for this snippet at the end of the page, if you want to embed it into a website or a blog!

/********************************************************************************************************
**  Program name:     TST_Perc_Non_Mut_Excl_Groups.sas
**  Author:           Richard Baxter                 Date Created: May, 2014
**  SAS Version:      9.1.3                                    OS: Unix
**
**  ---- Purpose ----
**
**  A simple way to output figures on non-mutually exclusive groups (e.g. co-morbidities, therapy groups).  
**  Also takes into account patients without data for groups.
**
**  An advantage of this method is that you don't need to create patient level count variable 
**  for each level of the group variable.  This approach allows you to use the event tables directly.
**
**  Test data is provided so this program can be run to see the data needed and the expect outcome
**
*********************************************************************************************************/

  options nodate nonumber nocenter pageno=1 obs=max nofmterr ps=52 ls=100;
  options mergenoby=warn msglevel=i;
  options formchar="|----||---|-/\<>*";
  ods noproctitle;  

  *************************;
  **  Create the test data ;
  *************************;

  **  Patient level dataset;
  data pat_data;
    format start end date11.;

    patid = 1; start = "01JAN2010"d; end = "31DEC2010"d; output;
    patid = 2; start = "01JAN2011"d; end = "31DEC2011"d; output;
    patid = 3; start = "01NOV2010"d; end = "31OCT2011"d; output;  **  Index pd misses 1 event for pat in test_data;
    patid = 4; start = "01JAN2010"d; end = "31DEC2010"d; output;  **  Patient has no records in test data but is thought at risk;
  
  run;

  **  Event level dataset;
  data test_data;
    retain patid .;
    format eventdate date11.;
    length grp $15;

    patid = 1; ** Pat with record in each of the 3 groups;
    eventdate = "01JAN2010"d; grp = 'Cough';  output;
    eventdate = "02JAN2010"d; grp = 'Cough';  output;
    eventdate = "02NOV2010"d; grp = 'Wheeze';  output;
    eventdate = "02DEC2010"d; grp = 'Poorly Knees';  output;
    eventdate = "12DEC2010"d; grp = 'Poorly Knees';  output;
    

    patid = 2; ** Pat with record in 2 groups.  Has 2 same grp records on same day - SHOULD BE COUNTED ONCE!;
    eventdate = "01JAN2011"d; grp = 'Cough';  output;
    eventdate = "01JAN2011"d; grp = 'Cough';  output;
    eventdate = "02NOV2011"d; grp = 'Wheeze';  output;

    patid = 3; ** Pat with record in 2 groups.  1 record is outside of index pd and should not be counted;
    eventdate = "01JAN2011"d; grp = 'Cough';  output;
    eventdate = "03MAR2011"d; grp = 'Cough';  output;
    eventdate = "22SEP2011"d; grp = 'Poorly Knees';  output;
    eventdate = "13OCT2011"d; grp = 'Poorly Knees';  output;
    eventdate = "02NOV2011"d; grp = 'Poorly Knees';  output;  ** This record should not be counted;

  proc sort;
    by patid eventdate;
  run;

  **------------------------------------------------;
  **  SUMMARY - This is what we expect in the output;
  **  Cough:        3 patients - 5 events;
  **  Poorly Knees: 2 patients - 4 events;
  **  Wheeze:       2 patients - 2 events;
  **------------------------------------------------;

  *******************************;
  **  From here is the algorithm ;
  *******************************;

  **  Merge the patient and test data, only keeping events falling within the analysis period;
  data perc1_applic_events;
    merge test_data(in = a) pat_data(in = b); 
    by patid;

    if a and b then do;
      if start <= eventdate <= end then output;
    end;
  run;

  **  Count the number of events each patient had for each grp;
  **  NOTE: The NODUPKEY in the PROC SORT remove duplicate records on the same day (within PAT & GRP);
  **  NOTE: The use of CLASSDATA and COMPLETETYPES ensures zero counts for all patients and grps;
  proc sort in = perc1_applic_events out = perc2_summ_grp_pat nodupkey;
    by grp patid eventdate;
  proc summary data = perc2_summ_grp_pat nway missing classdata = pat_data completetypes;
    by grp;
    class patid;
    output out = perc2_summ_grp_pat(rename=(_freq_ = num_events) drop=_type_);
  run;

  **  Add a denominator variable - value '1' for each row.;
  **  Ensure when num_events = 0 the value is set to missing;  
  **  Create a flag variable - set to 1 - if a patient has a record (no matter how many);  
  data perc2_summ_grp_pat;
    set perc2_summ_grp_pat;
    denom = 1;
    if num_events = 0 then num_events = .;
    flg_scripts = ifn(num_events, 1, .);
  run;

  proc tabulate data = perc2_summ_grp_pat format=comma8.;
    title1 bold "Table 1: N, % and basic statistics of events within non-mutually exclusive groups";
    title2 "Units: Patients - within each group level";
    title3 "The statistics summarises the number of events (not whether a patient had at least 1 event)";
    title4 "This means, for the statistics, only patients with 1+ record are included in the denominator";

    class grp;
    var denom flg_scripts num_events;
    table grp='', flg_scripts=''*(nmiss='Pats with 0 records' n='Pats with 1+ record' pctsum<denom>='% with record') 
                  num_events=''*(sum='Num Events' mean='Mean events per pat'*f=8.1 stddev='Std Dev'*f=8.2 p50='Median');
  run; title; footnote;

Create a free my code stock.com account now.

my code stok.com is a free service, which allows you to save and manage code snippes of any kind and programming language. We provide many advantages for your daily work with code-snippets, also for your teamwork. Give it a try!

Find out more and register now

You can customize the height of iFrame-Codes as needed! You can find more infos in our API Reference for iframe Embeds.