BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
CathyVI
Pyrite | Level 9

Hello, 

Please can anyone help with correctly using the code for empirical (observed) logits for ordinal response data. SAS provided this code in this paper: 37944 - Plotting empirical (observed) logits for binary and ordinal response data (sas.com)

I carefully copied the code into SAS on demand and only changed the data=?, y=? & x=?

data=    name of the input data set. Required.
  y=       name of the response variable. Required.
  x=       space-separated list of predictor variables. Required.

 but my code is not working. Please I would really appreciate any help. I wanted to use the code for my publication report.  

The empirical is a long code so I will not copy it here but here is my log when i run it.

 
 1          OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
 NOTE: ODS statements in the SAS Studio environment may disable some output features.
 69         
 70         /*                          INSTRUCTIONS FOR USE
 71         
 72            Version 1.1 or higher of the CtoN macro is required by the EmpiricalLogitPlot
 73            macro and must be defined before using the EmpiricalLogitPlot macro. Download
 74            it from this location: http://support.sas.com/kb/60678 and see the Downloads
 75            tab at that link. The code defining the CtoN macro and the code defining the
 76            macros below must all be submitted in your SAS session to make the macros
 77            available for use in that SAS Session. Do not alter any of the macro code
 78            to ensure successful macro execution. After running the macro code, check
 79            your SAS log to verify that no errors were generated.
 80         *******************************************************************************/
 81         
 82         %macro EmpiricalLogitPlot(version, data=stcp.cleanedpracticum2, y=issgrp, x=functional person_type gender dayofweek
 82       ! drug_bac lnage, const=0.5, neighbors=50,
 83                smooth=.3, contcutoff=20, options=DESCENDING PANEL) / minoperator;
 84         /*--------------------------------------------------------------------------
 85           A macro extension of SAS Usage Note 37944 for both class and continuous
 86           covariates. Calls the OneContPlot macro to plot the empirical logits defined
 87           using the NEIGHBORS/2 observed covariate values preceding and following each
 88           observation against the levels of a covariate with more than CONTCUTOFF
 89           levels. Calls the OneClassPlot macro to plot the empirical logits computed
 90           within each level of a covariate with fewer than CONTCUTOFF levels.
 91         
 92           version  Optional. Any text immediately following the open parenthesis and
 93                    followed by a comma will display the macro version.
 94           data=    name of the input data set. Required.
 95           y=       name of the response variable. Required.
 96           x=       space-separated list of predictor variables. Required.
 97           const=   small value between 0 and 1 to prevent zero counts. Default: 0.5.
 98           neighbors= number of neighbors around each observation used to compute
 99                    logits for continuous effects. Default: Average population size but
 100                   at least 1% of the sample size with a minimum of 2.
 101          smooth=  smoothing parameter used for loess curve fit to logits for
 102                   continuous effects. Default: 0.3.
 103          contcutoff= if an x= variable has more than the specified number of levels
 104                   then logits are computed within sets of neighboring observations;
 105                   otherwise computed within each level of the variable. Default: 20.
 106          options= DESCENDING (high response levels are of interest), ASCENDING (low
 107                   response levels are of interest), DATAORDER (use for character
 108                   response after sorting data so that first occurrence of each level
 109                   is in logically ascending or descending order as desired with the
 110                   first levels are of interest). Specify only one of DESCENDING,
 111                   ASCENDING, or DATAORDER. PANEL (single panel of all predictor
 112                   plots), NOPANEL (separate plot for each predictor). Default:
 113                   DESCENDING PANEL.
 114          --------------------------------------------------------------------------*/
 115        
 116        %macro existchk(data=, var=, dmsg=e, vmsg=e);
 117           %global status; %let status=ok;
 118           %if &dmsg=e %then %let dmsg=ERROR;
 119           %else %if &dmsg=w %then %let dmsg=WARNING;
 120           %else %let dmsg=NOTE;
 121           %if &vmsg=e %then %let vmsg=ERROR;
 122           %else %if &vmsg=w %then %let vmsg=WARNING;
 123           %else %let vmsg=NOTE;
 124           %if %quote(&data) ne %then %do;
 125             %if %sysfunc(exist(&data)) ne 1 %then %do;
 126               %put &dmsg: Data set %upcase(&data) not found.;
 127               %let status=nodata;
 128             %end;
 129             %else %if &var ne %then %do;
 130               %let dsid=%sysfunc(open(&data));
 131               %if &dsid %then %do;
 132                 %let i=1;
 133                 %do %while (%scan(&var,&i) ne %str() );
 134                    %let var&i=%scan(&var,&i);
 135                    %if %sysfunc(varnum(&dsid,&&var&i))=0 %then %do;
 136                      %put &vmsg: Variable %upcase(&&var&i) not found in data %upcase(&data).;
 137                      %let status=novar;
 138                    %end;
 139                    %let i=%eval(&i+1);
 140                 %end;
 141                 %let rc=%sysfunc(close(&dsid));
 142               %end;
 143               %else %put ERROR: Could not open data set &data.;
 144             %end;
 145           %end;
 146           %else %do;
 147             %put &dmsg: Data set not specified.;
 148             %let status=nodata;
 149           %end;
 150        %mend;
 151        
 152        %let elptime = %sysfunc(datetime());
 153        %let _version=1.2;
 154        %if &version ne %then %put NOTE: &sysmacroname macro Version &_version;
 155        %let _elpopts = %sysfunc(getoption(notes));
 156        %let version=%upcase(&version);
 157        %if %index(&version,DEBUG) %then %do;
 158          options notes mprint
 159            %if %index(&version,DEBUG2) %then mlogic symbolgen;
 160          ;
 161          ods select all;
 162          %put _user_;
 163        %end;
 164        %else %do;
 165          options nonotes nomprint nomlogic nosymbolgen;
 166          ods exclude all;
 167        %end;
 168        
 169        /* Check for newer version */
 170        %if %index(&version,NOCHECK)=0 %then %do;
 171           %let _notfound=0; %let _newver=0;
 172           filename _ver url 'http://ftp.sas.com/techsup/download/stat/versions.dat'
 173                    termstr=crlf;
 174           data _null_;
 175             infile _ver end=_eof;
 176             input name:$18. ver;
 177             if upcase(name)="&sysmacroname" then do;
 178               call symput("_newver",ver); stop;
 179             end;
 180             if _eof then call symput("_notfound",1);
 181             run;
 182           options notes;
 183           %if &syserr ne 0 or &_notfound=1 or &_newver=0 %then
 184             %put NOTE: Unable to check for newer version of &sysmacroname macro.;
 185           %else %if %sysevalf(&_newver > &_version) %then %do;
 186             %put NOTE: A newer version of the &sysmacroname macro is available at;
 187             %put NOTE- this location: http://support.sas.com/ ;
 188           %end;
 189           %if %index(%upcase(&version),DEBUG)=0 %then options nonotes;;
 190        %end;
 191        
 192        /* Input checks and process options */
 193        %if %index(&y,/) %then %do;
 194          %put ERROR: Events/Trials syntax is not supported in Y=.;
 195          %goto exit;
 196        %end;
 197        
 198        %existchk(data=&data, var=&y &x);
 199        %if &status=nodata or &status=novar %then %goto exit;
 200        
 201        %if %quote(&y)= %then %do;
 202          %put ERROR: Y= is required.;
 203          %goto exit;
 204        %end;
 205        
 206        %if &x= %then %do;
 207          %put ERROR: One or more variables must be specified in X=.;
 208          %goto exit;
 209        %end;
 210        
 211        %if %sysevalf(&neighbors ne) %then %do;
 212          %if %sysevalf(%sysfunc(mod(&neighbors,1)) ne 0 or &neighbors<=0) %then %do;
 213            %put ERROR: NEIGHBORS= must be an integer value greater than zero.;
 214            %goto exit;
 215          %end;
 216        %end;
 217        %else %let neighbors=50;
 218        %let nbhd=&neighbors;
 219        
 220        %if %sysevalf(&contcutoff ne) %then %do;
 221          %if %sysevalf(%sysfunc(mod(&contcutoff,1)) ne 0 or &contcutoff<=0) %then %do;
 222            %let contcutoff=%sysfunc(ceil(%sysfunc(abs(&contcutoff))));
 223            %if %index(&version,DEBUG)=0 %then options notes;;
 224            %put NOTE: CONTCUTOFF= value must be a positive integer.;
 225            %put NOTE- CONTCUTOFF= set to &contcutoff;
 226            %if %index(&version,DEBUG)=0 %then options nonotes;;
 227          %end;
 228        %end;
 229        %else %let contcutoff=20;
 230        
 231        %if %quote(&const) ne %then %do;
 232          %if (%sysfunc(verify(%sysfunc(catx( ,&const)),'0123456789.'))>0) +
 233              (%sysfunc(count(&const,.))>1) %then %do;
 234            %put ERROR: The CONST= value must be a positive value less than 1.;
 235            %goto exit;
 236          %end;
 237          %else %if &const<0 or &const>=1 %then %do;
 238            %put ERROR: The CONST= value must be a positive value less than 1.;
 239            %goto exit;
 240          %end;
 241        %end;
 242        %else %do;
 243          %put ERROR: CONST= is required and must be a positive value less than 1.;
 244          %goto exit;
 245        %end;
 246        
 247        %if %quote(&smooth) ne %then %do;
 248          %if (%sysfunc(verify(%sysfunc(catx( ,&smooth)),'0123456789.'))>0) +
 249              (%sysfunc(count(&smooth,.))>1) %then %do;
 250            %put ERROR: The SMOOTH= value must be a positive value.;
 251            %goto exit;
 252          %end;
 253          %else %if %sysevalf(&smooth<=0) %then %do;
 254            %put ERROR: The SMOOTH= value must be greater than zero.;
 255            %goto exit;
 256          %end;
 257        %end;
 258        %else %do;
 259          %put ERROR: SMOOTH= is required and must be positive value.;
 260          %goto exit;
 261        %end;
 262        
 263        %let validopts=ASCENDING DESCENDING DATAORDER PANEL NOPANEL;
 264        %let panel=1; %let plot=0; %let hievent=1; %let dataorder=0;
 265        %let i=1;
 266        %do %while (%scan(&options,&i) ne %str() );
 267           %let option&i=%upcase(%scan(&options,&i));
 268           %if &&option&i=DATAORDER %then %do;
 269              %let dataorder=1; %let hievent=0;
 270           %end;
 271           %else %if &&option&i=ASCENDING %then %let hievent=0;
 272           %else %if &&option&i=NOPANEL %then %do; %let panel=0; %let plot=1; %end;
 273           %else %do;
 274            %let chk=%eval(&&option&i in &validopts);
 275            %if not &chk %then %do;
 276              %put ERROR: Valid values of OPTIONS= are &validopts..;
 277              %goto exit;
 278            %end;
 279           %end;
 280           %let i=%eval(&i+1);
 281        %end;
 282        
 283        %if %index(&version,DEBUG)=0 %then options notes;;
 284        %put NOTE: Logits are computed over lower Ordered Values of &y..;
 285        %if %index(&version,DEBUG)=0 %then options nonotes;;
 286        
 287        proc sql;
 288          select count(*) into :n from &data where &y is not missing;
 289          quit;
 290        ods graphics / loessmaxobs=%sysfunc(max(5000,%eval(&n+1000)));
 291        data _tempdata;
 292           set &data;
 293           run;
 294        
 295        /* Order y= variable as requested */
 296        %if &dataorder=0 %then %do;
 297           proc sort data=_tempdata;
 298             by %if &hievent %then descending; &y;
 299             run;
 300        %end;
 301        %let chary=0; %let yname=&y;
 302        %let dsid=%sysfunc(open(_tempdata));
 303        %if &dsid %then %do;
 304          %let varnum=%sysfunc(varnum(&dsid,&y));
 305          %if %sysfunc(vartype(&dsid,&varnum))=C %then %do;
 306            %let rc=%sysfunc(close(&dsid));
 307            %CtoN(&version,data=_tempdata,var=&y,out=_tempdata,order=data,
 308                  options=noreplace noformat nodatanote nonewcheck)
 309            data _tempdata; set _tempdata(rename=(&y=_chary));
 310              label _chary='00'x;
 311              run;
 312            %let y=&y._N; %let chary=1;
 313          %end;
 314        %let rc=%sysfunc(close(&dsid));
 315        %end;
 316        proc freq nlevels data=_tempdata
 317          %if &hievent or &dataorder %then order=data;
 318        ;
 319           where not missing(&y);
 320           table &y %if &chary %then * _chary; / out=_ylevs noprint;
 321           ods exclude nlevels;
 322           ods output nlevels=_numy;
 323           run;
 324        data _null_;
 325           set _numy;
 326           call symputx('numy',nlevels);
 327           run;
 328        %if &chary=0 %then %do;
 329         data _null_;
 330           set _ylevs nobs=nlev;
 331           call symputx(cats('l',_n_),&y);
 332           run;
 333         data _tempdata;
 334           set _tempdata;
 335           select (&y);
 336             %do i=1 %to &numy;
 337               when (&&l&i) &y = &i;
 338             %end;
 339             otherwise &y = .;
 340           end;
 341           run;
 342        %end;
 343        %if &numy=2 %then %let lgtlabl=Logit;
 344        %else %let lgtlabl=CLogit;
 345        
 346        /* Variables with > 50 levels will use neighborhood method to compute logits.
 347           Variables with <=50 levels will have logits computed within each level.
 348        */
 349        %let cont=; %let class=;
 350        proc freq data=_tempdata nlevels;
 351          table &x / noprint;
 352          ods exclude nlevels;
 353          ods output nlevels=_nx;
 354          run;
 355        data _null_;
 356          set _nx;
 357          call symputx(cats('nlev',_n_),nnonmisslevels);
 358          run;
 359        %let i=1;
 360        %let dsid=%sysfunc(open(_tempdata));
 361        %if &dsid %then %do %while (%scan(&x,&i) ne %str() );
 362          %let varnum=%sysfunc(varnum(&dsid,%scan(%upcase(&x),&i)));
 363          %if %sysfunc(vartype(&dsid,&varnum))=N and &&nlev&i>20 %then
 364            %let cont=&cont %scan(&x,&i);
 365            %else %let class=&class %scan(&x,&i);
 366          %let i=%eval(&i+1);
 367        %end;
 368        %let rc=%sysfunc(close(&dsid));
 369        
 370        ods select all;
 371        %let num=1;
 372        %let numc=0;
 373        %let numd=0;
 374        %let totnum=1;
 375        %let doClass=1;
 376        %let numym1=%eval(&numy-1);
 377        %let var=%scan(&class,&num);
 378        %if (&var=) %then %do;
 379           %let doClass=0;
 380           %let var=%scan(&cont,&num);
 381           %if (&var=) %then %goto stopit;
 382        %end;
 383        data _ylevs;
 384          set _ylevs;
 385          ov=_n_;
 386          run;
 387        proc print data=_ylevs label noobs split="/";
 388          %if &chary=0 %then %do;
 389            id ov; var &y; label ov="Ordered/Value/(O.V.)";
 390          %end;
 391          %else %do;
 392            id &y; var _chary; label &y="Ordered/Value/(O.V.)" _chary="&yname";
 393          %end;
 394          title "Response Profile";
 395          title2 "Logits are computed over the lower Ordered Values";
 396          run;
 397        title;
 398        %do %while(&var ne);
 399           data _tempa(keep=&y &var);
 400              set _tempdata;
 401              run;
 402           %if %eval(&doClass eq 1) %then %do;
 403              %OneClassPlot(data=_tempa,x=&var,y=&y,numy=&numy,const=&const,plot=&plot);
 404              %let numc= %eval(&numc+1);
 405              data _tempc;
 406                 set %if %eval(&numc ne 1) %then _tempc; _temp2;
 407                 run;
 408           %end;
 409           %else %do;
 410              %OneContPlot(data=_tempa,x=&var,y=&y,numy=&numy,const=&const,plot=&plot,
 411                           nbhd=&nbhd);
 412              %let numd= %eval(&numd+1);
 413              data _tempd;
 414                 set %if %eval(&numd ne 1) %then _tempd; _temp2;
 415                 run;
 416           %end;
 417           %let num=%eval(&num+1);
 418           %let totnum=%eval(&totnum+1);;
 419           %if %eval(&doClass eq 1) %then %do;
 420              %let var=%scan(&class,&num);
 421              %if (&var=) %then %do;
 422                  %let doClass=0;
 423                  %let num=1;
 424              %end;
 425           %end;
 426           %if %eval(&doClass eq 0) %then %do;
 427              %let var=%scan(&cont,&num);
 428              %if (&var=) %then %goto stopit;
 429           %end;
 430        %end;
 431        
 432        %stopit: ;
 433        %if &panel %then %do;
 434           %if %eval(&numc>0) %then %do;
 435              proc sort data=_tempc;
 436                 by _group _x;
 437                 run;
 438           %end;
 439           %if %eval(&numd>0) %then %do;
 440              proc sort data=_tempd;
 441                 by _group _x;
 442                 run;
 443           %end;
 444           %if %eval(&numc>0 and &numd>0) %then %do;
 445              data _tempall;
 446                 merge _tempd _tempc;
 447                 by _group _x;
 448                 run;
 449           %end;
 450           %else %if %eval(&numc>0) %then %do;
 451              data _tempall;
 452                 set _tempc;
 453                 run;
 454           %end;
 455           %else %do;
 456              data _tempall;
 457                 set _tempd;
 458                 run;
 459           %end;
 460           proc sort data=_tempall;
 461              by _group;
 462              run;
 463           data _tempa(keep=_group _minx _maxx);
 464              set _tempall;
 465              by _group;
 466              retain _minx 1e100 _maxx -1e100;
 467              if first._group then do;
 468                 _minx=_x;
 469                 _maxx=_x;
 470              end;
 471              _minx=min(_minx,_x);
 472              _maxx=max(_maxx,_x);
 473              if last._group then output;
 474              run;
 475           data _tempall;
 476              merge _tempall _tempa;
 477              by _group;
 478              _x=(_x-_minx)/(_maxx-_minx);
 479              run;
 480           %if       ((&totnum-1)=1)   %then %do; %let rows=1; %let cols=1; %end;
 481           %else %if ((&totnum-1)=2)   %then %do; %let rows=1; %let cols=2; %end;
 482           %else %if ((&totnum-1)=3)   %then %do; %let rows=1; %let cols=3; %end;
 483           %else %if ((&totnum-1)=4)   %then %do; %let rows=2; %let cols=2; %end;
 484           %else %if ((&totnum-1)<=6)  %then %do; %let rows=2; %let cols=3; %end;
 485           %else %if ((&totnum-1)<=9)  %then %do; %let rows=3; %let cols=3; %end;
 486           %else %if ((&totnum-1)<=12) %then %do; %let rows=3; %let cols=4; %end;
 487           %else %do; %let cols=4; %let rows=4;  %end;
 488           proc sgpanel data=_tempall;
 489              panelby _group / novarname columns=&cols rows=&rows
 490                               uniscale=all skipemptycells;
 491              rowaxis label=
 492                 %if &numy>2 %then "Empirical Cumulative Logits";
 493                 %else "Empirical Logit";
 494              ;
 495              colaxis display=(nolabel noticks novalues);
 496              %if (&numd>0) %then %do i=1 %to &numym1;
 497              loess y=d&i x=_x / smooth=&smooth legendlabel="&lgtlabl(O.V.<=&i)"
 498                    name="series&i" lineattrs=GraphData&i(thickness=3px)
 499                    markerattrs=GraphDataDefault(color=gray) nomarkers
 500              ;
 501              %end;
 502              %if (&numc>0) %then %do i=1 %to &numym1;
 503              series y=c&i x=_x / legendlabel="&lgtlabl(O.V.<=&i)" name="series&i"
 504                     lineattrs=GraphData&i(thickness=3px);
 505              %end;
 506              %if &numd %then inset neighbors / position=bottom;;
 507              keylegend %do i=1 %to &numym1; "series&i" %end;;
 508              %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
 509              %else %str(title "Empirical Logit";);
 510              %if &numd %then
 511              title2 "Smoothing parameter = &smooth for continuous predictors";;
 512              run;
 513        %end;
 514        
 515        %exit:
 516        %if %index(&version,DEBUG)=0 %then %do;
 517           proc datasets nolist;
 518              delete _: ;
 519              run; quit;
 520        %end;
 521        %if %index(&version,DEBUG) %then %do;
 522          options nomprint nomlogic nosymbolgen;
 523          %put _user_;
 524        %end;
 525        options &_elpopts;
 526        title;
 527        %let elptime=%sysfunc(round(%sysevalf(%sysfunc(datetime()) - &elptime), 0.01));
 528        %put NOTE: The &sysmacroname macro used &elptime seconds.;
 529        %mend;
 530        
 531        %macro OneClassPlot(data=,x=,y=,numy=,const=0.5,plot=1);
 532        /*--------------------------------------------------------------------------
 533          A macro version of SAS Usage Note 37944 for covariates with fewer than
 534          CONTCUTOFF levels. Computes and/or plots the empirical logits of Y against
 535          the levels of one X variable.  Called by the EmpiricalLogitPlot macro.
 536        
 537          data=    name of the input data set.
 538          x=       name of the single CLASS covariate.
 539          y=       name of the response variable.
 540          numy=    number of levels of the response.
 541          const=   small value in case of zero cells.
 542          plot=    1=create the plot, 0=create data set only
 543          --------------------------------------------------------------------------*/
 544        %let numym1=%eval(&numy-1);
 545        %let zerosum=0;
 546        proc freq data=&data noprint;
 547           table &x*&y / sparse out=_temp2;
 548        run;
 549        proc sort data=_temp2;
 550           by &x;
 551        run;
 552        %let dsid=%sysfunc(open(_temp2));
 553        %if &dsid %then %do;
 554          %let varnum=%sysfunc(varnum(&dsid,&x));
 555          %if %sysfunc(vartype(&dsid,&varnum))=C %then %do;
 556            %let rc=%sysfunc(close(&dsid));
 557            %CtoN(&version,data=_temp2,var=&x,out=_temp2,options=format nodatanote nonewcheck)
 558          %end;
 559          %let rc=%sysfunc(close(&dsid));
 560        %end;
 561        proc transpose data=_temp2 out=_temp;
 562           by &x;
 563           var count;
 564           run;
 565        data _temp2 ;
 566           set _temp;
 567           length _group $ 32;
 568           if (_NAME_='COUNT');
 569           _group="&x";
 570           _x=&x;
 571           _const=%sysevalf(&const+0);
 572           %do i=1 %to &numym1; %let j=%eval(&i+1);
 573              _numsum=sum(of col1-col&i); _densum=sum(of col&j-col&numy);
 574              %if &const=0 %then %do;
 575                _const=0;
 576                if _numsum=0 or _densum=0 then do;
 577                  _const=0.5; call symputx('zerosum',1);
 578                end;
 579              %end;
 580              c&i=log((_numsum + _const) / (_densum + _const));
 581           %end;
 582           keep c1-c&numym1 _group _x &x;
 583           run;
 584        %if &zerosum %then %do;
 585          %if %index(&version,DEBUG)=0 %then options notes;;
 586          %put NOTE: Zero sum detected for &x.. CONST=0.5 used in affected logits.;
 587          %if %index(&version,DEBUG)=0 %then options nonotes;;
 588          %end;
 589        %if &plot %then %do;
 590           proc sgplot;
 591              %do i=1 %to &numym1;
 592              series y=c&i x=&x /
 593                     legendlabel="&lgtlabl(O.V.<=&i)" name="series&i"
 594                     lineattrs=GraphData&i(thickness=3px);
 595              %end;
 596              yaxis label=
 597                 %if &numy>2 %then "Empirical Cumulative Logits";
 598                 %else "Empirical Logit";
 599              ;
 600              xaxis label="&x";
 601              xaxis integer label="&x";
 602              keylegend %do i=1 %to &numym1; "series&i" %end;;
 603              %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
 604              %else %str(title "Empirical Logit";);
 605              title2;
 606              run;
 607        %end;
 608        %mend;
 609        
 610        %macro OneContPlot(data=,x=,y=,numy=,const=0.5,smooth=.3,plot=1,nbhd=);
 611        /*--------------------------------------------------------------------------
 612          A macro extension of SAS Usage Note 37944 for continuous covariates. Computes
 613          and/or plots the empirical logits defined using the NBHD/2 observed X values
 614          preceding and following each observation against the levels of a single
 615          continuous X variable, then smooths the result. Called by the
 616          EmpiricalLogitPlot macro.
 617        
 618          data=    name of the input data set.
 619          x=       name of the single continuous covariate.
 620          y=       name of the response variable. y=1,2,3...
 621          numy=    number of levels of the response.
 622          const=   small value in case of zero cells.
 623          nbhd=    total number of neighbors.
 624          smooth=  smoothing parameter used for loess curve fit to logits for
 625                   continuous effects. Default: 0.3.
 626          plot=    1=create the plot, 0=create data set only
 627          --------------------------------------------------------------------------*/
 628        %let zerosum=0; %let nbhderr=0;
 629        data _temp;
 630           set &data;
 631           run;
 632        proc sort data=_temp;
 633           by &x &y;
 634           run;
 635        proc sql noprint;
 636          select count(*) into :nyx from &data
 637          where &y is not missing and &x is not missing;
 638          quit;
 639        data _null_;
 640          set _nx;
 641          maxnbhd=max(ceil(sqrt(&nyx)),ceil(.01*&nyx));
 642          if &nbhd>maxnbhd then call symputx("nbhderr",maxnbhd);
 643          run;
 644        %if &nbhderr %then %do;
 645          %if %index(&version,DEBUG)=0 %then options notes;;
 646          %put NOTE: NEIGHBORS=&nbhd decreased to &nbhderr for X=&x..;
 647          %if %index(&version,DEBUG)=0 %then options nonotes;;
 648          %let nbhd=&nbhderr; %let neighbors=&nbhd;
 649          %end;
 650        %let Full=%eval(&nbhd);
 651        %let Fullp1=%eval(&nbhd+1);
 652        %let Half=%eval(&nbhd/2);
 653        %let numym1=%eval(&numy-1);
 654        data _temp2;
 655           set _temp;
 656           retain %do i=1 %to &numy; _sum&i %end; 0;
 657           _lagx=lag&Full(&x);
 658           _lagHalfx=lag&Half(&x);
 659           _lagy=lag&Fullp1(&y);
 660           %do i=1 %to &numy; _sum&i=_sum&i+(&y=&i); %end;
 661           if (_lagy^=.) then do;
 662              %do i=1 %to &numy; _sum&i=_sum&i-(_lagy=&i); %end;
 663           end;
 664           run;
 665        data _temp;
 666           set _temp2;
 667           if (_n_<&Full) then delete;
 668           run;
 669        data _temp2;
 670           set _temp;
 671           length _group $ 32;
 672           _const=%sysevalf(&const+0);
 673           _x=_lagHalfx;
 674           _group="&x";
 675           %do i=1 %to &numym1; %let j=%eval(&i+1);
 676              _numsum=sum(of _sum1-_sum&i); _densum=sum(of _sum&j-_sum&numy);
 677              %if &const=0 %then %do;
 678                _const=0;
 679                if _numsum=0 or _densum=0 then do;
 680                  _const=0.5; call symputx('zerosum',1);
 681                end;
 682              %end;
 683             d&i=log((_numsum + _const) / (_densum + _const));
 684           %end;
 685           Neighbors=&nbhd;
 686           keep d1-d&numym1 _group _x neighbors;
 687           run;
 688        %if &zerosum %then %do;
 689          %if %index(&version,DEBUG)=0 %then options notes;;
 690          %put NOTE: Zero sum detected for &x.. CONST=0.5 used in affected logits.;
 691          %if %index(&version,DEBUG)=0 %then options nonotes;;
 692          %end;
 693        %if &plot %then %do;
 694           proc sgplot;
 695              %do i=1 %to &numym1;
 696              loess y=d&i x=_x /
 697                    smooth=&smooth legendlabel="&lgtlabl(O.V.<=&i)"
 698                    lineattrs=GraphData&i(thickness=3px)
 699                    markerattrs=(color=gray) name="series&i" nomarkers
 700              ;
 701              %end;
 702              yaxis label=
 703                 %if &numy>2 %then "Empirical Cumulative Logits";
 704                 %else "Empirical Logit";
 705              ;
 706              xaxis label="&x";
 707              keylegend %do i=1 %to &numym1; "series&i" %end;;
 708              %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
 709              %else %str(title "Empirical Logit";);
 710              title2 "with &nbhd neighbors and smoothing parameter = &smooth";
 711              run;
 712        %end;
 713        %mend;
 714        
 715        
 716        OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
 726        

when I run it.

1 ACCEPTED SOLUTION

Accepted Solutions
Reeza
Super User

You shouldn't initially change anything in the macro you copied over. When you execute the macro then you change the parameters.

 

So this is your macro definition for example - what you copied.

 

%macro print_file(dsn=);

proc print data=&dsn.;
run;

%mend;

And then this step executes the macro:

%print_file(dsn=sashelp.class);

It seems like the two steps were done at once. 

 

Instead, copy the macro code. Then in a separate step, call the macro with the desired parameters.

 

UCLA introductory tutorial on macro variables and macros

https://stats.idre.ucla.edu/sas/seminars/sas-macros-introduction/

Tutorial on converting a working program to a macro

This method is pretty robust and helps prevent errors and makes it much easier to debug your code. Obviously biased, because I wrote it 🙂 https://github.com/statgeek/SAS-Tutorials/blob/master/Turning%20a%20program%20into%20a%20macro.md

Examples of common macro usage

https://communities.sas.com/t5/SAS-Communities-Library/SAS-9-4-Macro-Language-Reference-Has-a-New-Ap...

 

Spoiler

@CathyVI wrote:

Hello, 

Please can anyone help with correctly using the code for empirical (observed) logits for ordinal response data. SAS provided this code in this paper: 37944 - Plotting empirical (observed) logits for binary and ordinal response data (sas.com)

I carefully copied the code into SAS on demand and only changed the data=?, y=? & x=?

data=    name of the input data set. Required.
  y=       name of the response variable. Required.
  x=       space-separated list of predictor variables. Required.

 but my code is not working. Please I would really appreciate any help. I wanted to use the code for my publication report.  

The empirical is a long code so I will not copy it here but here is my log when i run it.

 
 1          OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
 NOTE: ODS statements in the SAS Studio environment may disable some output features.
 69         
 70         /*                          INSTRUCTIONS FOR USE
 71         
 72            Version 1.1 or higher of the CtoN macro is required by the EmpiricalLogitPlot
 73            macro and must be defined before using the EmpiricalLogitPlot macro. Download
 74            it from this location: http://support.sas.com/kb/60678 and see the Downloads
 75            tab at that link. The code defining the CtoN macro and the code defining the
 76            macros below must all be submitted in your SAS session to make the macros
 77            available for use in that SAS Session. Do not alter any of the macro code
 78            to ensure successful macro execution. After running the macro code, check
 79            your SAS log to verify that no errors were generated.
 80         *******************************************************************************/
 81         
 82         %macro EmpiricalLogitPlot(version, data=stcp.cleanedpracticum2, y=issgrp, x=functional person_type gender dayofweek
 82       ! drug_bac lnage, const=0.5, neighbors=50,
 83                smooth=.3, contcutoff=20, options=DESCENDING PANEL) / minoperator;
 84         /*--------------------------------------------------------------------------
 85           A macro extension of SAS Usage Note 37944 for both class and continuous
 86           covariates. Calls the OneContPlot macro to plot the empirical logits defined
 87           using the NEIGHBORS/2 observed covariate values preceding and following each
 88           observation against the levels of a covariate with more than CONTCUTOFF
 89           levels. Calls the OneClassPlot macro to plot the empirical logits computed
 90           within each level of a covariate with fewer than CONTCUTOFF levels.
 91         
 92           version  Optional. Any text immediately following the open parenthesis and
 93                    followed by a comma will display the macro version.
 94           data=    name of the input data set. Required.
 95           y=       name of the response variable. Required.
 96           x=       space-separated list of predictor variables. Required.
 97           const=   small value between 0 and 1 to prevent zero counts. Default: 0.5.
 98           neighbors= number of neighbors around each observation used to compute
 99                    logits for continuous effects. Default: Average population size but
 100                   at least 1% of the sample size with a minimum of 2.
 101          smooth=  smoothing parameter used for loess curve fit to logits for
 102                   continuous effects. Default: 0.3.
 103          contcutoff= if an x= variable has more than the specified number of levels
 104                   then logits are computed within sets of neighboring observations;
 105                   otherwise computed within each level of the variable. Default: 20.
 106          options= DESCENDING (high response levels are of interest), ASCENDING (low
 107                   response levels are of interest), DATAORDER (use for character
 108                   response after sorting data so that first occurrence of each level
 109                   is in logically ascending or descending order as desired with the
 110                   first levels are of interest). Specify only one of DESCENDING,
 111                   ASCENDING, or DATAORDER. PANEL (single panel of all predictor
 112                   plots), NOPANEL (separate plot for each predictor). Default:
 113                   DESCENDING PANEL.
 114          --------------------------------------------------------------------------*/
 115        
 116        %macro existchk(data=, var=, dmsg=e, vmsg=e);
 117           %global status; %let status=ok;
 118           %if &dmsg=e %then %let dmsg=ERROR;
 119           %else %if &dmsg=w %then %let dmsg=WARNING;
 120           %else %let dmsg=NOTE;
 121           %if &vmsg=e %then %let vmsg=ERROR;
 122           %else %if &vmsg=w %then %let vmsg=WARNING;
 123           %else %let vmsg=NOTE;
 124           %if %quote(&data) ne %then %do;
 125             %if %sysfunc(exist(&data)) ne 1 %then %do;
 126               %put &dmsg: Data set %upcase(&data) not found.;
 127               %let status=nodata;
 128             %end;
 129             %else %if &var ne %then %do;
 130               %let dsid=%sysfunc(open(&data));
 131               %if &dsid %then %do;
 132                 %let i=1;
 133                 %do %while (%scan(&var,&i) ne %str() );
 134                    %let var&i=%scan(&var,&i);
 135                    %if %sysfunc(varnum(&dsid,&&var&i))=0 %then %do;
 136                      %put &vmsg: Variable %upcase(&&var&i) not found in data %upcase(&data).;
 137                      %let status=novar;
 138                    %end;
 139                    %let i=%eval(&i+1);
 140                 %end;
 141                 %let rc=%sysfunc(close(&dsid));
 142               %end;
 143               %else %put ERROR: Could not open data set &data.;
 144             %end;
 145           %end;
 146           %else %do;
 147             %put &dmsg: Data set not specified.;
 148             %let status=nodata;
 149           %end;
 150        %mend;
 151        
 152        %let elptime = %sysfunc(datetime());
 153        %let _version=1.2;
 154        %if &version ne %then %put NOTE: &sysmacroname macro Version &_version;
 155        %let _elpopts = %sysfunc(getoption(notes));
 156        %let version=%upcase(&version);
 157        %if %index(&version,DEBUG) %then %do;
 158          options notes mprint
 159            %if %index(&version,DEBUG2) %then mlogic symbolgen;
 160          ;
 161          ods select all;
 162          %put _user_;
 163        %end;
 164        %else %do;
 165          options nonotes nomprint nomlogic nosymbolgen;
 166          ods exclude all;
 167        %end;
 168        
 169        /* Check for newer version */
 170        %if %index(&version,NOCHECK)=0 %then %do;
 171           %let _notfound=0; %let _newver=0;
 172           filename _ver url 'http://ftp.sas.com/techsup/download/stat/versions.dat'
 173                    termstr=crlf;
 174           data _null_;
 175             infile _ver end=_eof;
 176             input name:$18. ver;
 177             if upcase(name)="&sysmacroname" then do;
 178               call symput("_newver",ver); stop;
 179             end;
 180             if _eof then call symput("_notfound",1);
 181             run;
 182           options notes;
 183           %if &syserr ne 0 or &_notfound=1 or &_newver=0 %then
 184             %put NOTE: Unable to check for newer version of &sysmacroname macro.;
 185           %else %if %sysevalf(&_newver > &_version) %then %do;
 186             %put NOTE: A newer version of the &sysmacroname macro is available at;
 187             %put NOTE- this location: http://support.sas.com/ ;
 188           %end;
 189           %if %index(%upcase(&version),DEBUG)=0 %then options nonotes;;
 190        %end;
 191        
 192        /* Input checks and process options */
 193        %if %index(&y,/) %then %do;
 194          %put ERROR: Events/Trials syntax is not supported in Y=.;
 195          %goto exit;
 196        %end;
 197        
 198        %existchk(data=&data, var=&y &x);
 199        %if &status=nodata or &status=novar %then %goto exit;
 200        
 201        %if %quote(&y)= %then %do;
 202          %put ERROR: Y= is required.;
 203          %goto exit;
 204        %end;
 205        
 206        %if &x= %then %do;
 207          %put ERROR: One or more variables must be specified in X=.;
 208          %goto exit;
 209        %end;
 210        
 211        %if %sysevalf(&neighbors ne) %then %do;
 212          %if %sysevalf(%sysfunc(mod(&neighbors,1)) ne 0 or &neighbors<=0) %then %do;
 213            %put ERROR: NEIGHBORS= must be an integer value greater than zero.;
 214            %goto exit;
 215          %end;
 216        %end;
 217        %else %let neighbors=50;
 218        %let nbhd=&neighbors;
 219        
 220        %if %sysevalf(&contcutoff ne) %then %do;
 221          %if %sysevalf(%sysfunc(mod(&contcutoff,1)) ne 0 or &contcutoff<=0) %then %do;
 222            %let contcutoff=%sysfunc(ceil(%sysfunc(abs(&contcutoff))));
 223            %if %index(&version,DEBUG)=0 %then options notes;;
 224            %put NOTE: CONTCUTOFF= value must be a positive integer.;
 225            %put NOTE- CONTCUTOFF= set to &contcutoff;
 226            %if %index(&version,DEBUG)=0 %then options nonotes;;
 227          %end;
 228        %end;
 229        %else %let contcutoff=20;
 230        
 231        %if %quote(&const) ne %then %do;
 232          %if (%sysfunc(verify(%sysfunc(catx( ,&const)),'0123456789.'))>0) +
 233              (%sysfunc(count(&const,.))>1) %then %do;
 234            %put ERROR: The CONST= value must be a positive value less than 1.;
 235            %goto exit;
 236          %end;
 237          %else %if &const<0 or &const>=1 %then %do;
 238            %put ERROR: The CONST= value must be a positive value less than 1.;
 239            %goto exit;
 240          %end;
 241        %end;
 242        %else %do;
 243          %put ERROR: CONST= is required and must be a positive value less than 1.;
 244          %goto exit;
 245        %end;
 246        
 247        %if %quote(&smooth) ne %then %do;
 248          %if (%sysfunc(verify(%sysfunc(catx( ,&smooth)),'0123456789.'))>0) +
 249              (%sysfunc(count(&smooth,.))>1) %then %do;
 250            %put ERROR: The SMOOTH= value must be a positive value.;
 251            %goto exit;
 252          %end;
 253          %else %if %sysevalf(&smooth<=0) %then %do;
 254            %put ERROR: The SMOOTH= value must be greater than zero.;
 255            %goto exit;
 256          %end;
 257        %end;
 258        %else %do;
 259          %put ERROR: SMOOTH= is required and must be positive value.;
 260          %goto exit;
 261        %end;
 262        
 263        %let validopts=ASCENDING DESCENDING DATAORDER PANEL NOPANEL;
 264        %let panel=1; %let plot=0; %let hievent=1; %let dataorder=0;
 265        %let i=1;
 266        %do %while (%scan(&options,&i) ne %str() );
 267           %let option&i=%upcase(%scan(&options,&i));
 268           %if &&option&i=DATAORDER %then %do;
 269              %let dataorder=1; %let hievent=0;
 270           %end;
 271           %else %if &&option&i=ASCENDING %then %let hievent=0;
 272           %else %if &&option&i=NOPANEL %then %do; %let panel=0; %let plot=1; %end;
 273           %else %do;
 274            %let chk=%eval(&&option&i in &validopts);
 275            %if not &chk %then %do;
 276              %put ERROR: Valid values of OPTIONS= are &validopts..;
 277              %goto exit;
 278            %end;
 279           %end;
 280           %let i=%eval(&i+1);
 281        %end;
 282        
 283        %if %index(&version,DEBUG)=0 %then options notes;;
 284        %put NOTE: Logits are computed over lower Ordered Values of &y..;
 285        %if %index(&version,DEBUG)=0 %then options nonotes;;
 286        
 287        proc sql;
 288          select count(*) into :n from &data where &y is not missing;
 289          quit;
 290        ods graphics / loessmaxobs=%sysfunc(max(5000,%eval(&n+1000)));
 291        data _tempdata;
 292           set &data;
 293           run;
 294        
 295        /* Order y= variable as requested */
 296        %if &dataorder=0 %then %do;
 297           proc sort data=_tempdata;
 298             by %if &hievent %then descending; &y;
 299             run;
 300        %end;
 301        %let chary=0; %let yname=&y;
 302        %let dsid=%sysfunc(open(_tempdata));
 303        %if &dsid %then %do;
 304          %let varnum=%sysfunc(varnum(&dsid,&y));
 305          %if %sysfunc(vartype(&dsid,&varnum))=C %then %do;
 306            %let rc=%sysfunc(close(&dsid));
 307            %CtoN(&version,data=_tempdata,var=&y,out=_tempdata,order=data,
 308                  options=noreplace noformat nodatanote nonewcheck)
 309            data _tempdata; set _tempdata(rename=(&y=_chary));
 310              label _chary='00'x;
 311              run;
 312            %let y=&y._N; %let chary=1;
 313          %end;
 314        %let rc=%sysfunc(close(&dsid));
 315        %end;
 316        proc freq nlevels data=_tempdata
 317          %if &hievent or &dataorder %then order=data;
 318        ;
 319           where not missing(&y);
 320           table &y %if &chary %then * _chary; / out=_ylevs noprint;
 321           ods exclude nlevels;
 322           ods output nlevels=_numy;
 323           run;
 324        data _null_;
 325           set _numy;
 326           call symputx('numy',nlevels);
 327           run;
 328        %if &chary=0 %then %do;
 329         data _null_;
 330           set _ylevs nobs=nlev;
 331           call symputx(cats('l',_n_),&y);
 332           run;
 333         data _tempdata;
 334           set _tempdata;
 335           select (&y);
 336             %do i=1 %to &numy;
 337               when (&&l&i) &y = &i;
 338             %end;
 339             otherwise &y = .;
 340           end;
 341           run;
 342        %end;
 343        %if &numy=2 %then %let lgtlabl=Logit;
 344        %else %let lgtlabl=CLogit;
 345        
 346        /* Variables with > 50 levels will use neighborhood method to compute logits.
 347           Variables with <=50 levels will have logits computed within each level.
 348        */
 349        %let cont=; %let class=;
 350        proc freq data=_tempdata nlevels;
 351          table &x / noprint;
 352          ods exclude nlevels;
 353          ods output nlevels=_nx;
 354          run;
 355        data _null_;
 356          set _nx;
 357          call symputx(cats('nlev',_n_),nnonmisslevels);
 358          run;
 359        %let i=1;
 360        %let dsid=%sysfunc(open(_tempdata));
 361        %if &dsid %then %do %while (%scan(&x,&i) ne %str() );
 362          %let varnum=%sysfunc(varnum(&dsid,%scan(%upcase(&x),&i)));
 363          %if %sysfunc(vartype(&dsid,&varnum))=N and &&nlev&i>20 %then
 364            %let cont=&cont %scan(&x,&i);
 365            %else %let class=&class %scan(&x,&i);
 366          %let i=%eval(&i+1);
 367        %end;
 368        %let rc=%sysfunc(close(&dsid));
 369        
 370        ods select all;
 371        %let num=1;
 372        %let numc=0;
 373        %let numd=0;
 374        %let totnum=1;
 375        %let doClass=1;
 376        %let numym1=%eval(&numy-1);
 377        %let var=%scan(&class,&num);
 378        %if (&var=) %then %do;
 379           %let doClass=0;
 380           %let var=%scan(&cont,&num);
 381           %if (&var=) %then %goto stopit;
 382        %end;
 383        data _ylevs;
 384          set _ylevs;
 385          ov=_n_;
 386          run;
 387        proc print data=_ylevs label noobs split="/";
 388          %if &chary=0 %then %do;
 389            id ov; var &y; label ov="Ordered/Value/(O.V.)";
 390          %end;
 391          %else %do;
 392            id &y; var _chary; label &y="Ordered/Value/(O.V.)" _chary="&yname";
 393          %end;
 394          title "Response Profile";
 395          title2 "Logits are computed over the lower Ordered Values";
 396          run;
 397        title;
 398        %do %while(&var ne);
 399           data _tempa(keep=&y &var);
 400              set _tempdata;
 401              run;
 402           %if %eval(&doClass eq 1) %then %do;
 403              %OneClassPlot(data=_tempa,x=&var,y=&y,numy=&numy,const=&const,plot=&plot);
 404              %let numc= %eval(&numc+1);
 405              data _tempc;
 406                 set %if %eval(&numc ne 1) %then _tempc; _temp2;
 407                 run;
 408           %end;
 409           %else %do;
 410              %OneContPlot(data=_tempa,x=&var,y=&y,numy=&numy,const=&const,plot=&plot,
 411                           nbhd=&nbhd);
 412              %let numd= %eval(&numd+1);
 413              data _tempd;
 414                 set %if %eval(&numd ne 1) %then _tempd; _temp2;
 415                 run;
 416           %end;
 417           %let num=%eval(&num+1);
 418           %let totnum=%eval(&totnum+1);;
 419           %if %eval(&doClass eq 1) %then %do;
 420              %let var=%scan(&class,&num);
 421              %if (&var=) %then %do;
 422                  %let doClass=0;
 423                  %let num=1;
 424              %end;
 425           %end;
 426           %if %eval(&doClass eq 0) %then %do;
 427              %let var=%scan(&cont,&num);
 428              %if (&var=) %then %goto stopit;
 429           %end;
 430        %end;
 431        
 432        %stopit: ;
 433        %if &panel %then %do;
 434           %if %eval(&numc>0) %then %do;
 435              proc sort data=_tempc;
 436                 by _group _x;
 437                 run;
 438           %end;
 439           %if %eval(&numd>0) %then %do;
 440              proc sort data=_tempd;
 441                 by _group _x;
 442                 run;
 443           %end;
 444           %if %eval(&numc>0 and &numd>0) %then %do;
 445              data _tempall;
 446                 merge _tempd _tempc;
 447                 by _group _x;
 448                 run;
 449           %end;
 450           %else %if %eval(&numc>0) %then %do;
 451              data _tempall;
 452                 set _tempc;
 453                 run;
 454           %end;
 455           %else %do;
 456              data _tempall;
 457                 set _tempd;
 458                 run;
 459           %end;
 460           proc sort data=_tempall;
 461              by _group;
 462              run;
 463           data _tempa(keep=_group _minx _maxx);
 464              set _tempall;
 465              by _group;
 466              retain _minx 1e100 _maxx -1e100;
 467              if first._group then do;
 468                 _minx=_x;
 469                 _maxx=_x;
 470              end;
 471              _minx=min(_minx,_x);
 472              _maxx=max(_maxx,_x);
 473              if last._group then output;
 474              run;
 475           data _tempall;
 476              merge _tempall _tempa;
 477              by _group;
 478              _x=(_x-_minx)/(_maxx-_minx);
 479              run;
 480           %if       ((&totnum-1)=1)   %then %do; %let rows=1; %let cols=1; %end;
 481           %else %if ((&totnum-1)=2)   %then %do; %let rows=1; %let cols=2; %end;
 482           %else %if ((&totnum-1)=3)   %then %do; %let rows=1; %let cols=3; %end;
 483           %else %if ((&totnum-1)=4)   %then %do; %let rows=2; %let cols=2; %end;
 484           %else %if ((&totnum-1)<=6)  %then %do; %let rows=2; %let cols=3; %end;
 485           %else %if ((&totnum-1)<=9)  %then %do; %let rows=3; %let cols=3; %end;
 486           %else %if ((&totnum-1)<=12) %then %do; %let rows=3; %let cols=4; %end;
 487           %else %do; %let cols=4; %let rows=4;  %end;
 488           proc sgpanel data=_tempall;
 489              panelby _group / novarname columns=&cols rows=&rows
 490                               uniscale=all skipemptycells;
 491              rowaxis label=
 492                 %if &numy>2 %then "Empirical Cumulative Logits";
 493                 %else "Empirical Logit";
 494              ;
 495              colaxis display=(nolabel noticks novalues);
 496              %if (&numd>0) %then %do i=1 %to &numym1;
 497              loess y=d&i x=_x / smooth=&smooth legendlabel="&lgtlabl(O.V.<=&i)"
 498                    name="series&i" lineattrs=GraphData&i(thickness=3px)
 499                    markerattrs=GraphDataDefault(color=gray) nomarkers
 500              ;
 501              %end;
 502              %if (&numc>0) %then %do i=1 %to &numym1;
 503              series y=c&i x=_x / legendlabel="&lgtlabl(O.V.<=&i)" name="series&i"
 504                     lineattrs=GraphData&i(thickness=3px);
 505              %end;
 506              %if &numd %then inset neighbors / position=bottom;;
 507              keylegend %do i=1 %to &numym1; "series&i" %end;;
 508              %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
 509              %else %str(title "Empirical Logit";);
 510              %if &numd %then
 511              title2 "Smoothing parameter = &smooth for continuous predictors";;
 512              run;
 513        %end;
 514        
 515        %exit:
 516        %if %index(&version,DEBUG)=0 %then %do;
 517           proc datasets nolist;
 518              delete _: ;
 519              run; quit;
 520        %end;
 521        %if %index(&version,DEBUG) %then %do;
 522          options nomprint nomlogic nosymbolgen;
 523          %put _user_;
 524        %end;
 525        options &_elpopts;
 526        title;
 527        %let elptime=%sysfunc(round(%sysevalf(%sysfunc(datetime()) - &elptime), 0.01));
 528        %put NOTE: The &sysmacroname macro used &elptime seconds.;
 529        %mend;
 530        
 531        %macro OneClassPlot(data=,x=,y=,numy=,const=0.5,plot=1);
 532        /*--------------------------------------------------------------------------
 533          A macro version of SAS Usage Note 37944 for covariates with fewer than
 534          CONTCUTOFF levels. Computes and/or plots the empirical logits of Y against
 535          the levels of one X variable.  Called by the EmpiricalLogitPlot macro.
 536        
 537          data=    name of the input data set.
 538          x=       name of the single CLASS covariate.
 539          y=       name of the response variable.
 540          numy=    number of levels of the response.
 541          const=   small value in case of zero cells.
 542          plot=    1=create the plot, 0=create data set only
 543          --------------------------------------------------------------------------*/
 544        %let numym1=%eval(&numy-1);
 545        %let zerosum=0;
 546        proc freq data=&data noprint;
 547           table &x*&y / sparse out=_temp2;
 548        run;
 549        proc sort data=_temp2;
 550           by &x;
 551        run;
 552        %let dsid=%sysfunc(open(_temp2));
 553        %if &dsid %then %do;
 554          %let varnum=%sysfunc(varnum(&dsid,&x));
 555          %if %sysfunc(vartype(&dsid,&varnum))=C %then %do;
 556            %let rc=%sysfunc(close(&dsid));
 557            %CtoN(&version,data=_temp2,var=&x,out=_temp2,options=format nodatanote nonewcheck)
 558          %end;
 559          %let rc=%sysfunc(close(&dsid));
 560        %end;
 561        proc transpose data=_temp2 out=_temp;
 562           by &x;
 563           var count;
 564           run;
 565        data _temp2 ;
 566           set _temp;
 567           length _group $ 32;
 568           if (_NAME_='COUNT');
 569           _group="&x";
 570           _x=&x;
 571           _const=%sysevalf(&const+0);
 572           %do i=1 %to &numym1; %let j=%eval(&i+1);
 573              _numsum=sum(of col1-col&i); _densum=sum(of col&j-col&numy);
 574              %if &const=0 %then %do;
 575                _const=0;
 576                if _numsum=0 or _densum=0 then do;
 577                  _const=0.5; call symputx('zerosum',1);
 578                end;
 579              %end;
 580              c&i=log((_numsum + _const) / (_densum + _const));
 581           %end;
 582           keep c1-c&numym1 _group _x &x;
 583           run;
 584        %if &zerosum %then %do;
 585          %if %index(&version,DEBUG)=0 %then options notes;;
 586          %put NOTE: Zero sum detected for &x.. CONST=0.5 used in affected logits.;
 587          %if %index(&version,DEBUG)=0 %then options nonotes;;
 588          %end;
 589        %if &plot %then %do;
 590           proc sgplot;
 591              %do i=1 %to &numym1;
 592              series y=c&i x=&x /
 593                     legendlabel="&lgtlabl(O.V.<=&i)" name="series&i"
 594                     lineattrs=GraphData&i(thickness=3px);
 595              %end;
 596              yaxis label=
 597                 %if &numy>2 %then "Empirical Cumulative Logits";
 598                 %else "Empirical Logit";
 599              ;
 600              xaxis label="&x";
 601              xaxis integer label="&x";
 602              keylegend %do i=1 %to &numym1; "series&i" %end;;
 603              %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
 604              %else %str(title "Empirical Logit";);
 605              title2;
 606              run;
 607        %end;
 608        %mend;
 609        
 610        %macro OneContPlot(data=,x=,y=,numy=,const=0.5,smooth=.3,plot=1,nbhd=);
 611        /*--------------------------------------------------------------------------
 612          A macro extension of SAS Usage Note 37944 for continuous covariates. Computes
 613          and/or plots the empirical logits defined using the NBHD/2 observed X values
 614          preceding and following each observation against the levels of a single
 615          continuous X variable, then smooths the result. Called by the
 616          EmpiricalLogitPlot macro.
 617        
 618          data=    name of the input data set.
 619          x=       name of the single continuous covariate.
 620          y=       name of the response variable. y=1,2,3...
 621          numy=    number of levels of the response.
 622          const=   small value in case of zero cells.
 623          nbhd=    total number of neighbors.
 624          smooth=  smoothing parameter used for loess curve fit to logits for
 625                   continuous effects. Default: 0.3.
 626          plot=    1=create the plot, 0=create data set only
 627          --------------------------------------------------------------------------*/
 628        %let zerosum=0; %let nbhderr=0;
 629        data _temp;
 630           set &data;
 631           run;
 632        proc sort data=_temp;
 633           by &x &y;
 634           run;
 635        proc sql noprint;
 636          select count(*) into :nyx from &data
 637          where &y is not missing and &x is not missing;
 638          quit;
 639        data _null_;
 640          set _nx;
 641          maxnbhd=max(ceil(sqrt(&nyx)),ceil(.01*&nyx));
 642          if &nbhd>maxnbhd then call symputx("nbhderr",maxnbhd);
 643          run;
 644        %if &nbhderr %then %do;
 645          %if %index(&version,DEBUG)=0 %then options notes;;
 646          %put NOTE: NEIGHBORS=&nbhd decreased to &nbhderr for X=&x..;
 647          %if %index(&version,DEBUG)=0 %then options nonotes;;
 648          %let nbhd=&nbhderr; %let neighbors=&nbhd;
 649          %end;
 650        %let Full=%eval(&nbhd);
 651        %let Fullp1=%eval(&nbhd+1);
 652        %let Half=%eval(&nbhd/2);
 653        %let numym1=%eval(&numy-1);
 654        data _temp2;
 655           set _temp;
 656           retain %do i=1 %to &numy; _sum&i %end; 0;
 657           _lagx=lag&Full(&x);
 658           _lagHalfx=lag&Half(&x);
 659           _lagy=lag&Fullp1(&y);
 660           %do i=1 %to &numy; _sum&i=_sum&i+(&y=&i); %end;
 661           if (_lagy^=.) then do;
 662              %do i=1 %to &numy; _sum&i=_sum&i-(_lagy=&i); %end;
 663           end;
 664           run;
 665        data _temp;
 666           set _temp2;
 667           if (_n_<&Full) then delete;
 668           run;
 669        data _temp2;
 670           set _temp;
 671           length _group $ 32;
 672           _const=%sysevalf(&const+0);
 673           _x=_lagHalfx;
 674           _group="&x";
 675           %do i=1 %to &numym1; %let j=%eval(&i+1);
 676              _numsum=sum(of _sum1-_sum&i); _densum=sum(of _sum&j-_sum&numy);
 677              %if &const=0 %then %do;
 678                _const=0;
 679                if _numsum=0 or _densum=0 then do;
 680                  _const=0.5; call symputx('zerosum',1);
 681                end;
 682              %end;
 683             d&i=log((_numsum + _const) / (_densum + _const));
 684           %end;
 685           Neighbors=&nbhd;
 686           keep d1-d&numym1 _group _x neighbors;
 687           run;
 688        %if &zerosum %then %do;
 689          %if %index(&version,DEBUG)=0 %then options notes;;
 690          %put NOTE: Zero sum detected for &x.. CONST=0.5 used in affected logits.;
 691          %if %index(&version,DEBUG)=0 %then options nonotes;;
 692          %end;
 693        %if &plot %then %do;
 694           proc sgplot;
 695              %do i=1 %to &numym1;
 696              loess y=d&i x=_x /
 697                    smooth=&smooth legendlabel="&lgtlabl(O.V.<=&i)"
 698                    lineattrs=GraphData&i(thickness=3px)
 699                    markerattrs=(color=gray) name="series&i" nomarkers
 700              ;
 701              %end;
 702              yaxis label=
 703                 %if &numy>2 %then "Empirical Cumulative Logits";
 704                 %else "Empirical Logit";
 705              ;
 706              xaxis label="&x";
 707              keylegend %do i=1 %to &numym1; "series&i" %end;;
 708              %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
 709              %else %str(title "Empirical Logit";);
 710              title2 "with &nbhd neighbors and smoothing parameter = &smooth";
 711              run;
 712        %end;
 713        %mend;
 714        
 715        
 716        OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
 726        

when I run it.


View solution in original post

9 REPLIES 9
Reeza
Super User

You shouldn't initially change anything in the macro you copied over. When you execute the macro then you change the parameters.

 

So this is your macro definition for example - what you copied.

 

%macro print_file(dsn=);

proc print data=&dsn.;
run;

%mend;

And then this step executes the macro:

%print_file(dsn=sashelp.class);

It seems like the two steps were done at once. 

 

Instead, copy the macro code. Then in a separate step, call the macro with the desired parameters.

 

UCLA introductory tutorial on macro variables and macros

https://stats.idre.ucla.edu/sas/seminars/sas-macros-introduction/

Tutorial on converting a working program to a macro

This method is pretty robust and helps prevent errors and makes it much easier to debug your code. Obviously biased, because I wrote it 🙂 https://github.com/statgeek/SAS-Tutorials/blob/master/Turning%20a%20program%20into%20a%20macro.md

Examples of common macro usage

https://communities.sas.com/t5/SAS-Communities-Library/SAS-9-4-Macro-Language-Reference-Has-a-New-Ap...

 

Spoiler

@CathyVI wrote:

Hello, 

Please can anyone help with correctly using the code for empirical (observed) logits for ordinal response data. SAS provided this code in this paper: 37944 - Plotting empirical (observed) logits for binary and ordinal response data (sas.com)

I carefully copied the code into SAS on demand and only changed the data=?, y=? & x=?

data=    name of the input data set. Required.
  y=       name of the response variable. Required.
  x=       space-separated list of predictor variables. Required.

 but my code is not working. Please I would really appreciate any help. I wanted to use the code for my publication report.  

The empirical is a long code so I will not copy it here but here is my log when i run it.

 
 1          OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
 NOTE: ODS statements in the SAS Studio environment may disable some output features.
 69         
 70         /*                          INSTRUCTIONS FOR USE
 71         
 72            Version 1.1 or higher of the CtoN macro is required by the EmpiricalLogitPlot
 73            macro and must be defined before using the EmpiricalLogitPlot macro. Download
 74            it from this location: http://support.sas.com/kb/60678 and see the Downloads
 75            tab at that link. The code defining the CtoN macro and the code defining the
 76            macros below must all be submitted in your SAS session to make the macros
 77            available for use in that SAS Session. Do not alter any of the macro code
 78            to ensure successful macro execution. After running the macro code, check
 79            your SAS log to verify that no errors were generated.
 80         *******************************************************************************/
 81         
 82         %macro EmpiricalLogitPlot(version, data=stcp.cleanedpracticum2, y=issgrp, x=functional person_type gender dayofweek
 82       ! drug_bac lnage, const=0.5, neighbors=50,
 83                smooth=.3, contcutoff=20, options=DESCENDING PANEL) / minoperator;
 84         /*--------------------------------------------------------------------------
 85           A macro extension of SAS Usage Note 37944 for both class and continuous
 86           covariates. Calls the OneContPlot macro to plot the empirical logits defined
 87           using the NEIGHBORS/2 observed covariate values preceding and following each
 88           observation against the levels of a covariate with more than CONTCUTOFF
 89           levels. Calls the OneClassPlot macro to plot the empirical logits computed
 90           within each level of a covariate with fewer than CONTCUTOFF levels.
 91         
 92           version  Optional. Any text immediately following the open parenthesis and
 93                    followed by a comma will display the macro version.
 94           data=    name of the input data set. Required.
 95           y=       name of the response variable. Required.
 96           x=       space-separated list of predictor variables. Required.
 97           const=   small value between 0 and 1 to prevent zero counts. Default: 0.5.
 98           neighbors= number of neighbors around each observation used to compute
 99                    logits for continuous effects. Default: Average population size but
 100                   at least 1% of the sample size with a minimum of 2.
 101          smooth=  smoothing parameter used for loess curve fit to logits for
 102                   continuous effects. Default: 0.3.
 103          contcutoff= if an x= variable has more than the specified number of levels
 104                   then logits are computed within sets of neighboring observations;
 105                   otherwise computed within each level of the variable. Default: 20.
 106          options= DESCENDING (high response levels are of interest), ASCENDING (low
 107                   response levels are of interest), DATAORDER (use for character
 108                   response after sorting data so that first occurrence of each level
 109                   is in logically ascending or descending order as desired with the
 110                   first levels are of interest). Specify only one of DESCENDING,
 111                   ASCENDING, or DATAORDER. PANEL (single panel of all predictor
 112                   plots), NOPANEL (separate plot for each predictor). Default:
 113                   DESCENDING PANEL.
 114          --------------------------------------------------------------------------*/
 115        
 116        %macro existchk(data=, var=, dmsg=e, vmsg=e);
 117           %global status; %let status=ok;
 118           %if &dmsg=e %then %let dmsg=ERROR;
 119           %else %if &dmsg=w %then %let dmsg=WARNING;
 120           %else %let dmsg=NOTE;
 121           %if &vmsg=e %then %let vmsg=ERROR;
 122           %else %if &vmsg=w %then %let vmsg=WARNING;
 123           %else %let vmsg=NOTE;
 124           %if %quote(&data) ne %then %do;
 125             %if %sysfunc(exist(&data)) ne 1 %then %do;
 126               %put &dmsg: Data set %upcase(&data) not found.;
 127               %let status=nodata;
 128             %end;
 129             %else %if &var ne %then %do;
 130               %let dsid=%sysfunc(open(&data));
 131               %if &dsid %then %do;
 132                 %let i=1;
 133                 %do %while (%scan(&var,&i) ne %str() );
 134                    %let var&i=%scan(&var,&i);
 135                    %if %sysfunc(varnum(&dsid,&&var&i))=0 %then %do;
 136                      %put &vmsg: Variable %upcase(&&var&i) not found in data %upcase(&data).;
 137                      %let status=novar;
 138                    %end;
 139                    %let i=%eval(&i+1);
 140                 %end;
 141                 %let rc=%sysfunc(close(&dsid));
 142               %end;
 143               %else %put ERROR: Could not open data set &data.;
 144             %end;
 145           %end;
 146           %else %do;
 147             %put &dmsg: Data set not specified.;
 148             %let status=nodata;
 149           %end;
 150        %mend;
 151        
 152        %let elptime = %sysfunc(datetime());
 153        %let _version=1.2;
 154        %if &version ne %then %put NOTE: &sysmacroname macro Version &_version;
 155        %let _elpopts = %sysfunc(getoption(notes));
 156        %let version=%upcase(&version);
 157        %if %index(&version,DEBUG) %then %do;
 158          options notes mprint
 159            %if %index(&version,DEBUG2) %then mlogic symbolgen;
 160          ;
 161          ods select all;
 162          %put _user_;
 163        %end;
 164        %else %do;
 165          options nonotes nomprint nomlogic nosymbolgen;
 166          ods exclude all;
 167        %end;
 168        
 169        /* Check for newer version */
 170        %if %index(&version,NOCHECK)=0 %then %do;
 171           %let _notfound=0; %let _newver=0;
 172           filename _ver url 'http://ftp.sas.com/techsup/download/stat/versions.dat'
 173                    termstr=crlf;
 174           data _null_;
 175             infile _ver end=_eof;
 176             input name:$18. ver;
 177             if upcase(name)="&sysmacroname" then do;
 178               call symput("_newver",ver); stop;
 179             end;
 180             if _eof then call symput("_notfound",1);
 181             run;
 182           options notes;
 183           %if &syserr ne 0 or &_notfound=1 or &_newver=0 %then
 184             %put NOTE: Unable to check for newer version of &sysmacroname macro.;
 185           %else %if %sysevalf(&_newver > &_version) %then %do;
 186             %put NOTE: A newer version of the &sysmacroname macro is available at;
 187             %put NOTE- this location: http://support.sas.com/ ;
 188           %end;
 189           %if %index(%upcase(&version),DEBUG)=0 %then options nonotes;;
 190        %end;
 191        
 192        /* Input checks and process options */
 193        %if %index(&y,/) %then %do;
 194          %put ERROR: Events/Trials syntax is not supported in Y=.;
 195          %goto exit;
 196        %end;
 197        
 198        %existchk(data=&data, var=&y &x);
 199        %if &status=nodata or &status=novar %then %goto exit;
 200        
 201        %if %quote(&y)= %then %do;
 202          %put ERROR: Y= is required.;
 203          %goto exit;
 204        %end;
 205        
 206        %if &x= %then %do;
 207          %put ERROR: One or more variables must be specified in X=.;
 208          %goto exit;
 209        %end;
 210        
 211        %if %sysevalf(&neighbors ne) %then %do;
 212          %if %sysevalf(%sysfunc(mod(&neighbors,1)) ne 0 or &neighbors<=0) %then %do;
 213            %put ERROR: NEIGHBORS= must be an integer value greater than zero.;
 214            %goto exit;
 215          %end;
 216        %end;
 217        %else %let neighbors=50;
 218        %let nbhd=&neighbors;
 219        
 220        %if %sysevalf(&contcutoff ne) %then %do;
 221          %if %sysevalf(%sysfunc(mod(&contcutoff,1)) ne 0 or &contcutoff<=0) %then %do;
 222            %let contcutoff=%sysfunc(ceil(%sysfunc(abs(&contcutoff))));
 223            %if %index(&version,DEBUG)=0 %then options notes;;
 224            %put NOTE: CONTCUTOFF= value must be a positive integer.;
 225            %put NOTE- CONTCUTOFF= set to &contcutoff;
 226            %if %index(&version,DEBUG)=0 %then options nonotes;;
 227          %end;
 228        %end;
 229        %else %let contcutoff=20;
 230        
 231        %if %quote(&const) ne %then %do;
 232          %if (%sysfunc(verify(%sysfunc(catx( ,&const)),'0123456789.'))>0) +
 233              (%sysfunc(count(&const,.))>1) %then %do;
 234            %put ERROR: The CONST= value must be a positive value less than 1.;
 235            %goto exit;
 236          %end;
 237          %else %if &const<0 or &const>=1 %then %do;
 238            %put ERROR: The CONST= value must be a positive value less than 1.;
 239            %goto exit;
 240          %end;
 241        %end;
 242        %else %do;
 243          %put ERROR: CONST= is required and must be a positive value less than 1.;
 244          %goto exit;
 245        %end;
 246        
 247        %if %quote(&smooth) ne %then %do;
 248          %if (%sysfunc(verify(%sysfunc(catx( ,&smooth)),'0123456789.'))>0) +
 249              (%sysfunc(count(&smooth,.))>1) %then %do;
 250            %put ERROR: The SMOOTH= value must be a positive value.;
 251            %goto exit;
 252          %end;
 253          %else %if %sysevalf(&smooth<=0) %then %do;
 254            %put ERROR: The SMOOTH= value must be greater than zero.;
 255            %goto exit;
 256          %end;
 257        %end;
 258        %else %do;
 259          %put ERROR: SMOOTH= is required and must be positive value.;
 260          %goto exit;
 261        %end;
 262        
 263        %let validopts=ASCENDING DESCENDING DATAORDER PANEL NOPANEL;
 264        %let panel=1; %let plot=0; %let hievent=1; %let dataorder=0;
 265        %let i=1;
 266        %do %while (%scan(&options,&i) ne %str() );
 267           %let option&i=%upcase(%scan(&options,&i));
 268           %if &&option&i=DATAORDER %then %do;
 269              %let dataorder=1; %let hievent=0;
 270           %end;
 271           %else %if &&option&i=ASCENDING %then %let hievent=0;
 272           %else %if &&option&i=NOPANEL %then %do; %let panel=0; %let plot=1; %end;
 273           %else %do;
 274            %let chk=%eval(&&option&i in &validopts);
 275            %if not &chk %then %do;
 276              %put ERROR: Valid values of OPTIONS= are &validopts..;
 277              %goto exit;
 278            %end;
 279           %end;
 280           %let i=%eval(&i+1);
 281        %end;
 282        
 283        %if %index(&version,DEBUG)=0 %then options notes;;
 284        %put NOTE: Logits are computed over lower Ordered Values of &y..;
 285        %if %index(&version,DEBUG)=0 %then options nonotes;;
 286        
 287        proc sql;
 288          select count(*) into :n from &data where &y is not missing;
 289          quit;
 290        ods graphics / loessmaxobs=%sysfunc(max(5000,%eval(&n+1000)));
 291        data _tempdata;
 292           set &data;
 293           run;
 294        
 295        /* Order y= variable as requested */
 296        %if &dataorder=0 %then %do;
 297           proc sort data=_tempdata;
 298             by %if &hievent %then descending; &y;
 299             run;
 300        %end;
 301        %let chary=0; %let yname=&y;
 302        %let dsid=%sysfunc(open(_tempdata));
 303        %if &dsid %then %do;
 304          %let varnum=%sysfunc(varnum(&dsid,&y));
 305          %if %sysfunc(vartype(&dsid,&varnum))=C %then %do;
 306            %let rc=%sysfunc(close(&dsid));
 307            %CtoN(&version,data=_tempdata,var=&y,out=_tempdata,order=data,
 308                  options=noreplace noformat nodatanote nonewcheck)
 309            data _tempdata; set _tempdata(rename=(&y=_chary));
 310              label _chary='00'x;
 311              run;
 312            %let y=&y._N; %let chary=1;
 313          %end;
 314        %let rc=%sysfunc(close(&dsid));
 315        %end;
 316        proc freq nlevels data=_tempdata
 317          %if &hievent or &dataorder %then order=data;
 318        ;
 319           where not missing(&y);
 320           table &y %if &chary %then * _chary; / out=_ylevs noprint;
 321           ods exclude nlevels;
 322           ods output nlevels=_numy;
 323           run;
 324        data _null_;
 325           set _numy;
 326           call symputx('numy',nlevels);
 327           run;
 328        %if &chary=0 %then %do;
 329         data _null_;
 330           set _ylevs nobs=nlev;
 331           call symputx(cats('l',_n_),&y);
 332           run;
 333         data _tempdata;
 334           set _tempdata;
 335           select (&y);
 336             %do i=1 %to &numy;
 337               when (&&l&i) &y = &i;
 338             %end;
 339             otherwise &y = .;
 340           end;
 341           run;
 342        %end;
 343        %if &numy=2 %then %let lgtlabl=Logit;
 344        %else %let lgtlabl=CLogit;
 345        
 346        /* Variables with > 50 levels will use neighborhood method to compute logits.
 347           Variables with <=50 levels will have logits computed within each level.
 348        */
 349        %let cont=; %let class=;
 350        proc freq data=_tempdata nlevels;
 351          table &x / noprint;
 352          ods exclude nlevels;
 353          ods output nlevels=_nx;
 354          run;
 355        data _null_;
 356          set _nx;
 357          call symputx(cats('nlev',_n_),nnonmisslevels);
 358          run;
 359        %let i=1;
 360        %let dsid=%sysfunc(open(_tempdata));
 361        %if &dsid %then %do %while (%scan(&x,&i) ne %str() );
 362          %let varnum=%sysfunc(varnum(&dsid,%scan(%upcase(&x),&i)));
 363          %if %sysfunc(vartype(&dsid,&varnum))=N and &&nlev&i>20 %then
 364            %let cont=&cont %scan(&x,&i);
 365            %else %let class=&class %scan(&x,&i);
 366          %let i=%eval(&i+1);
 367        %end;
 368        %let rc=%sysfunc(close(&dsid));
 369        
 370        ods select all;
 371        %let num=1;
 372        %let numc=0;
 373        %let numd=0;
 374        %let totnum=1;
 375        %let doClass=1;
 376        %let numym1=%eval(&numy-1);
 377        %let var=%scan(&class,&num);
 378        %if (&var=) %then %do;
 379           %let doClass=0;
 380           %let var=%scan(&cont,&num);
 381           %if (&var=) %then %goto stopit;
 382        %end;
 383        data _ylevs;
 384          set _ylevs;
 385          ov=_n_;
 386          run;
 387        proc print data=_ylevs label noobs split="/";
 388          %if &chary=0 %then %do;
 389            id ov; var &y; label ov="Ordered/Value/(O.V.)";
 390          %end;
 391          %else %do;
 392            id &y; var _chary; label &y="Ordered/Value/(O.V.)" _chary="&yname";
 393          %end;
 394          title "Response Profile";
 395          title2 "Logits are computed over the lower Ordered Values";
 396          run;
 397        title;
 398        %do %while(&var ne);
 399           data _tempa(keep=&y &var);
 400              set _tempdata;
 401              run;
 402           %if %eval(&doClass eq 1) %then %do;
 403              %OneClassPlot(data=_tempa,x=&var,y=&y,numy=&numy,const=&const,plot=&plot);
 404              %let numc= %eval(&numc+1);
 405              data _tempc;
 406                 set %if %eval(&numc ne 1) %then _tempc; _temp2;
 407                 run;
 408           %end;
 409           %else %do;
 410              %OneContPlot(data=_tempa,x=&var,y=&y,numy=&numy,const=&const,plot=&plot,
 411                           nbhd=&nbhd);
 412              %let numd= %eval(&numd+1);
 413              data _tempd;
 414                 set %if %eval(&numd ne 1) %then _tempd; _temp2;
 415                 run;
 416           %end;
 417           %let num=%eval(&num+1);
 418           %let totnum=%eval(&totnum+1);;
 419           %if %eval(&doClass eq 1) %then %do;
 420              %let var=%scan(&class,&num);
 421              %if (&var=) %then %do;
 422                  %let doClass=0;
 423                  %let num=1;
 424              %end;
 425           %end;
 426           %if %eval(&doClass eq 0) %then %do;
 427              %let var=%scan(&cont,&num);
 428              %if (&var=) %then %goto stopit;
 429           %end;
 430        %end;
 431        
 432        %stopit: ;
 433        %if &panel %then %do;
 434           %if %eval(&numc>0) %then %do;
 435              proc sort data=_tempc;
 436                 by _group _x;
 437                 run;
 438           %end;
 439           %if %eval(&numd>0) %then %do;
 440              proc sort data=_tempd;
 441                 by _group _x;
 442                 run;
 443           %end;
 444           %if %eval(&numc>0 and &numd>0) %then %do;
 445              data _tempall;
 446                 merge _tempd _tempc;
 447                 by _group _x;
 448                 run;
 449           %end;
 450           %else %if %eval(&numc>0) %then %do;
 451              data _tempall;
 452                 set _tempc;
 453                 run;
 454           %end;
 455           %else %do;
 456              data _tempall;
 457                 set _tempd;
 458                 run;
 459           %end;
 460           proc sort data=_tempall;
 461              by _group;
 462              run;
 463           data _tempa(keep=_group _minx _maxx);
 464              set _tempall;
 465              by _group;
 466              retain _minx 1e100 _maxx -1e100;
 467              if first._group then do;
 468                 _minx=_x;
 469                 _maxx=_x;
 470              end;
 471              _minx=min(_minx,_x);
 472              _maxx=max(_maxx,_x);
 473              if last._group then output;
 474              run;
 475           data _tempall;
 476              merge _tempall _tempa;
 477              by _group;
 478              _x=(_x-_minx)/(_maxx-_minx);
 479              run;
 480           %if       ((&totnum-1)=1)   %then %do; %let rows=1; %let cols=1; %end;
 481           %else %if ((&totnum-1)=2)   %then %do; %let rows=1; %let cols=2; %end;
 482           %else %if ((&totnum-1)=3)   %then %do; %let rows=1; %let cols=3; %end;
 483           %else %if ((&totnum-1)=4)   %then %do; %let rows=2; %let cols=2; %end;
 484           %else %if ((&totnum-1)<=6)  %then %do; %let rows=2; %let cols=3; %end;
 485           %else %if ((&totnum-1)<=9)  %then %do; %let rows=3; %let cols=3; %end;
 486           %else %if ((&totnum-1)<=12) %then %do; %let rows=3; %let cols=4; %end;
 487           %else %do; %let cols=4; %let rows=4;  %end;
 488           proc sgpanel data=_tempall;
 489              panelby _group / novarname columns=&cols rows=&rows
 490                               uniscale=all skipemptycells;
 491              rowaxis label=
 492                 %if &numy>2 %then "Empirical Cumulative Logits";
 493                 %else "Empirical Logit";
 494              ;
 495              colaxis display=(nolabel noticks novalues);
 496              %if (&numd>0) %then %do i=1 %to &numym1;
 497              loess y=d&i x=_x / smooth=&smooth legendlabel="&lgtlabl(O.V.<=&i)"
 498                    name="series&i" lineattrs=GraphData&i(thickness=3px)
 499                    markerattrs=GraphDataDefault(color=gray) nomarkers
 500              ;
 501              %end;
 502              %if (&numc>0) %then %do i=1 %to &numym1;
 503              series y=c&i x=_x / legendlabel="&lgtlabl(O.V.<=&i)" name="series&i"
 504                     lineattrs=GraphData&i(thickness=3px);
 505              %end;
 506              %if &numd %then inset neighbors / position=bottom;;
 507              keylegend %do i=1 %to &numym1; "series&i" %end;;
 508              %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
 509              %else %str(title "Empirical Logit";);
 510              %if &numd %then
 511              title2 "Smoothing parameter = &smooth for continuous predictors";;
 512              run;
 513        %end;
 514        
 515        %exit:
 516        %if %index(&version,DEBUG)=0 %then %do;
 517           proc datasets nolist;
 518              delete _: ;
 519              run; quit;
 520        %end;
 521        %if %index(&version,DEBUG) %then %do;
 522          options nomprint nomlogic nosymbolgen;
 523          %put _user_;
 524        %end;
 525        options &_elpopts;
 526        title;
 527        %let elptime=%sysfunc(round(%sysevalf(%sysfunc(datetime()) - &elptime), 0.01));
 528        %put NOTE: The &sysmacroname macro used &elptime seconds.;
 529        %mend;
 530        
 531        %macro OneClassPlot(data=,x=,y=,numy=,const=0.5,plot=1);
 532        /*--------------------------------------------------------------------------
 533          A macro version of SAS Usage Note 37944 for covariates with fewer than
 534          CONTCUTOFF levels. Computes and/or plots the empirical logits of Y against
 535          the levels of one X variable.  Called by the EmpiricalLogitPlot macro.
 536        
 537          data=    name of the input data set.
 538          x=       name of the single CLASS covariate.
 539          y=       name of the response variable.
 540          numy=    number of levels of the response.
 541          const=   small value in case of zero cells.
 542          plot=    1=create the plot, 0=create data set only
 543          --------------------------------------------------------------------------*/
 544        %let numym1=%eval(&numy-1);
 545        %let zerosum=0;
 546        proc freq data=&data noprint;
 547           table &x*&y / sparse out=_temp2;
 548        run;
 549        proc sort data=_temp2;
 550           by &x;
 551        run;
 552        %let dsid=%sysfunc(open(_temp2));
 553        %if &dsid %then %do;
 554          %let varnum=%sysfunc(varnum(&dsid,&x));
 555          %if %sysfunc(vartype(&dsid,&varnum))=C %then %do;
 556            %let rc=%sysfunc(close(&dsid));
 557            %CtoN(&version,data=_temp2,var=&x,out=_temp2,options=format nodatanote nonewcheck)
 558          %end;
 559          %let rc=%sysfunc(close(&dsid));
 560        %end;
 561        proc transpose data=_temp2 out=_temp;
 562           by &x;
 563           var count;
 564           run;
 565        data _temp2 ;
 566           set _temp;
 567           length _group $ 32;
 568           if (_NAME_='COUNT');
 569           _group="&x";
 570           _x=&x;
 571           _const=%sysevalf(&const+0);
 572           %do i=1 %to &numym1; %let j=%eval(&i+1);
 573              _numsum=sum(of col1-col&i); _densum=sum(of col&j-col&numy);
 574              %if &const=0 %then %do;
 575                _const=0;
 576                if _numsum=0 or _densum=0 then do;
 577                  _const=0.5; call symputx('zerosum',1);
 578                end;
 579              %end;
 580              c&i=log((_numsum + _const) / (_densum + _const));
 581           %end;
 582           keep c1-c&numym1 _group _x &x;
 583           run;
 584        %if &zerosum %then %do;
 585          %if %index(&version,DEBUG)=0 %then options notes;;
 586          %put NOTE: Zero sum detected for &x.. CONST=0.5 used in affected logits.;
 587          %if %index(&version,DEBUG)=0 %then options nonotes;;
 588          %end;
 589        %if &plot %then %do;
 590           proc sgplot;
 591              %do i=1 %to &numym1;
 592              series y=c&i x=&x /
 593                     legendlabel="&lgtlabl(O.V.<=&i)" name="series&i"
 594                     lineattrs=GraphData&i(thickness=3px);
 595              %end;
 596              yaxis label=
 597                 %if &numy>2 %then "Empirical Cumulative Logits";
 598                 %else "Empirical Logit";
 599              ;
 600              xaxis label="&x";
 601              xaxis integer label="&x";
 602              keylegend %do i=1 %to &numym1; "series&i" %end;;
 603              %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
 604              %else %str(title "Empirical Logit";);
 605              title2;
 606              run;
 607        %end;
 608        %mend;
 609        
 610        %macro OneContPlot(data=,x=,y=,numy=,const=0.5,smooth=.3,plot=1,nbhd=);
 611        /*--------------------------------------------------------------------------
 612          A macro extension of SAS Usage Note 37944 for continuous covariates. Computes
 613          and/or plots the empirical logits defined using the NBHD/2 observed X values
 614          preceding and following each observation against the levels of a single
 615          continuous X variable, then smooths the result. Called by the
 616          EmpiricalLogitPlot macro.
 617        
 618          data=    name of the input data set.
 619          x=       name of the single continuous covariate.
 620          y=       name of the response variable. y=1,2,3...
 621          numy=    number of levels of the response.
 622          const=   small value in case of zero cells.
 623          nbhd=    total number of neighbors.
 624          smooth=  smoothing parameter used for loess curve fit to logits for
 625                   continuous effects. Default: 0.3.
 626          plot=    1=create the plot, 0=create data set only
 627          --------------------------------------------------------------------------*/
 628        %let zerosum=0; %let nbhderr=0;
 629        data _temp;
 630           set &data;
 631           run;
 632        proc sort data=_temp;
 633           by &x &y;
 634           run;
 635        proc sql noprint;
 636          select count(*) into :nyx from &data
 637          where &y is not missing and &x is not missing;
 638          quit;
 639        data _null_;
 640          set _nx;
 641          maxnbhd=max(ceil(sqrt(&nyx)),ceil(.01*&nyx));
 642          if &nbhd>maxnbhd then call symputx("nbhderr",maxnbhd);
 643          run;
 644        %if &nbhderr %then %do;
 645          %if %index(&version,DEBUG)=0 %then options notes;;
 646          %put NOTE: NEIGHBORS=&nbhd decreased to &nbhderr for X=&x..;
 647          %if %index(&version,DEBUG)=0 %then options nonotes;;
 648          %let nbhd=&nbhderr; %let neighbors=&nbhd;
 649          %end;
 650        %let Full=%eval(&nbhd);
 651        %let Fullp1=%eval(&nbhd+1);
 652        %let Half=%eval(&nbhd/2);
 653        %let numym1=%eval(&numy-1);
 654        data _temp2;
 655           set _temp;
 656           retain %do i=1 %to &numy; _sum&i %end; 0;
 657           _lagx=lag&Full(&x);
 658           _lagHalfx=lag&Half(&x);
 659           _lagy=lag&Fullp1(&y);
 660           %do i=1 %to &numy; _sum&i=_sum&i+(&y=&i); %end;
 661           if (_lagy^=.) then do;
 662              %do i=1 %to &numy; _sum&i=_sum&i-(_lagy=&i); %end;
 663           end;
 664           run;
 665        data _temp;
 666           set _temp2;
 667           if (_n_<&Full) then delete;
 668           run;
 669        data _temp2;
 670           set _temp;
 671           length _group $ 32;
 672           _const=%sysevalf(&const+0);
 673           _x=_lagHalfx;
 674           _group="&x";
 675           %do i=1 %to &numym1; %let j=%eval(&i+1);
 676              _numsum=sum(of _sum1-_sum&i); _densum=sum(of _sum&j-_sum&numy);
 677              %if &const=0 %then %do;
 678                _const=0;
 679                if _numsum=0 or _densum=0 then do;
 680                  _const=0.5; call symputx('zerosum',1);
 681                end;
 682              %end;
 683             d&i=log((_numsum + _const) / (_densum + _const));
 684           %end;
 685           Neighbors=&nbhd;
 686           keep d1-d&numym1 _group _x neighbors;
 687           run;
 688        %if &zerosum %then %do;
 689          %if %index(&version,DEBUG)=0 %then options notes;;
 690          %put NOTE: Zero sum detected for &x.. CONST=0.5 used in affected logits.;
 691          %if %index(&version,DEBUG)=0 %then options nonotes;;
 692          %end;
 693        %if &plot %then %do;
 694           proc sgplot;
 695              %do i=1 %to &numym1;
 696              loess y=d&i x=_x /
 697                    smooth=&smooth legendlabel="&lgtlabl(O.V.<=&i)"
 698                    lineattrs=GraphData&i(thickness=3px)
 699                    markerattrs=(color=gray) name="series&i" nomarkers
 700              ;
 701              %end;
 702              yaxis label=
 703                 %if &numy>2 %then "Empirical Cumulative Logits";
 704                 %else "Empirical Logit";
 705              ;
 706              xaxis label="&x";
 707              keylegend %do i=1 %to &numym1; "series&i" %end;;
 708              %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
 709              %else %str(title "Empirical Logit";);
 710              title2 "with &nbhd neighbors and smoothing parameter = &smooth";
 711              run;
 712        %end;
 713        %mend;
 714        
 715        
 716        OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
 726        

when I run it.


CathyVI
Pyrite | Level 9

@Reeza  I am not changing anything in the macro when I initially run it. I copied and run. No Error or warning but I got one note:

NOTE: ODS statements in the SAS Studio environment may disable some output features.

Should I be concern because am using SAS studio on demand. What am I doing wrong?

 

Reeza
Super User
No, SAS Studio should not affect anything. I don't see any attempt to execute the macro based on the log you posted though, so I think my initial response is still correct, you're not calling the macro properly. If you think you are please post the full code and then the log.
CathyVI
Pyrite | Level 9

@Reeza  This is the full code with instruction that I initially run.

/*                          INSTRUCTIONS FOR USE 

   Version 1.1 or higher of the CtoN macro is required by the EmpiricalLogitPlot 
   macro and must be defined before using the EmpiricalLogitPlot macro. Download
   it from this location: http://support.sas.com/kb/60678 and see the Downloads 
   tab at that link. The code defining the CtoN macro and the code defining the 
   macros below must all be submitted in your SAS session to make the macros
   available for use in that SAS Session. Do not alter any of the macro code
   to ensure successful macro execution. After running the macro code, check
   your SAS log to verify that no errors were generated. 
*******************************************************************************/

%macro EmpiricalLogitPlot(version, data=, y=, x=, const=0.5, neighbors=50,
       smooth=.3, contcutoff=20, options=DESCENDING PANEL) / minoperator; 
/*--------------------------------------------------------------------------
  A macro extension of SAS Usage Note 37944 for both class and continuous
  covariates. Calls the OneContPlot macro to plot the empirical logits defined 
  using the NEIGHBORS/2 observed covariate values preceding and following each 
  observation against the levels of a covariate with more than CONTCUTOFF 
  levels. Calls the OneClassPlot macro to plot the empirical logits computed 
  within each level of a covariate with fewer than CONTCUTOFF levels.
  
  version  Optional. Any text immediately following the open parenthesis and 
           followed by a comma will display the macro version.
  data=    name of the input data set. Required.
  y=       name of the response variable. Required.
  x=       space-separated list of predictor variables. Required.
  const=   small value between 0 and 1 to prevent zero counts. Default: 0.5.
  neighbors= number of neighbors around each observation used to compute 
           logits for continuous effects. Default: Average population size but
           at least 1% of the sample size with a minimum of 2.
  smooth=  smoothing parameter used for loess curve fit to logits for 
           continuous effects. Default: 0.3.
  contcutoff= if an x= variable has more than the specified number of levels
           then logits are computed within sets of neighboring observations; 
           otherwise computed within each level of the variable. Default: 20.
  options= DESCENDING (high response levels are of interest), ASCENDING (low 
           response levels are of interest), DATAORDER (use for character 
           response after sorting data so that first occurrence of each level 
           is in logically ascending or descending order as desired with the
           first levels are of interest). Specify only one of DESCENDING, 
           ASCENDING, or DATAORDER. PANEL (single panel of all predictor 
           plots), NOPANEL (separate plot for each predictor). Default:
           DESCENDING PANEL.
  --------------------------------------------------------------------------*/ 

%macro existchk(data=, var=, dmsg=e, vmsg=e);
   %global status; %let status=ok;
   %if &dmsg=e %then %let dmsg=ERROR;
   %else %if &dmsg=w %then %let dmsg=WARNING;
   %else %let dmsg=NOTE;
   %if &vmsg=e %then %let vmsg=ERROR;
   %else %if &vmsg=w %then %let vmsg=WARNING;
   %else %let vmsg=NOTE;
   %if %quote(&data) ne %then %do;
     %if %sysfunc(exist(&data)) ne 1 %then %do;
       %put &dmsg: Data set %upcase(&data) not found.;
       %let status=nodata;
     %end;
     %else %if &var ne %then %do;
       %let dsid=%sysfunc(open(&data));
       %if &dsid %then %do;
         %let i=1;
         %do %while (%scan(&var,&i) ne %str() );
            %let var&i=%scan(&var,&i);
            %if %sysfunc(varnum(&dsid,&&var&i))=0 %then %do;
              %put &vmsg: Variable %upcase(&&var&i) not found in data %upcase(&data).;
              %let status=novar;
            %end;
            %let i=%eval(&i+1);
         %end;
         %let rc=%sysfunc(close(&dsid));
       %end;
       %else %put ERROR: Could not open data set &data.;
     %end;
   %end;
   %else %do;
     %put &dmsg: Data set not specified.;
     %let status=nodata;
   %end;   
%mend;

%let elptime = %sysfunc(datetime());
%let _version=1.2;
%if &version ne %then %put NOTE: &sysmacroname macro Version &_version;
%let _elpopts = %sysfunc(getoption(notes));
%let version=%upcase(&version);
%if %index(&version,DEBUG) %then %do;
  options notes mprint
    %if %index(&version,DEBUG2) %then mlogic symbolgen;
  ;  
  ods select all;
  %put _user_;
%end;
%else %do;
  options nonotes nomprint nomlogic nosymbolgen;
  ods exclude all;
%end;

/* Check for newer version */
%if %index(&version,NOCHECK)=0 %then %do;
   %let _notfound=0; %let _newver=0;
   filename _ver url 'http://ftp.sas.com/techsup/download/stat/versions.dat' 
            termstr=crlf;
   data _null_;
     infile _ver end=_eof;
     input name:$18. ver;
     if upcase(name)="&sysmacroname" then do;
       call symput("_newver",ver); stop;
     end;
     if _eof then call symput("_notfound",1);
     run;
   options notes;
   %if &syserr ne 0 or &_notfound=1 or &_newver=0 %then
     %put NOTE: Unable to check for newer version of &sysmacroname macro.;
   %else %if %sysevalf(&_newver > &_version) %then %do;
     %put NOTE: A newer version of the &sysmacroname macro is available at;
     %put NOTE- this location: http://support.sas.com/ ;
   %end;
   %if %index(%upcase(&version),DEBUG)=0 %then options nonotes;;
%end;

/* Input checks and process options */
%if %index(&y,/) %then %do;
  %put ERROR: Events/Trials syntax is not supported in Y=.;
  %goto exit;
%end;

%existchk(data=&data, var=&y &x);
%if &status=nodata or &status=novar %then %goto exit;

%if %quote(&y)= %then %do;
  %put ERROR: Y= is required.;
  %goto exit;
%end;

%if &x= %then %do;
  %put ERROR: One or more variables must be specified in X=.;
  %goto exit;
%end;

%if %sysevalf(&neighbors ne) %then %do;
  %if %sysevalf(%sysfunc(mod(&neighbors,1)) ne 0 or &neighbors<=0) %then %do;
    %put ERROR: NEIGHBORS= must be an integer value greater than zero.;
    %goto exit;
  %end;
%end;
%else %let neighbors=50;
%let nbhd=&neighbors;

%if %sysevalf(&contcutoff ne) %then %do;
  %if %sysevalf(%sysfunc(mod(&contcutoff,1)) ne 0 or &contcutoff<=0) %then %do;
    %let contcutoff=%sysfunc(ceil(%sysfunc(abs(&contcutoff))));
    %if %index(&version,DEBUG)=0 %then options notes;;
    %put NOTE: CONTCUTOFF= value must be a positive integer.;
    %put NOTE- CONTCUTOFF= set to &contcutoff;
    %if %index(&version,DEBUG)=0 %then options nonotes;;
  %end;
%end;
%else %let contcutoff=20;

%if %quote(&const) ne %then %do;
  %if (%sysfunc(verify(%sysfunc(catx( ,&const)),'0123456789.'))>0) + 
      (%sysfunc(count(&const,.))>1) %then %do;
    %put ERROR: The CONST= value must be a positive value less than 1.;
    %goto exit;
  %end;
  %else %if &const<0 or &const>=1 %then %do;
    %put ERROR: The CONST= value must be a positive value less than 1.;
    %goto exit;
  %end;
%end;
%else %do;
  %put ERROR: CONST= is required and must be a positive value less than 1.;
  %goto exit;
%end;

%if %quote(&smooth) ne %then %do;
  %if (%sysfunc(verify(%sysfunc(catx( ,&smooth)),'0123456789.'))>0) + 
      (%sysfunc(count(&smooth,.))>1) %then %do;
    %put ERROR: The SMOOTH= value must be a positive value.;
    %goto exit;
  %end;
  %else %if %sysevalf(&smooth<=0) %then %do;
    %put ERROR: The SMOOTH= value must be greater than zero.;
    %goto exit;
  %end;
%end;
%else %do;
  %put ERROR: SMOOTH= is required and must be positive value.;
  %goto exit;
%end;

%let validopts=ASCENDING DESCENDING DATAORDER PANEL NOPANEL;
%let panel=1; %let plot=0; %let hievent=1; %let dataorder=0;
%let i=1;
%do %while (%scan(&options,&i) ne %str() );
   %let option&i=%upcase(%scan(&options,&i));
   %if &&option&i=DATAORDER %then %do; 
      %let dataorder=1; %let hievent=0; 
   %end;
   %else %if &&option&i=ASCENDING %then %let hievent=0;
   %else %if &&option&i=NOPANEL %then %do; %let panel=0; %let plot=1; %end;
   %else %do;
    %let chk=%eval(&&option&i in &validopts);
    %if not &chk %then %do;
      %put ERROR: Valid values of OPTIONS= are &validopts..;
      %goto exit;
    %end;
   %end;
   %let i=%eval(&i+1);
%end;

%if %index(&version,DEBUG)=0 %then options notes;;
%put NOTE: Logits are computed over lower Ordered Values of &y..;
%if %index(&version,DEBUG)=0 %then options nonotes;;

proc sql; 
  select count(*) into :n from &data where &y is not missing; 
  quit;
ods graphics / loessmaxobs=%sysfunc(max(5000,%eval(&n+1000)));
data _tempdata;  
   set &data;
   run;

/* Order y= variable as requested */
%if &dataorder=0 %then %do;
   proc sort data=_tempdata;
     by %if &hievent %then descending; &y;
     run;
%end;
%let chary=0; %let yname=&y;
%let dsid=%sysfunc(open(_tempdata));
%if &dsid %then %do;
  %let varnum=%sysfunc(varnum(&dsid,&y));
  %if %sysfunc(vartype(&dsid,&varnum))=C %then %do;
    %let rc=%sysfunc(close(&dsid));
    %CtoN(&version,data=_tempdata,var=&y,out=_tempdata,order=data,
          options=noreplace noformat nodatanote nonewcheck)
    data _tempdata; set _tempdata(rename=(&y=_chary)); 
      label _chary='00'x;
      run;
    %let y=&y._N; %let chary=1;
  %end;
%let rc=%sysfunc(close(&dsid));
%end;
proc freq nlevels data=_tempdata 
  %if &hievent or &dataorder %then order=data;
;
   where not missing(&y);
   table &y %if &chary %then * _chary; / out=_ylevs noprint;
   ods exclude nlevels;
   ods output nlevels=_numy;
   run;
data _null_; 
   set _numy;
   call symputx('numy',nlevels);
   run;
%if &chary=0 %then %do;
 data _null_;
   set _ylevs nobs=nlev;
   call symputx(cats('l',_n_),&y);
   run;
 data _tempdata; 
   set _tempdata;
   select (&y);
     %do i=1 %to &numy;
       when (&&l&i) &y = &i;
     %end;
     otherwise &y = .;
   end;
   run;
%end;
%if &numy=2 %then %let lgtlabl=Logit; 
%else %let lgtlabl=CLogit;

/* Variables with > 50 levels will use neighborhood method to compute logits.
   Variables with <=50 levels will have logits computed within each level.
*/
%let cont=; %let class=;
proc freq data=_tempdata nlevels;
  table &x / noprint; 
  ods exclude nlevels;
  ods output nlevels=_nx;
  run;
data _null_; 
  set _nx; 
  call symputx(cats('nlev',_n_),nnonmisslevels); 
  run;
%let i=1;
%let dsid=%sysfunc(open(_tempdata));
%if &dsid %then %do %while (%scan(&x,&i) ne %str() );
  %let varnum=%sysfunc(varnum(&dsid,%scan(%upcase(&x),&i)));
  %if %sysfunc(vartype(&dsid,&varnum))=N and &&nlev&i>20 %then 
    %let cont=&cont %scan(&x,&i);
    %else %let class=&class %scan(&x,&i);
  %let i=%eval(&i+1);
%end;
%let rc=%sysfunc(close(&dsid));

ods select all;
%let num=1; 
%let numc=0; 
%let numd=0; 
%let totnum=1; 
%let doClass=1; 
%let numym1=%eval(&numy-1); 
%let var=%scan(&class,&num);                                  
%if (&var=) %then %do; 
   %let doClass=0; 
   %let var=%scan(&cont,&num);                                  
   %if (&var=) %then %goto stopit;  
%end;                                
data _ylevs;
  set _ylevs;
  ov=_n_;
  run;
proc print data=_ylevs label noobs split="/";
  %if &chary=0 %then %do;
    id ov; var &y; label ov="Ordered/Value/(O.V.)"; 
  %end;
  %else %do;
    id &y; var _chary; label &y="Ordered/Value/(O.V.)" _chary="&yname";
  %end;
  title "Response Profile";
  title2 "Logits are computed over the lower Ordered Values";
  run;
title;
%do %while(&var ne);                                             
   data _tempa(keep=&y &var);                                                          
      set _tempdata; 
      run;
   %if %eval(&doClass eq 1) %then %do; 
      %OneClassPlot(data=_tempa,x=&var,y=&y,numy=&numy,const=&const,plot=&plot); 
      %let numc= %eval(&numc+1); 
      data _tempc; 
         set %if %eval(&numc ne 1) %then _tempc; _temp2; 
         run; 
   %end; 
   %else %do; 
      %OneContPlot(data=_tempa,x=&var,y=&y,numy=&numy,const=&const,plot=&plot,
                   nbhd=&nbhd); 
      %let numd= %eval(&numd+1); 
      data _tempd; 
         set %if %eval(&numd ne 1) %then _tempd; _temp2; 
         run; 
   %end; 
   %let num=%eval(&num+1); 
   %let totnum=%eval(&totnum+1);; 
   %if %eval(&doClass eq 1) %then %do;                                          
      %let var=%scan(&class,&num); 
      %if (&var=) %then %do; 
          %let doClass=0; 
          %let num=1; 
      %end;
   %end; 
   %if %eval(&doClass eq 0) %then %do;            
      %let var=%scan(&cont,&num); 
      %if (&var=) %then %goto stopit; 
   %end;
%end;

%stopit: ; 
%if &panel %then %do;
   %if %eval(&numc>0) %then %do;
      proc sort data=_tempc; 
         by _group _x;
         run;
   %end;
   %if %eval(&numd>0) %then %do;
      proc sort data=_tempd; 
         by _group _x;
         run;
   %end;
   %if %eval(&numc>0 and &numd>0) %then %do;
      data _tempall;
         merge _tempd _tempc;
         by _group _x;
         run;
   %end;
   %else %if %eval(&numc>0) %then %do;
      data _tempall;
         set _tempc;
         run;
   %end;
   %else %do;
      data _tempall;
         set _tempd;
         run;
   %end;
   proc sort data=_tempall;  
      by _group; 
      run;
   data _tempa(keep=_group _minx _maxx);  
      set _tempall;  
      by _group;  
      retain _minx 1e100 _maxx -1e100; 
      if first._group then do;  
         _minx=_x;  
         _maxx=_x;  
      end; 
      _minx=min(_minx,_x);  
      _maxx=max(_maxx,_x); 
      if last._group then output;  
      run;
   data _tempall;  
      merge _tempall _tempa;  
      by _group;  
      _x=(_x-_minx)/(_maxx-_minx);  
      run;
   %if       ((&totnum-1)=1)   %then %do; %let rows=1; %let cols=1; %end;    
   %else %if ((&totnum-1)=2)   %then %do; %let rows=1; %let cols=2; %end;    
   %else %if ((&totnum-1)=3)   %then %do; %let rows=1; %let cols=3; %end;    
   %else %if ((&totnum-1)=4)   %then %do; %let rows=2; %let cols=2; %end;    
   %else %if ((&totnum-1)<=6)  %then %do; %let rows=2; %let cols=3; %end;    
   %else %if ((&totnum-1)<=9)  %then %do; %let rows=3; %let cols=3; %end;    
   %else %if ((&totnum-1)<=12) %then %do; %let rows=3; %let cols=4; %end;    
   %else %do; %let cols=4; %let rows=4;  %end;    
   proc sgpanel data=_tempall;                                           
      panelby _group / novarname columns=&cols rows=&rows 
                       uniscale=all skipemptycells;      
      rowaxis label=
         %if &numy>2 %then "Empirical Cumulative Logits";
         %else "Empirical Logit";
      ; 
      colaxis display=(nolabel noticks novalues);                     
      %if (&numd>0) %then %do i=1 %to &numym1; 
      loess y=d&i x=_x / smooth=&smooth legendlabel="&lgtlabl(O.V.<=&i)" 
            name="series&i" lineattrs=GraphData&i(thickness=3px) 
            markerattrs=GraphDataDefault(color=gray) nomarkers
      ; 
      %end; 
      %if (&numc>0) %then %do i=1 %to &numym1; 
      series y=c&i x=_x / legendlabel="&lgtlabl(O.V.<=&i)" name="series&i" 
             lineattrs=GraphData&i(thickness=3px); 
      %end;
      %if &numd %then inset neighbors / position=bottom;;
      keylegend %do i=1 %to &numym1; "series&i" %end;; 
      %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
      %else %str(title "Empirical Logit";);
      %if &numd %then
      title2 "Smoothing parameter = &smooth for continuous predictors";;
      run;  
%end;

%exit:
%if %index(&version,DEBUG)=0 %then %do;
   proc datasets nolist; 
      delete _: ;
      run; quit;
%end;
%if %index(&version,DEBUG) %then %do;
  options nomprint nomlogic nosymbolgen;
  %put _user_;
%end;
options &_elpopts;
title;
%let elptime=%sysfunc(round(%sysevalf(%sysfunc(datetime()) - &elptime), 0.01));
%put NOTE: The &sysmacroname macro used &elptime seconds.;
%mend;                  

%macro OneClassPlot(data=,x=,y=,numy=,const=0.5,plot=1); 
/*-------------------------------------------------------------------------- 
  A macro version of SAS Usage Note 37944 for covariates with fewer than 
  CONTCUTOFF levels. Computes and/or plots the empirical logits of Y against 
  the levels of one X variable.  Called by the EmpiricalLogitPlot macro.

  data=    name of the input data set. 
  x=       name of the single CLASS covariate. 
  y=       name of the response variable.   
  numy=    number of levels of the response. 
  const=   small value in case of zero cells. 
  plot=    1=create the plot, 0=create data set only
  --------------------------------------------------------------------------*/ 
%let numym1=%eval(&numy-1);
%let zerosum=0;
proc freq data=&data noprint; 
   table &x*&y / sparse out=_temp2; 
run;
proc sort data=_temp2;                                                       
   by &x;  
run;
%let dsid=%sysfunc(open(_temp2));
%if &dsid %then %do;
  %let varnum=%sysfunc(varnum(&dsid,&x));
  %if %sysfunc(vartype(&dsid,&varnum))=C %then %do;
    %let rc=%sysfunc(close(&dsid));
    %CtoN(&version,data=_temp2,var=&x,out=_temp2,options=format nodatanote nonewcheck)
  %end;
  %let rc=%sysfunc(close(&dsid));
%end;
proc transpose data=_temp2 out=_temp; 
   by &x;  
   var count; 
   run;
data _temp2 ;  
   set _temp; 
   length _group $ 32;                                           
   if (_NAME_='COUNT');                                          
   _group="&x"; 
   _x=&x;         
   _const=%sysevalf(&const+0); 
   %do i=1 %to &numym1; %let j=%eval(&i+1); 
      _numsum=sum(of col1-col&i); _densum=sum(of col&j-col&numy);
      %if &const=0 %then %do;
        _const=0;
        if _numsum=0 or _densum=0 then do;
          _const=0.5; call symputx('zerosum',1);
        end;
      %end;
      c&i=log((_numsum + _const) / (_densum + _const)); 
   %end; 
   keep c1-c&numym1 _group _x &x;
   run; 
%if &zerosum %then %do;
  %if %index(&version,DEBUG)=0 %then options notes;;
  %put NOTE: Zero sum detected for &x.. CONST=0.5 used in affected logits.;
  %if %index(&version,DEBUG)=0 %then options nonotes;;
  %end;
%if &plot %then %do; 
   proc sgplot; 
      %do i=1 %to &numym1;  
      series y=c&i x=&x /
             legendlabel="&lgtlabl(O.V.<=&i)" name="series&i" 
             lineattrs=GraphData&i(thickness=3px);   
      %end; 
      yaxis label=
         %if &numy>2 %then "Empirical Cumulative Logits";
         %else "Empirical Logit";
      ; 
      xaxis label="&x";
      xaxis integer label="&x"; 
      keylegend %do i=1 %to &numym1; "series&i" %end;; 
      %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
      %else %str(title "Empirical Logit";);
      title2;
      run; 
%end; 
%mend; 

%macro OneContPlot(data=,x=,y=,numy=,const=0.5,smooth=.3,plot=1,nbhd=); 
/*--------------------------------------------------------------------------
  A macro extension of SAS Usage Note 37944 for continuous covariates. Computes
  and/or plots the empirical logits defined using the NBHD/2 observed X values 
  preceding and following each observation against the levels of a single 
  continuous X variable, then smooths the result. Called by the 
  EmpiricalLogitPlot macro.

  data=    name of the input data set. 
  x=       name of the single continuous covariate. 
  y=       name of the response variable. y=1,2,3... 
  numy=    number of levels of the response. 
  const=   small value in case of zero cells. 
  nbhd=    total number of neighbors. 
  smooth=  smoothing parameter used for loess curve fit to logits for 
           continuous effects. Default: 0.3.
  plot=    1=create the plot, 0=create data set only
  --------------------------------------------------------------------------*/ 
%let zerosum=0; %let nbhderr=0;
data _temp;  
   set &data;
   run;
proc sort data=_temp;  
   by &x &y; 
   run;
proc sql noprint; 
  select count(*) into :nyx from &data 
  where &y is not missing and &x is not missing; 
  quit;
data _null_;
  set _nx;
  maxnbhd=max(ceil(sqrt(&nyx)),ceil(.01*&nyx));
  if &nbhd>maxnbhd then call symputx("nbhderr",maxnbhd);
  run;  
%if &nbhderr %then %do;
  %if %index(&version,DEBUG)=0 %then options notes;;
  %put NOTE: NEIGHBORS=&nbhd decreased to &nbhderr for X=&x..;
  %if %index(&version,DEBUG)=0 %then options nonotes;;
  %let nbhd=&nbhderr; %let neighbors=&nbhd;
  %end;
%let Full=%eval(&nbhd); 
%let Fullp1=%eval(&nbhd+1); 
%let Half=%eval(&nbhd/2); 
%let numym1=%eval(&numy-1); 
data _temp2;  
   set _temp; 
   retain %do i=1 %to &numy; _sum&i %end; 0; 
   _lagx=lag&Full(&x);  
   _lagHalfx=lag&Half(&x);  
   _lagy=lag&Fullp1(&y); 
   %do i=1 %to &numy; _sum&i=_sum&i+(&y=&i); %end; 
   if (_lagy^=.) then do; 
      %do i=1 %to &numy; _sum&i=_sum&i-(_lagy=&i); %end; 
   end; 
   run; 
data _temp; 
   set _temp2;  
   if (_n_<&Full) then delete; 
   run; 
data _temp2;  
   set _temp; 
   length _group $ 32;
   _const=%sysevalf(&const+0); 
   _x=_lagHalfx; 
   _group="&x"; 
   %do i=1 %to &numym1; %let j=%eval(&i+1); 
      _numsum=sum(of _sum1-_sum&i); _densum=sum(of _sum&j-_sum&numy);
      %if &const=0 %then %do;
        _const=0;
        if _numsum=0 or _densum=0 then do;
          _const=0.5; call symputx('zerosum',1);
        end;
      %end;
     d&i=log((_numsum + _const) / (_densum + _const)); 
   %end; 
   Neighbors=&nbhd;
   keep d1-d&numym1 _group _x neighbors;
   run; 
%if &zerosum %then %do;
  %if %index(&version,DEBUG)=0 %then options notes;;
  %put NOTE: Zero sum detected for &x.. CONST=0.5 used in affected logits.;
  %if %index(&version,DEBUG)=0 %then options nonotes;;
  %end;
%if &plot %then %do; 
   proc sgplot; 
      %do i=1 %to &numym1;  
      loess y=d&i x=_x /
            smooth=&smooth legendlabel="&lgtlabl(O.V.<=&i)" 
            lineattrs=GraphData&i(thickness=3px) 
            markerattrs=(color=gray) name="series&i" nomarkers
      ; 
      %end; 
      yaxis label=
         %if &numy>2 %then "Empirical Cumulative Logits";
         %else "Empirical Logit";
      ;
      xaxis label="&x";
      keylegend %do i=1 %to &numym1; "series&i" %end;;    
      %if &numy>2 %then %str(title "Empirical Cumulative Logits";);
      %else %str(title "Empirical Logit";);
      title2 "with &nbhd neighbors and smoothing parameter = &smooth";
      run; 
%end; 
%mend; 

Then I filled this part with my information: %macro EmpiricalLogitPlot(version, data=, y=, x=, const=0.5, neighbors=50, smooth=.3, contcutoff=20, options=DESCENDING PANEL) / minoperator;

 

Here is my log

 
1 OPTIONS NONOTES NOSTIMER NOSOURCE NOSYNTAXCHECK;
NOTE: ODS statements in the SAS Studio environment may disable some output features.
69
Reeza
Super User
Please show the macro call as well.
If as posted, it is incorrect.
CathyVI
Pyrite | Level 9

@Reeza Thank you, I followed your initial suggestion and it worked. I accepted it as a solution. Thanks again

CathyVI
Pyrite | Level 9

@Reeza  Do you know if the EmpiricalLogitPlot for the proportional odds assumption can be done in excel?

Reeza
Super User
The data calculation or the graphing. You could create the data for the graphs and then do it in Excel but I wouldn't attempt to do the data calculations in Excel. If you look at the SAS code, there are some checks and calculations.
CathyVI
Pyrite | Level 9

@Reeza  The graphing. I submitted the graphing to my mentor and he is requesting the I use excel because he wanted an improved labelling of the title axis, vertical and horizontal title axis. I looked at the macro for plotting the graph and its very confusing to me- am unable to manipulate the code to get the expected labels. So I wanted to know if I export my data into excel, can I plot the graph using excel?

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

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
  • 9 replies
  • 634 views
  • 2 likes
  • 2 in conversation