Si consideri il modello fattoriale con \(k=1\) fattore e \(p=3\) variabili: \[\underset{p\times 1}{x} = \underset{p\times k}{\Lambda}\underset{k\times 1}{f} + \underset{p\times 1}{u}\]
Si generino \(n=20\) osservazioni indipendenti e identicamente distribuite da questo modello, salvando ciascuna osservazione \(x\) nella riga \(i\)-sima della matrice \(\underset{n\times p}{X}\). Per generare i dati, impostare il seme generatore dei numeri casuali set.seed(123)
e specificare:
n <- 20
p <- 3
Lambda <- matrix(c(0.5,0.2,-0.1), ncol=1)
Psi <- diag(c(0.0225, 0.0025, 0.008))
X <- matrix(NA,nrow=n,ncol=p)
set.seed(123)
for (i in 1:n){
f <- rnorm(1)
u <- rnorm(p, mean=0, sd=sqrt(diag(Psi)) )
X[i,] <- Lambda %*% f + u
}
La geometria del modello fattoriale può essere rappresentata graficamente come segue: i punti neri sono le osservazioni \(x\) generate come \(\Lambda f\) (punti rossi) e aggiungendo l’errore \(u\) (linee grigie). La retta rossa rappresenta il sottospazio dimensionale lungo il quale devono cadere tutti i valori di \(f\) mostrato in rosso.
Sigma = Lambda %*% t(Lambda) + Psi
round(Sigma,2)
[,1] [,2] [,3]
[1,] 0.27 0.10 -0.05
[2,] 0.10 0.04 -0.02
[3,] -0.05 -0.02 0.02
S = var(X) * ((n-1)/n)
round(S,2)
[,1] [,2] [,3]
[1,] 0.18 0.06 -0.04
[2,] 0.06 0.03 -0.02
[3,] -0.04 -0.02 0.02
D = diag(diag(Sigma)^(-1/2))
Corr_x = D %*% Sigma %*% D
round(Corr_x,2)
[,1] [,2] [,3]
[1,] 1.00 0.93 -0.71
[2,] 0.93 1.00 -0.72
[3,] -0.71 -0.72 1.00
R = cor(X)
round(R,2)
[,1] [,2] [,3]
[1,] 1.00 0.90 -0.72
[2,] 0.90 1.00 -0.73
[3,] -0.72 -0.73 1.00
# pesi fattoriali z
Lambda_z = D %*% Lambda
round(Lambda_z,2)
[,1]
[1,] 0.96
[2,] 0.97
[3,] -0.75
# varianze specifiche z
Psi_z = D %*% Psi %*% t(D)
diag(Psi_z)
[1] 0.08256881 0.05882353 0.44444444
# modello fattoriale per dati standardizzati
Lambda_z %*% t(Lambda_z) + Psi_z
[,1] [,2] [,3]
[1,] 1.0000000 0.9292280 -0.7139216
[2,] 0.9292280 1.0000000 -0.7231015
[3,] -0.7139216 -0.7231015 1.0000000
Corr_x
[,1] [,2] [,3]
[1,] 1.0000000 0.9292280 -0.7139216
[2,] 0.9292280 1.0000000 -0.7231015
[3,] -0.7139216 -0.7231015 1.0000000
factanal()
, argomenti factors=1
e rotation="none"
), ed ottenereaf <- factanal(x=X, factors=1, rotation="none", scores = "regression")
af
Call:
factanal(x = X, factors = 1, scores = "regression", rotation = "none")
Uniquenesses:
[1] 0.122 0.082 0.415
Loadings:
Factor1
[1,] 0.937
[2,] 0.958
[3,] -0.765
Factor1
SS loadings 2.381
Proportion Var 0.794
The degrees of freedom for the model is 0 and the fit was 0
# stima dei pesi fattoriali
hatLambda_z <- af$loadings[,]
round(hatLambda_z,3)
[1] 0.937 0.958 -0.765
# veri valori
round(Lambda_z,3)
[,1]
[1,] 0.958
[2,] 0.970
[3,] -0.745
# stima delle comunalità
hatH2 <- apply(af$loadings^2,1,sum)
round(hatH2,3)
[1] 0.878 0.918 0.585
# veri valori
H2 <- apply(Lambda_z^2,1,sum)
round(H2,3)
[1] 0.917 0.941 0.556
# stima delle varianze specifiche
hatPsi_z <- diag(af$uniquenesses)
round(diag(hatPsi_z),3)
[1] 0.122 0.082 0.415
# veri valori
round(diag(Psi_z),3)
[1] 0.083 0.059 0.444
# differenza vera correlazione e stima
round(Corr_x - ( hatLambda_z%*%t(hatLambda_z) + hatPsi_z ),5)
[,1] [,2] [,3]
[1,] 0.00000 0.03147 0.00268
[2,] 0.03147 0.00000 0.00938
[3,] 0.00268 0.00938 0.00000
A = diag(diag(Sigma))
hatLambda = A^(1/2) %*% hatLambda_z
round(hatLambda, 4)
[,1]
[1,] 0.4892
[2,] 0.1975
[3,] -0.1026
# vero valore
Lambda
[,1]
[1,] 0.5
[2,] 0.2
[3,] -0.1
hatPsi <- A^(1/2) %*% hatPsi_z %*% A^(1/2)
round(hatPsi, 4)
[,1] [,2] [,3]
[1,] 0.0332 0.0000 0.0000
[2,] 0.0000 0.0035 0.0000
[3,] 0.0000 0.0000 0.0075
# vero valore
Psi
[,1] [,2] [,3]
[1,] 0.0225 0.0000 0.000
[2,] 0.0000 0.0025 0.000
[3,] 0.0000 0.0000 0.008
Xtilde = scale(X, center=TRUE, scale=FALSE)
hatf_thompson = apply(Xtilde,1, function(x) t(hatLambda) %*% solve(S) %*% x)
plot(hatf_thompson, f)
abline(a=0,b=1)
hatf_bartlett = apply(Xtilde,1, function(x) solve(t(hatLambda) %*% solve(hatPsi) %*% hatLambda) %*% t(hatLambda) %*% solve(hatPsi)%*% x)
# uguale a
hatf = af$scores
sum(hatf_bartlett- hatf)
[1] -6.106227e-16
plot(hatf_bartlett, f)
abline(a=0,b=1, "dashed")
Si consideri la seguente matrice di correlazione
rm(list=ls())
R = matrix(c(
1.000, 0.439, 0.410, 0.288, 0.329, 0.248,
0.439, 1.000, 0.351, 0.354, 0.320, 0.329,
0.410, 0.351, 1.000, 0.164, 0.190, 0.181,
0.288, 0.354, 0.164, 1.000, 0.595, 0.470,
0.329, 0.320, 0.190, 0.595, 1.000, 0.464,
0.248, 0.329, 0.181, 0.470, 0.464, 1.000
), byrow=T, ncol=6)
colnames(R) = c("Gaelic", "English", "History", "Arithmetic", "Algebra", "Geometry")
R
Gaelic English History Arithmetic Algebra Geometry
[1,] 1.000 0.439 0.410 0.288 0.329 0.248
[2,] 0.439 1.000 0.351 0.354 0.320 0.329
[3,] 0.410 0.351 1.000 0.164 0.190 0.181
[4,] 0.288 0.354 0.164 1.000 0.595 0.470
[5,] 0.329 0.320 0.190 0.595 1.000 0.464
[6,] 0.248 0.329 0.181 0.470 0.464 1.000
relativa ai voti di \(n=220\) studenti maschi nelle materie Gaelic, English, History, Arithmetic, Algebra e Geometry (\(p=6\)). Interpretare la matrice di correlazione.
library(corrplot)
corrplot(R, diag=FALSE, type = 'upper')
I voti tra le materie sono correlati positivamente, ovvero gli studenti che vanno bene in una specifica materia vanno bene anche nelle altre. Le correlazioni più forti si trovano nel gruppo delle materie matematiche, e in misura leggermente inferiore, nel gruppo delle materie umanistiche, mentre c’è meno correlazione tra i due gruppi di materie.
factanal()
, argomenti factors=2
e rotation="none"
), ottenendo la stima della matrice dei pesi fattoriali, interpretando i due fattori ottenuti;n = 220
# modello fattoriale con 2 fattori senza rotazione
af <- factanal(covmat=R, factors=2, rotation="none", n.obs=n)
af
Call:
factanal(factors = 2, covmat = R, n.obs = n, rotation = "none")
Uniquenesses:
Gaelic English History Arithmetic Algebra Geometry
0.510 0.594 0.644 0.377 0.431 0.628
Loadings:
Factor1 Factor2
[1,] 0.553 0.429
[2,] 0.568 0.288
[3,] 0.392 0.450
[4,] 0.740 -0.273
[5,] 0.724 -0.211
[6,] 0.595 -0.132
Factor1 Factor2
SS loadings 2.209 0.606
Proportion Var 0.368 0.101
Cumulative Var 0.368 0.469
Test of the hypothesis that 2 factors are sufficient.
The chi square statistic is 2.33 on 4 degrees of freedom.
The p-value is 0.674
# stima dei pesi fattoriali
Lambda <- af$loadings[,]
round(Lambda,3)
Factor1 Factor2
[1,] 0.553 0.429
[2,] 0.568 0.288
[3,] 0.392 0.450
[4,] 0.740 -0.273
[5,] 0.724 -0.211
[6,] 0.595 -0.132
# primo fattore "andare bene a scuola"
# secondo fattore "math vs non-math"
varimax
della matrice dei pesi fattoriali (argomento rotation="varimax"
). Confrontare le stime delle varianze specifiche e della matrice dei pesi fattoriali con la soluzione senza rotazione.# rotazione varimax
af2 <- factanal(covmat = R, factors=2, rotation="varimax", n.obs=n)
af2
Call:
factanal(factors = 2, covmat = R, n.obs = n, rotation = "varimax")
Uniquenesses:
Gaelic English History Arithmetic Algebra Geometry
0.510 0.594 0.644 0.377 0.431 0.628
Loadings:
Factor1 Factor2
[1,] 0.235 0.659
[2,] 0.323 0.549
[3,] 0.590
[4,] 0.771 0.170
[5,] 0.724 0.213
[6,] 0.572 0.210
Factor1 Factor2
SS loadings 1.612 1.203
Proportion Var 0.269 0.201
Cumulative Var 0.269 0.469
Test of the hypothesis that 2 factors are sufficient.
The chi square statistic is 2.33 on 4 degrees of freedom.
The p-value is 0.674
# matrice di rotazione
af2$rotmat
[,1] [,2]
[1,] 0.8420397 0.5394156
[2,] -0.5394156 0.8420397
# la matrice dei pesi fattoriali cambia
af2$loadings
Loadings:
Factor1 Factor2
[1,] 0.235 0.659
[2,] 0.323 0.549
[3,] 0.590
[4,] 0.771 0.170
[5,] 0.724 0.213
[6,] 0.572 0.210
Factor1 Factor2
SS loadings 1.612 1.203
Proportion Var 0.269 0.201
Cumulative Var 0.269 0.469
# primo fattore "math"
# secondo fattore "non-math"
# rappresentazione grafica della rotazione
plot(af$loadings,xlim=c(-1,1), ylim=c(-1,1), pch="", asp=1)
text(af$loadings, colnames(R))
abline(h=0)
abline(v=0)
af2 <- varimax(af$loadings,normalize=FALSE)
abline(0, af2$rotmat[2,1]/af2$rotmat[1,1], lty=2)
abline(0, af2$rotmat[2,2]/af2$rotmat[1,2], lty=2)
factanal(covmat=R, factors=1, n.obs = n)$PVAL
objective
4.528823e-08
k=1
p=6
af = factanal(covmat=R, factors=k, n.obs = n)
hatLambda = af$loadings[,]
hatPsi = diag(af$uniqueness)
fit = hatLambda %*% t(hatLambda) + hatPsi
t = n*log(det(fit)/det(R))
t
[1] 53.08106
gdl = ((p-k)^2 - p - k)/2
pchisq(t, lower.tail=FALSE, df=gdl)
[1] 2.821254e-08
Caricare il dati scor
presenti nella libreria bootstrap
e calcolare la matrice di correlazione \(\underset{p\times p}{R}\).
library(bootstrap)
# carico i dati:
data(scor)
X <- scor
n <- nrow(X)
p <- ncol(X)
# matrice di correlazione
R <- cor(X)
round(R, 2)
mec vec alg ana sta
mec 1.00 0.55 0.55 0.41 0.39
vec 0.55 1.00 0.61 0.49 0.44
alg 0.55 0.61 1.00 0.71 0.66
ana 0.41 0.49 0.71 1.00 0.61
sta 0.39 0.44 0.66 0.61 1.00
factanal()
, stimare con il metodo della massima verosimiglianza il modello fattoriale con \(k=2\) fattori (argomento factors=2
) eseguendo la rotazione varimax
della matrice dei pesi fattoriali (argomento rotation="varimax"
).af <- factanal(X, factors=2, rotation = "varimax", scores="regression")
af$loadings
Loadings:
Factor1 Factor2
mec 0.265 0.681
vec 0.356 0.674
alg 0.740 0.514
ana 0.738 0.322
sta 0.696 0.290
Factor1 Factor2
SS loadings 1.774 1.370
Proportion Var 0.355 0.274
Cumulative Var 0.355 0.629
# primo fattore "open book"
# secondo fattore "closed book"
puntfat <- af$scores
# punteggi fattoriali con il metodo di thompson
plot(puntfat,pch="")
text(puntfat, labels=c(1:88))
abline(h=0)
abline(v=0)
# studente 66
X[66,]
mec vec alg ana sta
66 59 53 37 22 19
Caricare il dati scor
presenti nella libreria bootstrap
e calcolare la matrice di correlazione \(\underset{p\times p}{R}\).
library(bootstrap)
# carico i dati:
data(scor)
X <- scor
n <- nrow(X)
p <- ncol(X)
# matrice di correlazione
R <- cor(X)
round(R, 2)
mec vec alg ana sta
mec 1.00 0.55 0.55 0.41 0.39
vec 0.55 1.00 0.61 0.49 0.44
alg 0.55 0.61 1.00 0.71 0.66
ana 0.41 0.49 0.71 1.00 0.61
sta 0.39 0.44 0.66 0.61 1.00
# sostituisco 1 sulla diagonale di R con 0
R0 <- R - diag(rep(1,p))
# calcolo la stima iniziale della comunalità
h2 <- apply(abs(R0), 2, max)
h2
mec vec alg ana sta
0.5534052 0.6096447 0.7108059 0.7108059 0.6647357
# calcolo la stima di Psi
Psi = diag(1-h2)
Psi
[,1] [,2] [,3] [,4] [,5]
[1,] 0.4465948 0.0000000 0.0000000 0.0000000 0.0000000
[2,] 0.0000000 0.3903553 0.0000000 0.0000000 0.0000000
[3,] 0.0000000 0.0000000 0.2891941 0.0000000 0.0000000
[4,] 0.0000000 0.0000000 0.0000000 0.2891941 0.0000000
[5,] 0.0000000 0.0000000 0.0000000 0.0000000 0.3352643
# calcolo la matrice di correlazione ridotta R*
Rstar <- R - Psi
round(Rstar,2)
mec vec alg ana sta
mec 0.55 0.55 0.55 0.41 0.39
vec 0.55 0.61 0.61 0.49 0.44
alg 0.55 0.61 0.71 0.71 0.66
ana 0.41 0.49 0.71 0.71 0.61
sta 0.39 0.44 0.66 0.61 0.66
calcolare la stima della matrice dei pesi fattoriali \[\hat{\Lambda} = V_k L^{1/2}_k\] dopo aver ottenuto la decomposizione spettrale di \(R^* = V L V'\) e dove \(\underset{p \times k}{V_k}\) contiene le prime \(k\) colonne di \(V\) e \(\underset{k \times k}{L_k} = diag(l_1,\ldots,l_k)\).
aggiornare la stima delle comunalità \[\hat{h}^2_i = \sum_{j=1}^{k} \hat{\lambda}^2_{ij}\] dove \(\hat{\lambda}_{ij}\) è l’elemento di posizione \((i,j)\) della matrice \(\hat{\Lambda}\) ottenuta al passo precedente
aggiornare la stima della matrice di correlazione ridotta \[R^*= R - \hat{\Psi}\] dove \(\hat{\Psi} = diag(\hat{\psi}_1,\ldots,\hat{\psi}_p)\) con \(\hat{\psi}_i = 1 - \hat{h}^2_i\) dove \(\hat{h}^2_i\) è la stima ottenuta al passo precedente
# decomposizione spettrale di R*
eigen <- eigen(Rstar)
# k=2
k = 2
# stima di Lambda
Lambda <- eigen$vectors[,1:k] %*% diag(eigen$values[1:k]^{1/2})
Lambda
[,1] [,2]
[1,] -0.6459890 0.35354561
[2,] -0.7125528 0.30300833
[3,] -0.8639382 -0.05134392
[4,] -0.7864129 -0.24856797
[5,] -0.7419269 -0.27558100
# nuova stima comunalità
h2.new = apply(Lambda^2, 1, sum)
h2.new
[1] 0.5422963 0.5995455 0.7490254 0.6802313 0.6264004
# nuova stima di Psi
Psi.new <- diag(1-h2.new)
Psi.new
[,1] [,2] [,3] [,4] [,5]
[1,] 0.4577037 0.0000000 0.0000000 0.0000000 0.0000000
[2,] 0.0000000 0.4004545 0.0000000 0.0000000 0.0000000
[3,] 0.0000000 0.0000000 0.2509746 0.0000000 0.0000000
[4,] 0.0000000 0.0000000 0.0000000 0.3197687 0.0000000
[5,] 0.0000000 0.0000000 0.0000000 0.0000000 0.3735996
# nuova stima di R*
Rstar.new = R - Psi.new
Rstar.new
mec vec alg ana sta
mec 0.5422963 0.5534052 0.5467511 0.4093920 0.3890993
vec 0.5534052 0.5995455 0.6096447 0.4850813 0.4364487
alg 0.5467511 0.6096447 0.7490254 0.7108059 0.6647357
ana 0.4093920 0.4850813 0.7108059 0.6802313 0.6071743
sta 0.3890993 0.4364487 0.6647357 0.6071743 0.6264004
for (i in 1:100){
h2 <- apply(Lambda^2, 1, sum)
Rstar <- R0 + diag(h2)
eigen <- eigen(Rstar)
Lambda <- eigen$vectors[,1:k] %*% diag(eigen$values[1:k]^{1/2})
}
# stima finale per Lambda
Lambda
[,1] [,2]
[1,] -0.6427483 0.34238878
[2,] -0.7081925 0.28687387
[3,] -0.8966056 -0.08718706
[4,] -0.7710248 -0.23504626
[5,] -0.7179803 -0.22818566
# stima finale per le comunalità
h2 <- apply(Lambda^2, 1, sum)
h2
[1] 0.5303554 0.5838332 0.8115032 0.6497260 0.5675644
# stima finale per Psi
Psi = diag(1-h2)
# differenza
fit = Lambda%*%t(Lambda) + Psi
round( R - fit, 4)
mec vec alg ana sta
mec 0.0000 0.0000 0.0003 -0.0057 0.0057
vec 0.0000 0.0000 -0.0003 0.0065 -0.0066
alg 0.0003 -0.0003 0.0000 -0.0010 0.0011
ana -0.0057 0.0065 -0.0010 0.0000 0.0000
sta 0.0057 -0.0066 0.0011 0.0000 0.0000