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.02S = 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.02D = 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.00R = 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.0000000Corr_x           [,1]       [,2]       [,3]
[1,]  1.0000000  0.9292280 -0.7139216
[2,]  0.9292280  1.0000000 -0.7231015
[3,] -0.7139216 -0.7231015  1.0000000factanal(), 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.00000A = 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.1hatPsi <- 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.008Xtilde = 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-16plot(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.000relativa 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.08106gdl = ((p-k)^2 - p - k)/2
pchisq(t, lower.tail=FALSE, df=gdl)[1] 2.821254e-08Caricare 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.00factanal(), 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  19Caricare 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.66calcolare 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.6264004for (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