BookmarkSubscribeRSS Feed
tofov2
Calcite | Level 5

Hey everyone,

 

I want to create a table with different counts and then frequencies across  groups, followed by unadjusted odds ratios and then P-value for Chi squared. Table should be similar to that seen as table 1 or 2 in most medical manuscripts. Any thoughts on how to do this? The attached image shows an example. I can add in titles and other formating, but I have having trouble showing the unadjusted odds ratios in a list format.

 

Picture1.png

1 REPLY 1
FreelanceReinh
Jade | Level 19

Hello @tofov2,

 

Sorry to see that you haven't got any replies yet. I think the LOGISTIC procedure could be useful for obtaining the odds ratios and their confidence intervals -- rather than the FREQ procedure, which computes odds ratios only for (sets of) 2 x 2 tables. Your example output suggests that there even the chi-square p-values were calculated using (the methods of) PROC LOGISTIC because with PROC FREQ I got 0.005 (not 0.006) as the rounded p-value for ancestry category "African American" (restricting the table to 2 x 2 by means of a WHERE condition). Using PROC LOGISTIC, however, I could reproduce all odds ratio and chi-square statistics of your table. (But, obviously, you must know exactly what statistics are required for your output.) Combining these results with frequencies and percentages from PROC FREQ, the REPORT procedure could be used to create the desired summary table.

 

Here's the raw code I used to reproduce your example table in listing output. I hope you can adapt it to your real data. Note that you won't need the weight n and freq n statements if your real dataset is not aggregated like my sample dataset HAVE.

/* Create sample data for demonstration */

data have;
call streaminit(27182818);
array m[0:1,-1:2] _temporary_ (164 110 48 88, 363 250 144 146);
array k[3] _temporary_;
do resp=0 to 1;
  do sex=1 to 2;
    if sex=1 then do anc=1 to 3;
      if anc<3 then do;
        k[anc]=rand('hyper',m[resp,-1],m[resp,0],m[resp,anc]);
        n=k[anc];
        output;
      end;
      else do;
        k[anc]=m[resp,0]-k[1]-k[2];
        n=k[anc];
        output;
      end;
    end;
    else do anc=1 to 3;
      if anc<3 then do;
        n=m[resp,anc]-k[anc];
        output;
      end;
      else do;
        n=m[resp,-1]-m[resp,1]-m[resp,2]-k[anc];
        output;
      end;
    end;
  end;
end;
run;

/* Obtain frequencies and percentages */

ods output CrossTabFreqs=ctf;
proc freq data=have;
tables resp*(sex anc);
weight n;
run;

/* Compute statistics */

ods output GlobalTests(persist=proc)=glt(where=(test=:'L'))
           ParameterEstimates(persist=proc)=est
           OddsRatios(persist=proc)=odr;

proc logistic data=have desc;
class sex(ref='1') / param=ref;
model resp=sex;
freq n;
run;

proc logistic data=have desc;
class anc(ref='1') / param=ref;
model resp=anc;
freq n;
run;

ods output close;

/* Prepare frequencies and percentages for output */

proc sql;
create table ctfs as
select scan(table,-1,'* ') as var, whichc(calculated var,'sex','anc') as varnum, * from ctf
order by varnum, sex, anc, resp>., resp desc;
quit;

data freqtab;
set ctfs(rename=(frequency=n));
val=input(vvaluex(scan(table,-1,'* ')),32.);
select(resp);
  when(.) if char(_type_,2)='0' then call symputx('n_coho',n);
          else do; n_c=n; p_c=percent; end;
  when(1) if char(_type_,2)='0' then call symputx('n_resp',n);
          else do; n_r=n; p_r=rowpercent; end;
  when(0) if char(_type_,2)='0' then call symputx('n_nonr',n);
          else do; n_n=n; p_n=rowpercent; end;
end;
if resp=0 & _type_='11';
retain n_: p_:;
keep var varnum val n_: p_:;
run;

/* Prepare statistics for output */

data odr2;
set odr;
var=scan(effect,1,' ');
varnum=whichc(var,'sex','anc');
val=input(scan(effect,2,' '),32.);
drop _: effect;
run;

data odr3;
set odr2;
by varnum;
output;
if last.varnum then do;
  val=1;
  oddsratioest=.r;
  lowerCL=.;
  upperCL=.;
  output;
end;
run;

proc sort data=odr3;
by varnum val;
run;

data est2;
set est(rename=(variable=var));
varnum=whichc(var,'sex','anc');
val=input(classval0,32.);
if val>.;
keep var varnum val probchisq;
run;

data glt2;
set glt;
if df=1 then probchisq=.;
varnum=_n_;
val=.;
keep varnum val probchisq;
run;

data odrest;
merge odr3 est2(drop=var);
by varnum val;
run;

data stats;
set glt2 odrest;
by varnum val;
run;

/* Prepare output */

proc format;
value varnum
1='Sex'
2='Ancestry'
;
value sex (default=18)
1='Male'
2='Female'
;
value anc (default=18)
1='European American'
2='African American'
3='Hispanic/Latino'
;
value orf (default=9)
.r='Reference'
low-high=[8.2]
;
value orclf (default=6)
.=' '
low-high=[oddsr6.2]
;
picture pval (default=6 round)
0-<0.001   = '<0.001' (noedit)
0.001-<0.1 = '9.999'
0.1-high   = '9.99'
;
run;

options missing=' ';

data want;
merge freqtab stats(drop=var);
by varnum val;
length valc $20;
valc=putn(val,cats(var,'-r'));
run;

/* Create listing output table */

proc report data=want;
column varnum valc ("_Cohort (n=&n_coho)_" n_c p_c) ("_Responders (n=&n_resp)_" n_r p_r) ("_Nonresponders (n=&n_nonr)_" n_n p_n)
       OddsRatioEst LowerCL UpperCL ProbChiSq;
define varnum / order order=internal format=varnum. ' ';
define valc / ' ';
define n_: / width=10 'N';
define p_: / format=3. width=11 '%';
define OddsRatioEst / display width=10 format=orf. 'Odds Ratio'; 
define LowerCL / format=orclf. ' ';
define UpperCL / format=orclf. ' ' spacing=1;
define ProbChiSq / format=pval. width=7 'P-Value';
run;

SAS Innovate 2025: Call for Content

Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!

Submit your idea!

What is Bayesian Analysis?

Learn the difference between classical and Bayesian statistical approaches and see a few PROC examples to perform Bayesian analysis in this video.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 1 reply
  • 749 views
  • 0 likes
  • 2 in conversation