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.
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...
@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.
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...
@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.
@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 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
@Reeza Thank you, I followed your initial suggestion and it worked. I accepted it as a solution. Thanks again
@Reeza Do you know if the EmpiricalLogitPlot for the proportional odds assumption can be done in excel?
@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?
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
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.