  *---------------------------------------------------------------*             
  * A SAS MACRO TO TEST THE SIGNIFICANCE OF DIFFERENCES           *             
  * BETWEEN PARAMETER ESTIMATES IN PROC CATMOD                    *             
  *                                                               *             
  * This macro, called DIFFPARM, will compute significance tests  *             
  * for the DIFFerence in PARMater estimates that are obtained    *             
  * for multinomial logistic regression models using PROC CATMOD. *             
  *                                                               *             
  * A description of the DIFFPARM macro is published in           *             
  * OAC's Perspective, volume 18(2), 1994, pp. XX-XX and in       *             
  * proceedings for the Western Users of SAS Software Conference, *             
  * Santa Monica, CA, October 1993.                               *             
  *                                                               *             
  * The DIFFPARM macro was written in version 6.08 of the         *             
  * SAS System running under MVS on an IBM ES/9000 model 900.     *             
  * If the macro is ported to another version of SAS or           *             
  * to another operating system you should thoroughly test        *             
  * the accuracy of the results.                                  *             
  *                                                               *             
  * Created 9-9-93, redesigned 10-10-93                           *             
  * Linda R. Ferguson                                             *             
  * Mel Widawski                                                  *             
  * Office of Academic Computing                                  *             
  * 5628 Math Science Addition                                    *             
  * University of California, Los Angeles                         *             
  * Los Angeles  CA  90024-1557                                   *             
  * (310) 825-7452                                                *             
  * consult@mvs.oac.ucla.edu                                      *             
  *---------------------------------------------------------------*;            
                                                                                
options pagesize=56;                                                            
                                                                                
%macro diffparm(numcat,numparm,dsn);                                            
                                                                                
  options nocenter;                                                             
  options linesize=132;                                                         
                                                                                
  /*-------------------------------------------------------------*/             
  /* The following determines the number of cases in the dataset */             
  /* output by catmod and tests whether the parameters NUMCAT    */             
  /* and NUMPARM fit the dataset.                                */             
  /*                                                             */             
  /* Added:     Mel Widawski          10-10-93                   */             
  /*-------------------------------------------------------------*/             
                                                                                
  %global num ;                                                                 
  %if &dsn =   %then                                                            
                    %do; %let dsn=LOGITEST ;                                    
                         %PUT NOTE: No DSN specified using &DSN ;               
                    %end;                                                       
     DATA _NULL_;                                                               
       IF 0 THEN SET &DSN POINT=_N_ NOBS=COUNT;                                 
       CALL SYMPUT('NUM',LEFT(PUT(COUNT,8.)));                                  
       STOP;                                                                    
     RUN;                                                                       
                                                                                
  %let numdf  = %eval(&numcat-1);                                               
  %let t      = %eval(&numdf*&numparm) ;                                        
  %let eval   = %eval( &t  + 1) ;                                               
                                                                                
%IF &eval   ^=  &num   %then %do;   /* observations not OK */                   
       %PUT  ******************************************************;            
       %PUT  ****   ERROR:                                         ;            
       %PUT  ****   Number of lines, &num, in &dsn                 ;            
       %PUT  ****     ^=    ((Number of Categories -1 = &numdf)    ;            
       %PUT  ****       X    (Number of Parameters = &numparm)) + 1;            
       %PUT  ****                                                  ;            
       %PUT  ****   Probable error in specifying NUMCAT or NUMPARM ;            
       %PUT  ******************************************************;            
  %end;      /* end observations not OK */                                      
                                                                                
%else %do;  /*  observations OK */                                              
                                                                                
                                                                                
       *-----------------------------------------------------------*            
       *  To test for the significance of parameter                *            
       *  estimates bi and bj, a z-test can be computed            *            
       *  using the following formula for variance.                *            
       *                                                           *            
       *                  bi - bj                                  *            
       *   z= -------------------------------------                *            
       *      sqrt{var(bi) + var(bj) - 2cov(bi,bj)}                *            
       *-----------------------------------------------------------*;           
                                                                                
   data _null_;   set &dsn (DROP=_METHOD_);                                     
      file print  /*log*/  header=newpage;                                      
      retain  rowpoint 0 Bpoint 0;                                              
                                                                                
     *---------------------------------------------------------------*          
     *  Example to help understand levels and parameters.            *          
     *                                                               *          
     *  If the dependent variable has 5 levels, there will be        *          
     *  4 response functions, and the last level of the              *          
     *  dependent variable will be the baseline.                     *          
     *  If there are 6 predictor variables, there will be            *          
     *  7 parameter estimates per response function (add one         *          
     *  for the intercept).                                          *          
     *                                                               *          
     * The parameter estimates are numbered as follows:              *          
     *     B1=intercept for level1                                   *          
     *     B2=intercept for level2                                   *          
     *     B3=intercept for level3                                   *          
     *     B4=intercept for level4                                   *          
     *     B5=var1 for level1                                        *          
     *     B6=var1 for level2                                        *          
     *     B7=var1 for level3                                        *          
     *     B8=var1 for level4                                        *          
     *     B9=var2 for level1                                        *          
     *     B10=var2 for level2                                       *          
     *     etc.                                                      *          
     *                                                               *          
     * Significance tests are computed for the following differences *          
     * in parameter estimates:                                       *          
     *     B1-B2, B1-B3, B1-B4, B2-B3, B2-B4, B3-B4                  *          
     *     B5-B6, B5-B7, B5-B8, B6-B7, B6-B8, B7-B8                  *          
     *     B9-B10, B9-B11, B9-B12, B10-B11, B10-B12, B11-B12         *          
     *     etc.                                                      *          
     *---------------------------------------------------------------*;         
                                                                                
    *------------------------------------------------------------*              
    * Explanation of Macro Variables:                            *              
    * numcat  = number of outcome categories = k.                *              
    * numdf   = number of response functions = (k-1).            *              
    * numparm = number of parameter estimates per response       *              
    *           function = p.                                    *              
    * t       = total number of parameter est = t = p*(k-1).     *              
    * num     = total number of obs           = t+1 = p*(k-1)+1. *              
    *                                                            *              
    * Explanation of additional counts:                          *              
    * number of comparisons per set of parameter estimates =     *              
    *   c = (k-1)!/(k-3)!2!.                                     *              
    * total number of comparisons for model = p*c.               *              
    *                                                            *              
    * Explanation of Arrays:                                     *              
    * The following arrays have dimension "t" (total number      *              
    * of parameter estimates for the entire model):              *              
    *    ARRAY B  (input array of parameters and covar matrix)   *              
    *    ARRAY P  (array to retain  parameters)                  *              
    *                                                            *              
    * The following array has dimensions "(k-1),(k-1)"           *              
    * (size of covariance matrix of response functions           *              
    *  for each model parmeter (predictor variables and          *              
    *  intercept)):                                              *              
    *    ARRAY COV                                               *              
    *------------------------------------------------------------*;             
                                                                                
     /* compute numerator as bi - bj, where j=i+1 */                            
                                                                                
   ARRAY B(&t) ; /* B1-Bt (where t = number of parameters)  */                  
   ARRAY P(&t) _TEMPORARY_ ;   /* retains parameters        */                  
   ARRAY cov(&numdf,&numdf) _TEMPORARY_ ;                                       
          /*covariance matrix used for computing comparisons*/                  
                                                                                
   if _TYPE_='PARMS' then do;                                                   
      /*  Fill the P (parm) array to retain parameters      */                  
      DO I = 1 TO &t;                                                           
         P(i) = B(i);                                                           
      end;                                                                      
                                                                                
   end;                                                                         
                                                                                
   else if _TYPE_='COV' then do;                                                
                                                                                
      rowpoint=rowpoint+1;                                                      
                                                                                
      DO I = rowpoint TO &numdf;                                                
         /* fill current covariance matrix  */                                  
         cov(rowpoint,i) = B(i+Bpoint) ;                                        
      end;                                                                      
                                                                                
      if rowpoint=&numdf then                                                   
        do;                   /*  compute and print */                          
             do i = 1 to &numdf - 1 ;   /* do i        */                       
                  do j = i+1 to &numdf ;  /* do j         */                    
                    k  = i + Bpoint ;                                           
                    kk = j + Bpoint ;                                           
                                                                                
                  /* compute test only for relevant comparisons */              
                                                                                
                  /* compute differences */                                     
                   diff     = p(k)-p(kk);                                       
                                                                                
                  /* find demoninator (standard error of difference) */         
                   sediff=SQRT(cov(i,i) + cov(j,j) - 2*cov(i,j));               
                                                                                
                  /* put it all together */                                     
                   zdiff    = diff / sediff;                                    
                                                                                
                  /* find probability level for z-score */                      
                   ztemp=abs(zdiff);                                            
                   zprob    = 2*(1 - probnorm(ztemp));                          
                                                                                
                  /* print the results   */                                     
                    put / @1 k   @5 kk                                          
                          @10 p(k)             8.4                              
                          @20 p(kk)            8.4                              
                          @30 diff             8.4                              
                          @40 cov(i,i)         8.4                              
                          @50 cov(j,j)         8.4                              
                          @60 cov(i,j)         8.4                              
                          @70 sediff           8.4                              
                          @80 zdiff            8.4                              
                          @90 zprob            8.4                              
                          ;                                                     
                                                                                
                  end;   /* do j         */                                     
             end;      /* do i        */                                        
                                                                                
             Bpoint = Bpoint + &numdf ;                                         
             rowpoint=0;                                                        
        end;        /* compute and print */                                     
   end;           /* type ='COV' */                                             
   return;                                                                      
                                                                                
                                                                                
   newpage:  put  132*'-' ;                                                     
     /*---------------------------*/                                            
     /* create heading for output */                                            
     /*---------------------------*/                                            
      put / 'Significance test for difference between'                          
            ' parameter i and parameter j'                                      
            ' (with probability level for a two-tailed test).' ;                
      put / ;                                                                   
      put "Number of categories for outcome variable is &numcat";               
      put / ;                                                                   
      put "Number of parameter estimates per response function &numparm";       
      put /    @1 'i'   @5 'j'                                                  
               @11 'beta(i)'                                                    
               @21 'beta(j)'                                                    
               @31 'diff(i,j)'                                                  
               @41 'var(i)'                                                     
               @51 'var(j)'                                                     
               @61 'cov(i,j)'                                                   
               @71 'se(i,j)'                                                    
               @81 'z(i,j)'                                                     
               @91 'prob'     ;                                                 
      put / 132*'-' ;                                                           
      numline=4;                                                                
   return;   /* end link to newpage */                                          
                                                                                
   run;                                                                         
 %end;  /*end observations OK  */                                               
%mend diffparm;                                                                 
