# Konfirmatorische Faktorenanalyse # # Datenbeispiel aus Wirtz & Nachtigall (2006, S. 203 ff.) # # WARNUNG: Eine Stichprobengröße von 20 ist für eine konfirmatorische Faktoren- # analyse eigentlich absurd. Faustregel: N=55 ist das absolute Minimum, ab 150 # kann man sinnvoll arbeiten, aber es gilt auch, dass die Stichprobengröße ca. # 5 bis 10 mal so groß wie die Anzahl der zu schätzenden Parameter sein sollte. # In unserem Beispiel sind beim 1. Modell 13 Parameter zu schätzen, d.h. die # Stichprobengröße sollte 150 oder mehr betragen (da 5 bis 10 mal 13 kleiner als # 150 ist). # ============================================================================== BaseURL="http://www2.jura.uni-hamburg.de/instkrim/kriminologie/Mitarbeiter/Enzmann/Lehre/StatIIKrim/Uebungen/" # Gegebenfalls die folgende Anweisung auskommentieren und den Pfadnamen (mit ab- # schließendem Schrägstrich-Vorwärts) eintragen, z.B.: Pfad = 'd:/winword/texte/S2_ss06/StatIIKrim/Uebungen/' # ------------------------------------------------------------------------------ # Nur bei Internet-Anschluss verwenden: download.file(paste(BaseURL,'pca.r',sep=""),paste(Pfad,'pca.r',sep=""),mode='wb') download.file(paste(BaseURL,'fa.promax.r',sep=""),paste(Pfad,'fa.promax.r',sep=""),mode='wb') download.file(paste(BaseURL,'factor1.dat',sep=""),paste(Pfad,'factor1.dat',sep=""),mode='wb') # ------------------------------------------------------------------------------ # Die Dateien müssen im aktuellen Arbeitsverzeichnis vorliegen! source(paste(Pfad,'pca.r',sep="")) source(paste(Pfad,'fa.promax.r',sep="")) ErwStud = read.table(paste(Pfad,'factor1.dat',sep=""),header=T,sep='\t') # ============================================================================== # Korrelationsmatrix der Variablen: round(cor(ErwStud),3) # ------------------------------------------------------------------------------ # Hauptkomponentenanalyse (Kriterium für die Anzahl der Faktoren: Paralleltest- # analyse, Output: sortierte Ladungen): pca(ErwStud,parallel=T,sort=T) # Maximum-Likelihood Faktorenanalyse mit zwei Faktoren und sortierten Ladungen: fa.promax(ErwStud,factors=2,sort=T) # ------------------------------------------------------------------------------ # Laden des Pakets "sem" (= structural equation models) library(sem) # Erzeugen einer Korrelationsmatrix (mit anhand der EFA sortierten Variablen - # die Sortierung ist für das Folgende nicht nötig, erleichtert aber den Ver- # gleich mit den Ergebnissen der obigen EFA): R = cor(ErwStud[,c(6,4,1,3,2,5)]) R # Erzeugen einer Varianz-Kovarianz-Matrix (mit anhand der EFA sortierten Vari- # ablen): COV = var(ErwStud[,c(6,4,1,3,2,5)]) COV # ------------------------------------------------------------------------------ # Spezifikation des Modells der konfirmatorischen Faktorenanalyse in Form der # RAM (reticular action model - don't ask!) Notation (da die latenten Variablen # hier keine abhängigen Variablen darstellen, können die Varianzen der Faktoren # auf 1 fixiert und die Ladungen alle als zu schätzende freie Parameter spezifi- # zier werden. Stellt ein Faktor jedoch eine AV dar, darf die Varianz nicht # fixiert werden, weshalb dann statt dessen _eine_ der Ladungen des Faktors auf # 1 fixiert werden muss): model.cfa = specify.model() FACHV06 <- F1, LA061, NA FACHV04 <- F1, LA041, NA FACHV01 <- F1, LA011, NA SOZSI03 <- F2, LA032, NA SOZSI02 <- F2, LA022, NA SOZSI05 <- F2, LA052, NA FACHV06 <-> FACHV06, E06, NA FACHV04 <-> FACHV04, E04, NA FACHV01 <-> FACHV01, E01, NA SOZSI03 <-> SOZSI03, E03, NA SOZSI02 <-> SOZSI02, E02, NA SOZSI05 <-> SOZSI05, E05, NA F1 <-> F1, NA, 1 F2 <-> F2, NA, 1 F1 <-> F2, D12, NA obs.vars = rownames(COV) N = dim(ErwStud)[1] # ACHTUNG: Obiges N = ... liefert nur dann die korrekte Stichprobengröße, wenn # die Variablen der Korrelationsmatrix keinerlei fehlende Werte aufweisen! # Schätzung der Modellparameter unter Verwendung einer Korrelationsmatrix: sem.cfa.r = sem(model.cfa, R, N, obs.vars) summary(sem.cfa.r) # Nun das Gleiche unter Verwendung einer Kovarianzmatrix (wie normalerweise # für Strukturgleichungsmodelle gefordert): sem.cfa.r = sem(model.cfa, COV, N, obs.vars) # Die Parameter des Modells konnten nicht geschätzt werden, vermutlich machen # die negativen Ladungen hier ein Problem. Das lässt sich evt. beseitigen, indem # für die negativen Ladungen negative Startwerte (hier mit -1) spezifiziert # werden: model.cfa = specify.model() FACHV06 <- F1, LA061, -1.00 FACHV04 <- F1, LA041, NA FACHV01 <- F1, LA011, NA SOZSI03 <- F2, LA032, NA SOZSI02 <- F2, LA022, -1.00 SOZSI05 <- F2, LA052, NA FACHV06 <-> FACHV06, E06, NA FACHV04 <-> FACHV04, E04, NA FACHV01 <-> FACHV01, E01, NA SOZSI03 <-> SOZSI03, E03, NA SOZSI02 <-> SOZSI02, E02, NA SOZSI05 <-> SOZSI05, E05, NA F1 <-> F1, NA, 1 F2 <-> F2, NA, 1 F1 <-> F2, D12, NA sem.cfa = sem(model.cfa, COV, N, obs.vars) summary(sem.cfa) # Die Standardisierten Parameter: std.coef(sem.cfa) # Ob eine Freisetzung auf Null fixierter (d.h. nicht spezifizierter) Parameter # die Passung des Modells zu den Daten verbessern können bzw. wo mögliche Fehl- # spezifikationen des Modells vorliegen, kann man anhand der Modifikationsindi- # zes sehen, die man in R mit mod.incides() bekommen kann: mod.indices(sem.cfa) # Modifikationsindizes größer 5 können Hinweise auf Fehlspezifikationen des # Modells liefern. Hier scheint eine Doppelladung der Variablen FACHV01 die # Passung des Modells zu den Daten deutlich verbessern zu können. Das entspre- # chende Modell lautet: model.cfa.mod = specify.model() FACHV06 <- F1, LA061, -1.00 FACHV04 <- F1, LA041, NA FACHV01 <- F1, LA011, NA FACHV01 <- F2, LA012, NA # Hier die Ladung von FACHV01 auch auf F2 SOZSI03 <- F2, LA032, NA SOZSI02 <- F2, LA022, -1.00 SOZSI05 <- F2, LA052, NA FACHV06 <-> FACHV06, E06, NA FACHV04 <-> FACHV04, E04, NA FACHV01 <-> FACHV01, E01, NA SOZSI03 <-> SOZSI03, E03, NA SOZSI02 <-> SOZSI02, E02, NA SOZSI05 <-> SOZSI05, E05, NA F1 <-> F1, NA, 1 F2 <-> F2, NA, 1 F1 <-> F2, D12, NA sem.cfa.mod = sem(model.cfa.mod, COV, N, obs.vars) # Nun hat das Programm Probleme, die Parameter zu schätzen. Aus dem ersten # Modell können aber die unstandardisierten Parameter als Startwerte übernommen # und spezifiziert werden: model.cfa.mod = specify.model() FACHV06 <- F1, LA061, -0.98 FACHV04 <- F1, LA041, 1.11 FACHV01 <- F1, LA011, 0.90 FACHV01 <- F2, LA012, NA # Hier die Ladung von FACHV01 auch auf F2 SOZSI03 <- F2, LA032, 1.22 SOZSI02 <- F2, LA022, -0.67 SOZSI05 <- F2, LA052, 0.53 FACHV06 <-> FACHV06, E06, 0.13 FACHV04 <-> FACHV04, E04, 0.53 FACHV01 <-> FACHV01, E01, 1.12 SOZSI03 <-> SOZSI03, E03, 0.13 SOZSI02 <-> SOZSI02, E02, 0.42 SOZSI05 <-> SOZSI05, E05, 0.87 F1 <-> F1, NA, 1 F2 <-> F2, NA, 1 F1 <-> F2, D12, 0.18 sem.cfa.mod = sem(model.cfa.mod, COV, N, obs.vars) summary(sem.cfa.mod) std.coef(sem.cfa.mod) mod.indices(sem.cfa.mod) # Dieses Modell passt deutlich besser zu den Daten. Aber Vorsicht: Nachträgliche # Modellanpassungen sollten nur vorgenommen werden, wenn unbedingt nötig oder # wenn sie auch theoretisch gut gerechtfertigt werden können. Die konfirmatori- # sche Analyse geht damit in eine exploratorische über und es besteht dabei # immer die Gefahr, das Modell an spezifische Besonderheiten der Stichprobe an- # zupassen (was vermieden werden sollte)!