Rotation of Canonical Variables

 /****************************************************************/
 /*          S A S   S A M P L E   L I B R A R Y                 */
 /*                                                              */
 /*    NAME: CANROTAT                                            */
 /*   TITLE: Rotation of Canonical Variables                     */
 /* PRODUCT: SAS/STAT                                            */
 /*  SYSTEM: ALL                                                 */
 /*    KEYS: multivariate analysis,                              */
 /*   PROCS: CANCORR FACTOR CORR SCORE                           */
 /*    DATA:                                                     */
 /*                                                              */
 /* SUPPORT: WSS            UPDATE:                              */
 /*     REF: Cliff & Krus (1976), "Interpretation of Canonical   */
 /*          Analysis: Rotated vs. Unrotated Solutions,"         */
 /*          Psychometrika, 41, 35-42.                           */
 /*    MISC:                                                     */
 /*                                                              */
 /****************************************************************/

title 'Simultaneous Symmetric Varimax Rotation of Canonical Variables';
title2 'Cliff & Krus (1976)';

data fit;
   input weight waist pulse chins situps jumps;
   datalines;
191  36  50   5  162   60
189  37  52   2  110   60
193  38  58  12  101  101
162  35  62  12  105   37
189  35  46  13  155   58
182  36  56   4  101   42
211  38  56   8  101   38
167  34  60   6  125   40
176  31  74  15  200   40
154  33  56  17  251  250
169  34  50  17  120   38
166  33  52  13  210  115
154  34  64  14  215  105
247  46  50   1   50   50
193  36  46   6   70   31
202  37  62  12  210  120
176  37  54   4   60   25
157  32  52  11  230   80
156  33  54  15  225   73
138  33  68   2  110   43
;

proc cancorr data=fit outstat=stat
   vprefix=PHYS vname='Physiological Measurements'
   wprefix=EXER wname='Exercises';
   var weight waist pulse;
   with chins situps jumps;
run;

*** Extract both within-set structure matrices and change the
    prefixes from PHYS and EXER to BOTH so that both can be rotated
    at same time. Change _type_ to 'PATTERN', which is what proc
    factor expects;

data strphys(keep=_type_ _name_  weight waist pulse)
     strexer(keep=_type_ _name_  chins situps jumps);
   set stat; drop which;
   if _type_='STRUCTUR' then do;
      _type_='PATTERN';
      which=substr(_name_,1,4);
      substr(_name_,1,4)='BOTH';
      if which='PHYS' then output strphys;
                      else output strexer;
   end;
run;

***  Merge the within-set structure matrices back together and add
     to original outstat= data set;

data strboth;
   merge strphys strexer;
run;

data both(type=factor);
   set stat strboth;
run;

*** Rotate both within-set structure matrices. This gives the
    rotated structures but not the coefficients;

proc factor data=both method=pattern r=v outstat=fact;
run;

*** The rotated coefficients must be computed separately. Make
    separate data sets and change the prefixes back to PHYS, EXER;

data factphys(type=factor keep=_type_ _name_  weight waist pulse)
     factexer(type=factor keep=_type_ _name_  chins situps jumps);
   set fact;
   if substr(_name_,1,4)='BOTH' then do;
      substr(_name_,1,4)='PHYS'; output factphys;
      substr(_name_,1,4)='EXER'; output factexer;
      end;
   else output;
run;

*** Compute standardized scoring coefficients for PHYS variables;

proc factor data=factphys score outstat=factphys;
   var weight waist pulse;
run;

*** Compute canonical scores for PHYS variables;

proc score data=fit score=factphys out=fitphys;
   var weight waist pulse;
run;

*** Compute correlations between canonical scores and PHYS variables
    to verify computations. Compare with rotated factor pattern;

proc corr noprob;
   var phys:;
   with weight waist pulse;
run;

*** Compute correlations among PHYS canonical variables. Should
    be identity;

proc corr noprob;
   var phys:;
run;

*** Compute standardized scoring coefficients for EXER variables;

proc factor data=factexer score outstat=factexer;
   var chins situps jumps;
run;

*** Compute canonical scores for EXER variables;

proc score data=fit score=factexer out=fitexer;
   var chins situps jumps;
run;

*** Compute correlations between canonical scores and EXER variables
    to verify computations. Compare with rotated factor pattern;

proc corr noprob;
   var exer:;
   with chins situps jumps;
run;

*** Compute correlations among EXER canonical variables. Should
    be identity;

proc corr noprob;
   var exer:;
run;

*** Compute between-set correlations for canonical variables.
    Note that this correlation matrix is symmetric but NOT diagonal;

data fitboth;
   merge fitphys fitexer;
run;

proc corr noprob;
   var phys:;
   with exer:;
run;