BookmarkSubscribeRSS Feed
orchid_sugar
Fluorite | Level 6

I did my analysis using proc genmod with repeated subject by the organization ID (hierarchical regression). I am trying to create a odds ratio figure like below image where each variable's category is showing:

 

orchid_sugar_1-1699662259570.png

1) Does below code still work for hierarchical regression?

proc logistic data=test plots(only)=oddsratio(logbase=10);
   class orgID / param=glm;
   model event(event="1") = homeless pay_cat pls_abbr race_grp HPI_pt_cat HPI_hpl_cat /link=logit clodds=wald;
run;

2) How can I make the figure like above? proc logistic doesn't seem to be working

orchid_sugar_2-1699662538217.png

 

 

 

5 REPLIES 5
sbxkoenk
SAS Super FREQ

Hello,

 

It's not because you make some Visuals on top of Analytics that it becomes "Visual Analytics".

Yes, I know, actually it does make it (static) Visual Analytics 🙂 ... but Visual Analytics (VA) happens to be the name of another product from SAS (to create dashboards with dynamic visuals) that you haven't used at all. Hence I moved your post to the "Statistical Procedures"-board where it belongs.

 

BR, Koen

sbxkoenk
SAS Super FREQ

Hello,

 

Why did you switch from PROC GENMOD to PROC LOGISTIC?
There's no REPEATED statement in PROC LOGISTIC.

You can do Hierarchical Logistic Regression Modeling with PROC GLIMMIX though!

No multilevel analysis in PROC LOGISTIC!

 

Here are some blog entries about forest plots (the plot-type you are working with):

BR, Koen

StatDave
SAS Super FREQ

You cannot obtain odds ratios for all levels of a categorical (CLASS) variable. An odds ratio compares the event odds of two levels of a categorical variable. So, for a categorical with two levels, there can only be one odds ratio. The plot you show (which is of hazard ratios, not odds ratios) apparently compares levels of some other binary variable (with placebo and MTX levels) within each gender rather than comparing the response hazards of the two genders. That is how there can be hazard ratios for both genders.

 

You can use the ESTIMATE statement to estimate odds ratios and then plot them using PROC SGPLOT. PROC GEE is a newer procedure specifically for fitting the GEE model and is the recommended procedure when fitting that model. Use the EXP and CL options in the ESTIMATE to obtain the odds ratio estimates and confidence limits. Using the wheezing data in the Getting Started section of the GENMOD documentation, the following fits the GEE model, estimates and saves the odds ratios, and plots them. The coefficients for CITY compare the odds of its two levels and exponentiate that difference. For a continuous variable, the 1 coefficient selects its single parameter that is exponentiated to obtain the odds ratio for the difference of one unit.

proc gee data=six;
   class case City;
   model wheeze(event='1') = City Age Smoke / dist=bin link=logit;
   repeated subject=case / type=exch;
   estimate 
     'city' city 1 -1,
     'age' age 1,
     'smoke' smoke 1 / exp cl;
   ods output estimates=or;
   run;
proc sgplot noautolegend;
   highlow high=upperexp low=lowerexp y=label / highcap=serif lowcap=serif;
   scatter y=label x=expestimate;
   refline 0 / axis=x;
   yaxis label=' ';
   xaxis label='Odds Ratio';
   run;

Ksharp
Super User

You could try STRATA statement of PROC LOGISTIC .

But the better code is using PROC GENMOD or PROC GLIMMIX as showed by @StatDave .

 

data Data1;
do ID=1 to 63;
do Outcome = 1 to 0 by -1;
input Gall Hyper @@;
output;
end;
end;
datalines;
0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 0 1
0 1 0 0 1 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 1 1 0 0 1 1 0 1 0 1 0 0 1
0 1 0 0 0 0 1 1 0 0 1 1 0 0 0 1 0 1 0 0
0 0 1 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 0 0 1 0 0 0 1 1 0 0 0 0 1 0 0
0 1 0 0 0 1 0 0 0 1 0 0 0 0 0 0 1 1 1 1
0 0 0 1 0 1 0 0 0 1 0 1 0 1 0 1 0 1 0 0
0 0 0 0 0 1 1 0 0 0 0 1 0 0 0 0 1 0 0 0
0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 0 1 0 1
0 0 0 0 0 1 0 1 0 1 0 0 0 1 0 0 1 0 0 0
0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 1 0 0
1 0 1 0 0 1 0 0 1 0 0 0
;

proc logistic data=Data1;
strata ID;
model outcome(event='1')=Gall/ clodds=wald;
run;
Ksharp
Super User

After you got these ODDS Ratio 95%CI , you could plot the forest graph by the following code.

 

data forest_subgroup;
infile cards truncover;
  label Subgroup='子组' Count='人数' Percent='mRS=0-1 n(%)' 
  Count_test='人数' Percent_test='mRS=0-1 n(%)' ci='Odds Ratio(95%CI)' pvalue='P-value';;
  input Id Subgroup : $40. Count Percent : $40.  Count_test Percent_test  : $40.   Mean  Low  High   ci : $40. pvalue;
  format pvalue pvalue6.3;
  indentWt=1;
  ObsId=_n_; 
  total_n=Count+Count_test ;
  datalines4;
1 全部                       662  443(66.9%)   667   414(62.1%)   0.885	0.763  1.026  0.885(0.763;1.026)  0.899
1 有无桥接治疗               .     .    .     . .       .       .   .   
2 有桥接治疗                 21  10(47.6%)     23  7(30.4%)      0.685  0.310  1.511  0.685(0.310;1.511)   0.0004
2 无桥接治疗                 583  392(67.2%)    583  371(63.6%)     0.913 0.778  1.072 0.913(0.778;1.072)
1 年龄分组                   .     .  .     .  .       .       .      .
2 ≥18岁且<60岁              588   404(68.7%)  606  385(63.5%)     0.887  0.758  1.038  0.887(0.758;1.038)   0.8765
2 ≥60岁且<80岁                      71    37(52.1%)   56   25(44.6%)   0.676   0.395   1.155  0.676(0.395;1.155)
1 基线NIHSS分组              .     .  .     .  .       .       .      .
2 ≤7分                      383   309(80.7%)   370  281(75.9%)   0.861   0.690   1.075  0.861(0.690;1.075)   0.0054
2 ≥8分且≤14分                       276   124(44.9%)  291  130(44.7%)    0.979   0.778   1.233  0.979(0.778;1.233)
1 接受溶栓治疗时间窗分组     .     .  .     .  .       .       .      .
2 <3h                        330   218(66.1%)   340  217(63.8%)    0.945  0.759   1.175  0.945(0.759;1.175)   0.3241
2 ≥3h且<4h                  330   222(67.3%)   326 194(59.5%)    0.82   0.658   1.023  0.820(0.658;1.023)
;;;;
run;

/*It is for the symbol size of 95%CI*/
proc rank data=forest_subgroup out=forest_subgroup groups=5 ties=dense;
var total_n;
ranks total_n_rank;
run;

data forest_subgroup;
 set forest_subgroup;
  indentWt=1;
  ObsId=_n_; 
run;
data forest_subgroup_2;
  set forest_subgroup nobs=n end=last;
  length text $20;
  val=mod(_N_-1, 6);
/*  if val eq 1 or val eq 2 or val eq 3 then ref=obsid;*/
 if obsid in (2:4 8:10 ) then ref=obsid;
  /*--Separate Subgroup headers and obs into separate columns--*/
  indentwt=2;
  if id=1 then indentWt=0;

  output;
  if last then do;
    call missing (subgroup, count, percent, Count_test ,Percent_test,   mean, low, high,  ci,
                   indentwt, val, ref ,pvalue,total_n);
        obsid=n+1; 
    xl=0.5; yl=n+1; text='P'; output;;
        xl=2; yl=n+1; text='T'; output;
  end;
  run;


/*It is for the symbol size of 95%CI*/
data forest_subgroup_2;
 set forest_subgroup_2;
if total_n_rank=0 then mean0=mean;
if total_n_rank=1 then mean1=mean;
if total_n_rank=2 then mean2=mean;
if total_n_rank=3 then mean3=mean;
if total_n_rank=4 then mean4=mean;
run;

/*--Define Format with Unicode for the left and right arrows--*/
proc format;;
  value $txt
  "T" = "试验组更好 (*ESC*){Unicode '2192'x}"
  "P" = "(*ESC*){Unicode '2190'x} 对照组更好";
run;

/*--Attribute maps for Subgroup Test attributes--*/
data attrmap;
  length textweight $10;
  id='text'; value='1'; textcolor='Black'; textsize=15; textweight='bold'; output;
  id='text'; value='2'; textcolor='Black'; textsize=10; textweight='normal'; output;
run;
/*--Forest Plot--*/
options missing=' ' orientation=landscape ;
title j=l h=1.2  "                                                    试验组                       对照组";
/*ods rtf file='c:\temp\temp.rtf' style=htmlblue;*/
ods graphics / reset width=9.6in height=4.5in   noborder noscale outputfmt=png;
proc sgplot data=forest_subgroup_2 nowall noborder nocycleattrs dattrmap=attrmap noautolegend;
  format text $txt.;
  styleattrs axisextent=data;
  refline ref / lineattrs=(thickness=22 color=grayee);  /*<-- discrete thickness*/
  highlow y=obsid low=low high=high /lowcap=serif highcap=serif lineattrs=graphdata2;   /*clipcap CLIPCAPSHAPE=CLOSEDARROW */

  /*It is for the symbol size of 95%CI*/
  scatter y=obsid x=mean0 / markerattrs=graphdata1(symbol=squarefilled size=4 );
  scatter y=obsid x=mean1 / markerattrs=graphdata1(symbol=squarefilled size=6 );
  scatter y=obsid x=mean2 / markerattrs=graphdata1(symbol=squarefilled size=8 );
  scatter y=obsid x=mean3 / markerattrs=graphdata1(symbol=squarefilled size=10 );
  scatter y=obsid x=mean4 / markerattrs=graphdata1(symbol=squarefilled size=12 );

  scatter y=obsid x=mean / markerattrs=(size=0) x2axis;
  refline 1 / axis=x;

  text x=xl y=obsid text=text / position=bottom contributeoffsets=none strip  textattrs=(size=10);
  yaxistable subgroup  / location=inside position=left textgroup=id labelattrs=(size=10  weight=bold)  
            LABELJUSTIFY=left  valueattrs=(size=10 ) 
             textgroupid=text indentweight=indentWt;
  yaxistable  Count Percent  Count_test Percent_test/ VALUEJUSTIFY=right  
                      location=inside position=left labelattrs=(size=10 weight=bold) valueattrs=(size=10) pad=(right=15px) ;
  yaxistable ci pvalue/ VALUEJUSTIFY=right 
                     location=inside position=right labelattrs=(size=10 weight=bold) valueattrs=(size=10) pad=(right=15px) ;
 
  yaxis reverse display=none colorbands=odd colorbandsattrs=(transparency=1)  ;
  xaxis display=(nolabel)  type=log ;
  x2axis label=' ' display=(noline noticks novalues) labelattrs=(size=10)  ;
run;
/*ods rtf close;*/

Ksharp_0-1699845562212.png

 

sas-innovate-wordmark-2025-midnight.png

Register Today!

Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.


Register now!

What is ANOVA?

ANOVA, or Analysis Of Variance, is used to compare the averages or means of two or more populations to better understand how they differ. Watch this tutorial for more.

Find more tutorials on the SAS Users YouTube channel.

Discussion stats
  • 5 replies
  • 1692 views
  • 0 likes
  • 4 in conversation