# Chapter 2: Factor Analysis

### Example 2 on Factor analysis: Fitting the same model separately for each country

Consider the same six items for "effectiveness of the police" and "procedural fairness of the police" as in Example 1, and a 2-factor confirmatory factor analysis model with the same simple measurement structure as used there. Fit the model separately for the samples from each of the countries in the ESS. Does the model fit well in all of the countries? How much does estimated correlation between the factors vary across the countries?

In both Stata and R, we can implement the calculations by programming a loop over the countries, carrying out the estimation one country at a time, and collecting the estimates we need in a summary table or matrix.

// Fitting the same 2-factor CFA model for 6 items separately for
// each country, and collecting some of the results in a table.
levelsof cntry, clean local(countries)
local n_c: word count `countries'
matrix results = J(`n_c',5,.)
matrix rownames results = `countries'
matrix colnames results = Fcorr pGlob pvEFA RMSEA CFI
// Loop over the countries, and collect results:
local i = 0
foreach c of local countries {
local ++i
display "Country: " "`c'"
// 2-factor CFA model
sem (Effective -> plcpvcr plccbrg plcarcr) ///
(ProcFair -> plcrspc plcfrdc plcexdc) if cntry=="`c'", ///
var(Effective@1 ProcFair@1) method(mlmv) iter(100) ///
nolog satopts(nolog) baseopts(nolog)
matrix b=e(b)
estimates store cfa_mod
estat gof, stats(all)
local converged=e(converged)
if(`converged'==1){
matrix results[`i',1] = _b[cov(Effective,ProcFair):_cons]
matrix results[`i',2] = r(p_ms)
matrix results[`i',4] = r(rmsea)
matrix results[`i',5] = r(cfi)
}
// 2-factor EFA model, for comparison
quietly: sem (Effective -> plcpvcr plccbrg plcarcr ///
(plcrspc,init(0)) (plcfrdc,init(0))) ///
(ProcFair -> (plccbrg,init(0)) (plcarcr,init(0)) ///
plcrspc plcfrdc plcexdc) if cntry=="`c'", ///
var(Effective@1 ProcFair@1) method(mlmv) from(b) iter(100)
local converged=e(converged)
if(`converged'==1){
lrtest cfa_mod .
matrix results[`i',3] = r(p)
}
}
//
matlist results, format(%4.3f)

# Fitting the same 2-factor CFA model for 6 items separately for
# each country, and collecting some of the results in a table.
library(lavaan)
#
countries <- unique(ESS5Police\$cntry)
results <- matrix(NA,length(countries),5)
rownames(results) <- countries
colnames(results) <- c("Fcorr","pGolb","pvEFA","RMSEA","CFI")
ModelSyntax.cfa2 <- '
Effective =~ plcpvcr+plccbrg+plcarcr
ProcFair =~ plcrspc+plcfrdc+plcexdc
'
ModelSyntax.efa2 <- '
Effective =~ plcpvcr+plccbrg+plcarcr+plcrspc+plcfrdc+0*plcexdc
ProcFair =~ 0*plcpvcr+plccbrg+plcarcr+plcrspc+plcfrdc+plcexdc
'
# Loop over the countries, and collect results:
i <- 0
for(cntry in countries){
i <- i+1
cat("Country: ", cntry, "\n")
#
FittedModel.cfa2 <- sem(model = ModelSyntax.cfa2,
data = ESS5Police[ESS5Police\$cntry==cntry,],
std.lv = TRUE, meanstructure = TRUE,missing="ml")
print(summary(FittedModel.cfa2,fit.measures=T))
conv.tmp <- inspect(FittedModel.cfa2,"converged")
if(conv.tmp){
results[i,1] <- coef(FittedModel.cfa2)["Effective~~ProcFair"]
s.tmp <- fitMeasures(FittedModel.cfa2)
results[i,2] <- s.tmp["pvalue"]
results[i,4] <- s.tmp["rmsea"]
results[i,5] <- s.tmp["cfi"]
}
#
FittedModel.efa2 <- sem(model = ModelSyntax.efa2,
data = ESS5Police[ESS5Police\$cntry==cntry,],
std.lv = TRUE, meanstructure = TRUE,missing="ml")
conv.tmp <- inspect(FittedModel.efa2,"converged")
if(conv.tmp){
print(lr.tmp <- anova(FittedModel.efa2,FittedModel.cfa2))
results[i,3] <- lr.tmp\$"Pr(>Chisq)"[2]
}
}
#
print(round(results,3))

Results from this analysis are shown in Table 2.2. We observe that the fit of the model is moderate to good in all of the countries, with RMSEA values between 0.035 and 0.077, and CFI between 0.967 and 0.995. The correlation between the factors (which are all scaled in the same direction, as we can confirm by checking the signs of the factor loadings in the attached output) is positive in all countries, with values between 0.396 for the Netherlands and 0.734 for Greece. The estimated standard errors of these correlations are around 0.03, so some of the between-country differences are clearly statistically significant. Here these results on the correlations are treated mainly as a descriptive summary of the variation across the countries. For any more detailed interpretation of them it would be preferable to draw also on substantive hypotheses or explanations about where and why these correlations might vary between countries.

Table 2.2: Results for a 2-factor confirmatory factor analysis model for indicators of Effectiveness and Procedural fairness of the police, fitted separately to samples in each country in the ESS.

Country
(country code)
Factor corr. p-value:
Overall
p-value:
vs. EFA
RMSEA CFI
Belgium (BE) 0.450 <0.001 <0.001 0.059 0.977
Bulgaria (BG) 0.728 <0.001 <0.001 0.049 0.993
Switzerland (CH) 0.483 <0.001 <0.001 0.046 0.986
Cyprus (CY) 0.657 <0.001 <0.001 0.058 0.990
Czech Republic (CZ) 0.646 <0.001 <0.001 0.069 0.980
Germany (DE) 0.488 <0.001 <0.001 0.052 0.978
Denmark (DK) 0.553 <0.001 <0.001 0.051 0.980
Estonia (EE) 0.613 <0.001 <0.001 0.055 0.980
Spain (ES) 0.662 <0.001 <0.001 0.039 0.994
Finland (FI) 0.480 <0.001 <0.001 0.035 0.991
France (FR) 0.606 <0.001 <0.001 0.069 0.976
United Kingdom (GB) 0.582 <0.001 <0.001 0.054 0.986
Greece (GR) 0.734 <0.001 <0.001 0.050 0.995
Croatia (HR) 0.680 <0.001 <0.001 0.065 0.985
Hungary (HU) 0.612 <0.001 <0.001 0.039 0.992
Ireland (IE) 0.624 <0.001 <0.001 0.054 0.988
Israel (IL) 0.637 <0.001 <0.001 0.077 0.976
Lithuania (LT) 0.640 <0.001 <0.001 0.041 0.993
Croatioa (HR) 0.680 <0.001 <0.001 0.065 0.985
Netherlands (NL) 0.396 <0.001 <0.001 0.058 0.976
Norway (NO) 0.487 <0.001 <0.001 0.071 0.967
Poland (PL) 0.570 <0.001 <0.001 0.056 0.987
Portugal (HR) 0.455 <0.001 <0.001 0.064 0.982
Russia (HR) 0.690 <0.001 <0.001 0.069 0.984
Sweden (SE) 0.504 <0.001 <0.001 0.066 0.969
Slovenia (SI) 0.572 <0.001 <0.001 0.058 0.985
Slovakia (SK) 0.568 <0.001 <0.001 0.071 0.981
Ukraine (UA) 0.637 <0.001 <0.001 0.058 0.989

Go to next chapter >>