*! version 1.4.0 Philippe VAN KERM, February 1998 *! Simple Correspondence Analysis *! Syntax: coranal [weight] [if ] [in ] [, d(#) q(#) asymmetric] capture program drop coranal program define coranal version 5.0 loc varlist "req ex min(2) max(2)" loc in "opt" loc if "opt" loc weight "aweight fweight" loc options "d(integer 0) q(real 0) Asymmetric" parse "`*'" if `d'<0 | `d'==1 {Alert1} if `q'<0 | `q'>1 { di in gr "Quality threshold mis-specified : option q(`q') rejected" loc q = 0 } parse "`varlist'", parse (" ") loc weight "[`weight'`exp']" loc var1 `1' loc var2 `2' checkstr `var1' `var2' tempname N IN JN tmp1 tmp2 RS CS RM CM P DR DC DR12 DC12 tmp3 A PrinIn U T /* */ Totin F G V OT UU VV DL1 DL2 FS GS DL1C DL2C RI CI SQC1 SQC2 FP tmp GP n overn /***************** Base Matrices Definitions *****************/ preserve cap qui tab `var1' `var2' `weight' `if' `in',matcell(`N') matrow(`IN') matcol(`JN') if _result(1)==0 { di in blue "no observations" exit } if _rc==134 { loc tmp = "`var1'" loc var1 = "`var2'" loc var2 = "`tmp'" cap qui tab `var1' `var2' `weight' `if' `in',matcell(`N') matrow(`IN') matcol(`JN') if _rc==134 {Alert2} } scalar n=_result(1) loc i = rowsof(`N') loc j = colsof(`N') if `i'<`j' { mat `N'=`N'' mat `tmp1'=`IN'' mat `IN' = `JN'' mat `JN'=`tmp1' loc tmp = `i' loc i=`j' loc j=`tmp' loc tmp = "`var1'" loc var1 = "`var2'" loc var2 = "`tmp'" } if `j' <= 1 {Alert3} mat `RS' = J(`i',1,0) mat `CS' = J(1,`j',0) loc n1 1 while `n1' <= `i' { loc n2 1 loc sum 0 while `n2' <= `j' { loc sum = `sum' + `N'[`n1',`n2'] loc n2 = `n2' + 1 } mat `RS'[`n1',1] = `sum' loc n1 = `n1' + 1 } loc n1 1 while `n1' <= `j' { loc n2 1 loc sum 0 while `n2' <= `i' { loc sum = `sum' + `N'[`n2',`n1'] loc n2 = `n2' + 1 } mat `CS'[1,`n1'] = `sum' loc n1 = `n1' + 1 } scalar overn= 1/scalar(n) mat `RM' = overn*`RS' mat `CM' = overn*`CS' mat `P' = overn*`N' mat `DR' = diag(`RM') mat `DC' = diag(`CM') /*** Computation of the matrix of standardized residuals ***/ mat `DR12'=J(`i',`i',0) loc n1 1 while `n1'<=`i' { mat `DR12'[`n1',`n1'] = (1/(sqrt(`DR'[`n1',`n1']))) loc n1 = `n1'+1 } mat `DC12'=J(`j',`j',0) loc n1 1 while `n1'<=`j' { mat `DC12'[`n1',`n1'] = (1/(sqrt(`DC'[`n1',`n1']))) loc n1 = `n1'+1 } mat `tmp1' = `RM'*`CM' mat `tmp1' = `P'-`tmp1' mat `tmp1' = `DR12'*`tmp1' mat `A' = `tmp1'*`DC12' /*** Singular Value Decomposition, Inertia and Coordinates ***/ /* Singular value decomposition */ mat svd `U' `T' `V' = `A' /* Ordering of U T and V */ mat `OT' = `T' mat `UU' = `U' mat `VV' = `V' loc n1 1 while `n1' <= `j' { loc n2 1 loc max = -1 loc posmax 0 while `n2' <= `j' { if `T'[1,`n2'] > `max' { loc max = `T'[1,`n2'] loc posmax = `n2' } loc n2 = `n2' + 1 } mat `T'[1,`posmax'] = 0 - 1 mat `OT'[1,`n1'] = `max' loc n3 1 while `n3'<=`i' { mat `UU'[`n3',`n1'] = `U'[`n3',`posmax'] loc n3 = `n3' + 1 } loc n3 1 while `n3'<=`j' { mat `VV'[`n3',`n1'] = `V'[`n3',`posmax'] loc n3 = `n3' + 1 } loc n1 = `n1' + 1 } mat `U' = `UU' mat `V' = `VV' mat `T' = diag(`OT') /* Inertia */ loc sum 0 loc K = `j' - 1 mat `PrinIn' = J(3,`K',0) loc n1 1 while `n1' <= `K' { mat `PrinIn'[1,`n1'] = (`T'[`n1',`n1'])^2 loc sum = `sum' + ((`T'[`n1',`n1'])^2) loc n1 = `n1' + 1 } scalar Totin = `sum' loc n1 1 loc sum 0 while `n1' <= `K' { mat `PrinIn'[2,`n1'] = `PrinIn'[1,`n1']/scalar(Totin) loc sum = `sum' + `PrinIn'[2,`n1'] mat `PrinIn'[3,`n1'] = `sum' loc n1 = `n1' + 1 } /* Row coordinates in F and decompositions of inertia by rows */ mat `tmp1' = `DR12'*`U' mat `tmp2' = `tmp1'*`T' mat `F' = J(`i',`K',0) mat `FS' = J(`i',`K',0) mat `DL1' = J(`i',`K',0) mat `DL1C' = J(`i',`K',0) loc n1 1 while `n1' <= `i' { loc n2 1 while `n2' <= `K' { mat `F'[`n1',`n2'] = `tmp2'[`n1',`n2'] mat `FS'[`n1',`n2'] = `F'[`n1',`n2']/`T'[`n2',`n2'] mat `DL1'[`n1',`n2'] = ((`F'[`n1',`n2'])^2)*(`RM'[`n1',1]) mat `DL1C'[`n1',`n2'] = `DL1'[`n1',`n2'] / `PrinIn'[1,`n2'] loc n2 = `n2' + 1 } loc n1 = `n1' + 1 } /* Column principal coordinates in G and decompositions of inertia by columns */ mat `tmp1' = `DC12'*`V' mat `tmp2' = `tmp1'*`T' mat `G' = J(`j',`K',0) mat `GS' = J(`j',`K',0) mat `DL2' = J(`j',`K',0) mat `DL2C' = J(`j',`K',0) loc n1 1 while `n1' <= `j' { loc n2 1 while `n2' <= `K' { mat `G'[`n1',`n2'] = `tmp2'[`n1',`n2'] mat `GS'[`n1',`n2'] = `G'[`n1',`n2']/`T'[`n2',`n2'] mat `DL2'[`n1',`n2'] = ((`G'[`n1',`n2'])^2)*(`CM'[1,`n1']) mat `DL2C'[`n1',`n2'] = `DL2'[`n1',`n2'] / `PrinIn'[1,`n2'] loc n2 = `n2' + 1 } loc n1 = `n1' + 1 } mat `RI' = J(`i',1,0) loc n1 1 while `n1' <= `i' { loc n2 1 loc sum 0 while `n2'<=`K' { loc sum = `sum' + `DL1'[`n1',`n2'] loc n2 = `n2' + 1 } mat `RI'[`n1',1] = `sum' loc n1 = `n1' + 1 } mat `CI' = J(`j',1,0) loc n1 1 while `n1' <= `j' { loc n2 1 loc sum 0 while `n2'<=`K' { loc sum = `sum' + `DL2'[`n1',`n2'] loc n2 = `n2' + 1 } mat `CI'[`n1',1] = `sum' loc n1 = `n1' + 1 } mat `SQC1'=J(`i',`K',0) loc n1 1 while `n1' <=`i' { loc n2 1 while `n2' <= `K' { mat `SQC1'[`n1',`n2'] = `DL1'[`n1',`n2'] / `RI'[`n1',1] loc n2 = `n2' + 1 } loc n1 = `n1' + 1 } mat `SQC2'=J(`j',`K',0) loc n1 1 while `n1' <=`j' { loc n2 1 while `n2' <= `K' { mat `SQC2'[`n1',`n2'] = `DL2'[`n1',`n2'] / `CI'[`n1',1] loc n2 = `n2' + 1 } loc n1 = `n1' + 1 } /************** Output Display **************/ title /*** Table display ***/ loc n1 1 loc n2 1 loc rname1 " " while `n1' <=`i' { loc nam = `IN'[`n1',1] loc rname`n2' = "`rname`n2''" + "`nam'" + " " if length("`rname`n2''")>=50 {loc n2 = `n2' + 1} loc n1 =`n1' + 1 } loc n1 1 loc n2 1 loc cname1 " " while `n1' <=`j' { loc nam = `JN'[1,`n1'] loc cname`n2' = "`cname`n2''" + "`nam'" + " " if length("`cname`n2''")>=50 {loc n2 = `n2' + 1} loc n1 =`n1' + 1 } if (`d'==0) | (`d'>`K') {loc dg = `K'} else {loc dg = `d'} loc n1 1 loc nam "Dim" while `n1' <=`dg' { loc name = "`nam'`n1'" loc xname = "`xname'" + "`name'" + " " loc n1 =`n1' + 1 } PrtTI Totin mat `tmp' = `PrinIn'[.,1..`dg'] mat `tmp' = `tmp'' mat colnames `tmp' = Inertia Share Cumul mat rownames `tmp' = `xname' di in green " Principal Inertias and Percentages :" mat list `tmp', noheader f(%10.3f) mat `F' = `F'[.,1..`dg'] mat `tmp' = `RI',`F' mat `FP' = `RM',`tmp' mat rownames `FP' = `rname1'`rname2'`rname3'`rname4'`rname5'`rname6' /* */ `rname7'`rname8'`rname9'`rname10' mat roweq `FP' = `var1' mat colnames `FP' = Mass Inertia `xname' di di in green " " "`var1'" " coordinates : " mat list `FP' , noheader f(%10.3f) mat `G' = `G'[.,1..`dg'] mat `tmp1' = `CI',`G' mat `tmp2' = `CM'' mat `GP' = `tmp2',`tmp1' mat rownames `GP' = `cname1'`cname2'`cname3'`cname4'`cname5'`cname6' /* */ `cname7'`cname8'`cname9'`cname10' mat roweq `GP' = `var2' mat colnames `GP' = Mass Inertia `xname' di di in green " " "`var2'" " coordinates : " mat list `GP' , noheader f(%10.3f) mat `DL1C' = `DL1C'[.,1..`dg'] mat rownames `DL1C' = `rname1'`rname2'`rname3'`rname4'`rname5'`rname6' /* */ `rname7'`rname8'`rname9'`rname10' mat roweq `DL1C' = `var1' mat colnames `DL1C' = `xname' di di in green " Explained inertia of axis by " "`var1'" " :" mat list `DL1C' , noheader f(%10.4f) mat `DL2C' = `DL2C'[.,1..`dg'] mat rownames `DL2C' = `cname1'`cname2'`cname3'`cname4'`cname5'`cname6' /* */ `cname7'`cname8'`cname9'`cname10' mat roweq `DL2C' = `var2' mat colnames `DL2C' = `xname' di di in green " Explained inertia of axis by " "`var2'" " :" mat list `DL2C' , noheader f(%10.4f) mat `SQC1' = `SQC1'[.,1..`dg'] mat rownames `SQC1' = `rname1'`rname2'`rname3'`rname4'`rname5'`rname6' /* */ `rname7'`rname8'`rname9'`rname10' mat roweq `SQC1' = `var1' mat colnames `SQC1' = `xname' di di in green " Contributions of principal axes to " "`var1'" " :" mat list `SQC1' , noheader f(%10.4f) mat `SQC2' = `SQC2'[.,1..`dg'] mat rownames `SQC2' = `cname1'`cname2'`cname3'`cname4'`cname5'`cname6' /* */ `cname7'`cname8'`cname9'`cname10' mat roweq `SQC2' = `var2' mat colnames `SQC2' = `xname' di di in green " Contributions of principal axes to " "`var2'" " :" mat list `SQC2' , noheader f(%10.4f) loc lb1 : value label `var1' loc lb2 : value label `var2' di if "`lb1'" ~= "" {label list `lb1'} if "`lb2'" ~= "" {label list `lb2'} /*** Graphical display ***/ if `d' ~= 0 { if `K' < `d' { di in red "Not enough principal dimensions for the representations requested"} else { mat F = `F' mat G = `G' mat colnames F = `xname' mat colnames G = `xname' svmat F ,names(matcol) svmat G ,names(matcol) if "`asymmetric'"~="" { mat FS = `FS' mat GS = `GS' mat FS = FS[.,1..`dg'] mat GS = GS[.,1..`dg'] mat colnames FS = `xname' mat colnames GS = `xname' svmat FS ,names(matcol) svmat GS ,names(matcol) } svmat `IN' ,names(Flab) mat `JN' = `JN'' svmat `JN' ,names(Glab) label values Flab1 `lb1' label values Glab1 `lb2' if `q'~=0 { loc n1 1 while `n1'<=`i' { loc n2 1 loc qual 0 while `n2' <=`dg' { loc qual = `qual' + `SQC1'[`n1',`n2'] loc n2 = `n2' + 1 } if `qual' < `q' {qui replace Flab1=. in `n1'} loc n1 =`n1' + 1 } loc n1 1 while `n1'<=`j' { loc n2 1 loc qual 0 while `n2' <=`dg' { loc qual = `qual' + `SQC2'[`n1',`n2'] loc n2 = `n2' + 1 } if `qual' < `q' {qui replace Glab1=. in `n1'} loc n1 =`n1' + 1 } } loc n1 1 while `n1' <= `d'-1 { loc n2 = `n1' + 1 while `n2'<=`d' { graph FDim`n2' FDim`n1', s([Flab1]) ti("`var1' scores") b2("Axis `n1'") /* */ l1(" ") l2("Axis `n2'") xla yla xline(0) yline(0) border loc xma = _result(4) loc xmi = _result(3) loc yma = _result(2) loc ymi = _result(1) more graph GDim`n2' GDim`n1', s([Glab1]) ti("`var2' scores") b2("Axis `n1'") /* */ l1(" ") l2("Axis `n2'") xla yla xline(0) yline(0) border if _result(4)>`xma' {loc xma = _result(4)} if _result(3)<`xmi' {loc xmi = _result(3)} if _result(2)>`yma' {loc yma = _result(2)} if _result(1)<`ymi' {loc ymi = _result(1)} more if "`asymmetric'" == "" { gph open graph GDim`n2' GDim`n1', xscale(`xmi',`xma') yscale(`ymi',`yma') s([Glab1]) /* */ ti("Joint `var1' and `var2' scores (symmetric map)") b2("Axis `n1'") /* */ l1(" ") l2("Axis `n2'") xla yla xline(0) yline(0) border graph FDim`n2' FDim`n1', xscale(`xmi',`xma') yscale(`ymi',`yma') s([Flab1]) /* */ ti(" ") b2(" ") l1(" ") l2(" ") xla yla xline(0) yline(0) border gph close more } else { as_gr GSDim`n2' GSDim`n1' Glab1 `var1' `var2' `n1' `n2' FDim`n2' FDim`n1' Flab1 more as_gr FSDim`n2' FSDim`n1' Flab1 `var1' `var2' `n1' `n2' GDim`n2' GDim`n1' Glab1 more } loc n2 = `n2' + 1 } loc n1 = `n1' + 1 } } } restore end /* Subroutines */ capture program drop Alert1 program define Alert1 di in red "Invalid number of dimensions" exit 198 end capture program drop Alert2 program define Alert2 di in red "Variables take on too many values" exit 134 end capture program drop Alert3 program define Alert3 di in red "A variable is uniquely valued" exit end capture program drop checkstr program define checkstr cap confirm string variable `1' if _rc==0 { di in red "variables in varlist must be numeric" exit 109 } cap confirm string variable `2' if _rc==0 { di in red "variables in varlist must be numeric" exit 109 } end capture program drop title program define title di in green _d(78) "-" di di in green _col(20) "SIMPLE CORRESPONDENCE ANALYSIS" di di in green _d(78) "-" di end capture program drop PrtTI program define PrtTI di di in green " Total Inertia : " in yellow %10.3f scalar(`1') di end capture program drop as_gr program define as_gr gph open graph `1' `2' , s([`3']) /* */ ti("Joint `4' and `5' scores (asymmetric map)") b2("Axis `6'") l1(" ") /* */ l2("Axis `7'") xla yla xline(0) yline(0) border loc xma = _result(4) loc xmi = _result(3) loc yma = _result(2) loc ymi = _result(1) graph `8' `9', xscale(`xmi',`xma') yscale(`ymi',`yma') s([`10']) /* */ ti(" ") b2(" ") l1(" ") l2(" ") xla yla xline(0) yline(0) border gph close end