Annotated Example of IML Program for Evaluating Factor Indeterminacy
and Factor Score Estimates Computed using Thurstone's Regression Approach
(annotation appears in red)

The IML program is simply appended to your SAS program that reads the data. Here is an example SAS program for a 19-item questionnaire called the Morningness-Eveningness Questionairre. Most of the 540 cases have been omitted for brevity.

Title "Morningness-Eveningness Questionnaire";
Data MEQDATA;
    Input   id  meq1 - meq19;
Cards;
   1  2  3  2  2  3  3  3  2  3  3  6  3  2  4  3  2  3  3  4
   2  5  3  2  3  3  1  2  1  3  4  6  3  1  3  4  4  5  3  6
   3  3  2  1  1  2  3  1  2  2  3  4  0  1  2  1  2  3  2  0
   4  5  3  2  3  3  1  3  2  4  4  4  2  1  4  4  1  5  3  4
   5  3  2  3  3  4  4  4  1  1  3  4  5  3  4  3  1  3  3  4
   6  2  2  1  2  2  3  2  1  3  2  4  0  1  2  3  2  3  2  0
 ....
 539  4  3  3  2  2  3  2  3  2  3  4  3  1  4  3  2  3  3  2
 540  1  1  1  2  2  2  1  2  1  1  4  2  3  2  2  1  3  2  0
;

The IML program is now appended:

/* ***************************************************************** */
/*                                                                   */
/*           REFINED ("EXACT") FACTOR SCORE EVALUATION               */
/*                  Maximize R-Square (Equation 5)                   */
/*          ----------------------------------------------           */
/*  The user makes only two changes to the program (marked in the    */
/*  code with numbers) before running:                               */
/*    1. The name of the data set to be analyzed is specified on     */
/*       the SET subcommand. The variables to be factored (only)     */
/*       are listed on the "KEEP" subcommand.                        */
/*    2. Desired options are set on the PROC FACTOR command.         */
/*                                                                   */
/*  Note: The item correlation matrix must have an inverse for       */
/*        this program to run without producing an error.            */
/*                                                                   */
/* ***************************************************************** */

options linesize=132 font='Sasfont' 8 nocenter;
data work;
  set MEQDATA;                                                        /* 1 */
  keep meq1 - meq19;

Notice that only two changes to the IML program are required.

The first change is made to the "data" statement above. Specifically, the "set" command is changed to include the name of the data set I am working on, "set MEQDATA". Also, the names of the variables that I am actually factor analyzing are included on the "keep" command. Notice that the "id" (subject number) has been excluded as it is not included in the factor analysis.

proc factor data=work m=ml n=3 r=p power=4 scree outstat=fact;     /* 2 */

The second change is made to the "proc factor" command. I am here requesting a maximum likelihood factor analysis (m=ml), the extraction of three factors (n=3), and promax rotation (r=p). I have set the power for the rotation to 4, a value recommended in the literature (power=4). Other options can be set, such as principal axis factoring (m=prinit) and varimax rotation (r=v). The "outstat=fact" option should NOT, however, be changed.

No other changes are required to the IML program. Simply run the complete SAS code and examine the end of the output for the unique information generated by the IML program.
 

proc standard data=work mean=0 std=1 replace out=zscores;
data ItmLabel;
  set fact;
  if _type_ = 'SCORE';
proc transpose data=ItmLabel out=ItmLabel;

proc iml;
reset fw=8 spaces=4;

   start corr (x, corr);
      nr=nrow(x);
      sum=x[+,];
      xpx=t(x)*x-t(sum)*sum/nr;
      s=diag(1/sqrt(vecdiag(xpx)));
      corr=s*xpx*s;
   finish corr;

use ItmLabel;
read all var{_name_} into Item;

use fact;
read all into ItemCor where(_type_ = 'CORR');
read all into Pattern where(_type_ = 'PATTERN');
Pattern=T(Pattern);
nr=nrow(Pattern);
nc=ncol(Pattern);
read all into FactCor where(_type_ = 'FCORR');
if type(FactCor) = 'U' then
  FactCor = I(nc);
FactCor=FactCor[1:nc,1:nc];
Struct=Pattern*FactCor;

use zscores;
read all into ZScore;
factor=T(DO(1,nc,1));

print , , "**** BEGIN OUTPUT FROM PROC IML **** ", , ;
FSCoef=inv(ItemCor)*Struct;
print "Factor Score Ceofficients for Items / Factors", Item FSCoef [format=6.3], , ,;

MultR=t(Struct)*inv(ItemCor)*Struct;
RSQR=vecdiag(MultR);
MultR=sqrt(vecdiag(MultR));
MinCor=j(nrow(MultR),1,0);
do i=1 to nrow(MultR);
  MinCor[i] = 2 * MultR[i]**2 - 1;
  end;
print "Indeterminacy / Determinacy Indices", "(Multiple R, R-Squared, and Minimum Correlation)"
      ,factor MultR [format=6.3] RSQR [format=6.3] MinCor [format=6.3], , ,;

C=t(FSCoef)*ItemCor*FSCoef;
C=diag(C);
C=sqrt(C);
Univ=t(Struct)*FSCoef*inv(C);
Valid=vecdiag(Univ);
print "Validity Coefficients",
      factor Valid [format=6.3] " compare to MULTR --> " MultR [format=6.3], , ,;

do i=1 to nrow(Univ);
  Univ[i,i] = .;
  FactCor[i,i] = .;
  end;
print "Univocality",
      "(Rows = Factor Scores / Columns = Factors)",
      Univ [format=6.3] " compare to FACTCOR --> " FactCor [format=6.3], , ,;

FactScor=ZScore*FSCoef;
run corr(FactScor,ScoreCor);
do i=1 to nrow(ScoreCor);
  do j=1 to ncol(ScoreCor);
    if i < j then do;
      ScoreCor[i,j] = .;
      FactCor[i,j] = .;
      end;
    FactCor[i,i] = 1;
    end;
  end;
print "Correlational Accuracy",
       ScoreCor [format=6.3] " compare to FACTCOR --> " FactCor [format=6.3], , ,;
stop;
run;