Solo per ricapitolare (e nel caso in cui i collegamenti ipertestuali OP falliscano in futuro), stiamo esaminando un set hsb2
di dati in quanto tale:
id female race ses schtyp prog read write math science socst
1 70 0 4 1 1 1 57 52 41 47 57
2 121 1 4 2 1 3 68 59 53 63 61
...
199 118 1 4 2 1 1 55 62 58 58 61
200 137 1 4 3 1 2 63 65 65 53 61
che può essere importato qui .
Trasformiamo la variabile read
in variabile ordinata / ordinata:
hsb2$readcat<-cut(hsb2$read, 4, ordered = TRUE)
(means = tapply(hsb2$write, hsb2$readcat, mean))
(28,40] (40,52] (52,64] (64,76]
42.77273 49.97849 56.56364 61.83333
Ora siamo tutti insieme a basta eseguire un'ANOVA regolare - sì, è R, e abbiamo praticamente avere una variabile dipendente continua, write
e una variabile esplicativa con più livelli, readcat
. In R possiamo usarelm(write ~ readcat, hsb2)
1. Generazione della matrice di contrasto:
Esistono quattro livelli diversi per la variabile ordinata readcat
, quindi avremo contrasti.n−1=3
table(hsb2$readcat)
(28,40] (40,52] (52,64] (64,76]
22 93 55 30
Innanzitutto, andiamo per i soldi e diamo un'occhiata alla funzione R integrata:
contr.poly(4)
.L .Q .C
[1,] -0.6708204 0.5 -0.2236068
[2,] -0.2236068 -0.5 0.6708204
[3,] 0.2236068 -0.5 -0.6708204
[4,] 0.6708204 0.5 0.2236068
Ora analizziamo cosa è successo sotto il cofano:
scores = 1:4 # 1 2 3 4 These are the four levels of the explanatory variable.
y = scores - mean(scores) # scores - 2.5
y=[−1.5,−0.5,0.5,1.5]
seq_len(n) - 1=[0,1,2,3]
n = 4; X <- outer(y, seq_len(n) - 1, "^") # n = 4 in this case
⎡⎣⎢⎢⎢⎢1111−1.5−0.50.51.52.250.250.252.25−3.375−0.1250.1253.375⎤⎦⎥⎥⎥⎥
Cosa è successo la? la outer(a, b, "^")
solleva gli elementi a
agli elementi b
, in modo che la prima colonna risultati delle operazioni, , ( - 0,5 ) 0 , 0,5 0 e 1,5 0 ; la seconda colonna tra ( - 1,5 ) 1 , ( - 0,5 ) 1 , 0,5 1 e 1,5 1 ; il terzo da ( - 1,5 ) 2 = 2,25(−1.5)0(−0.5)00.501.50(−1.5)1(−0.5)10.511.51(−1.5)2=2.25, , 0,5 2 = 0,25 e 1,5 2 = 2,25 ; e il quarto, ( - 1,5 ) 3 = - 3,375 , ( - 0,5 ) 3 = - 0,125 , 0,5 3 = 0,125 e 1,5 3 = 3,375 .(−0.5)2=0.250.52=0.251.52=2.25(−1.5)3=−3.375(−0.5)3=−0.1250.53=0.1251.53=3.375
Quindi facciamo una decomposizione ortogonale di questa matrice e prendiamo la rappresentazione compatta di Q ( ). Alcuni dei meccanismi interni delle funzioni utilizzate nella fattorizzazione QR in R utilizzati in questo post sono ulteriormente spiegati qui .QRc_Q = qr(X)$qr
⎡⎣⎢⎢⎢⎢−20.50.50.50−2.2360.4470.894−2.502−0.92960−4.5840−1.342⎤⎦⎥⎥⎥⎥
... di cui salviamo solo la diagonale ( z = c_Q * (row(c_Q) == col(c_Q))
). Ciò che si trova in diagonale: solo le voci "dal basso" della parte del Q R decomposizione. Appena? bene, no ... Si scopre che la diagonale di una matrice triangolare superiore contiene gli autovalori della matrice!RQR
Successivamente chiamiamo la seguente funzione: raw = qr.qy(qr(X), z)
il cui risultato può essere replicato "manualmente" da due operazioni: 1. Trasformare la forma compatta di , ovvero in Q , una trasformazione che può essere realizzata con , e 2. Effettuare il moltiplicazione di matrici Q z , come in .Qqr(X)$qr
QQ = qr.Q(qr(X))
QzQ %*% z
Fondamentalmente, moltiplicando dai autovalori di R non cambia l'ortogonalità dei vettori colonna costituente, ma dato che il valore assoluto degli autovalori appare in ordine decrescente dall'alto verso sinistra a destra, la moltiplicazione di Q z tenderà a diminuire la valori nelle colonne polinomiali di ordine superiore:QRQz
Matrix of Eigenvalues of R
[,1] [,2] [,3] [,4]
[1,] -2 0.000000 0 0.000000
[2,] 0 -2.236068 0 0.000000
[3,] 0 0.000000 2 0.000000
[4,] 0 0.000000 0 -1.341641
Confronta i valori nei vettori di colonna successivi (quadratici e cubici) prima e dopo le operazioni di fattorizzazione e con le prime due colonne non interessate.QR
Before QR factorization operations (orthogonal col. vec.)
[,1] [,2] [,3] [,4]
[1,] 1 -1.5 2.25 -3.375
[2,] 1 -0.5 0.25 -0.125
[3,] 1 0.5 0.25 0.125
[4,] 1 1.5 2.25 3.375
After QR operations (equally orthogonal col. vec.)
[,1] [,2] [,3] [,4]
[1,] 1 -1.5 1 -0.295
[2,] 1 -0.5 -1 0.885
[3,] 1 0.5 -1 -0.885
[4,] 1 1.5 1 0.295
Alla fine chiamiamo (Z <- sweep(raw, 2L, apply(raw, 2L, function(x) sqrt(sum(x^2))), "/", check.margin = FALSE))
trasformare la matrice raw
in vettori ortonormali :
Orthonormal vectors (orthonormal basis of R^4)
[,1] [,2] [,3] [,4]
[1,] 0.5 -0.6708204 0.5 -0.2236068
[2,] 0.5 -0.2236068 -0.5 0.6708204
[3,] 0.5 0.2236068 -0.5 -0.6708204
[4,] 0.5 0.6708204 0.5 0.2236068
Questa funzione "normalizza" semplicemente la matrice dividendo ( "/"
) per colonna ogni elemento per . Quindi può essere scomposto in due fasi:(i), risultante, che sono i denominatori di ciascuna colonna in(ii)dove ogni elemento in una colonna è diviso per il valore corrispondente di(i).∑col.x2i−−−−−−−√(i) apply(raw, 2, function(x)sqrt(sum(x^2)))
2 2.236 2 1.341
(ii)(i)
A questo punto i vettori di colonna formano una base ortonormale di , fino a quando non ci liberiamo della prima colonna, che sarà l'intercettazione, e abbiamo riprodotto il risultato di :R4contr.poly(4)
⎡⎣⎢⎢⎢⎢−0.6708204−0.22360680.22360680.67082040.5−0.5−0.50.5−0.22360680.6708204−0.67082040.2236068⎤⎦⎥⎥⎥⎥
Le colonne di questa matrice sono ortonormali , come può essere mostrato da (sum(Z[,3]^2))^(1/4) = 1
e z[,3]%*%z[,4] = 0
, ad esempio (per inciso, lo stesso vale per le righe). E, ogni colonna è il risultato di aumentare le iniziali al 1 -esimo, 2 -nd e 3 potere -rd rispettivamente - cioè lineare, quadratica o cubica .scores - mean123
2. Quali contrasti (colonne) contribuiscono in modo significativo a spiegare le differenze tra i livelli nella variabile esplicativa?
Possiamo semplicemente eseguire ANOVA e guardare il riepilogo ...
summary(lm(write ~ readcat, hsb2))
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 52.7870 0.6339 83.268 <2e-16 ***
readcat.L 14.2587 1.4841 9.607 <2e-16 ***
readcat.Q -0.9680 1.2679 -0.764 0.446
readcat.C -0.1554 1.0062 -0.154 0.877
... per vedere che c'è un effetto lineare di readcat
on write
, in modo che i valori originali (nel terzo blocco di codice all'inizio del post) possano essere riprodotti come:
coeff = coefficients(lm(write ~ readcat, hsb2))
C = contr.poly(4)
(recovered = c(coeff %*% c(1, C[1,]),
coeff %*% c(1, C[2,]),
coeff %*% c(1, C[3,]),
coeff %*% c(1, C[4,])))
[1] 42.77273 49.97849 56.56364 61.83333
... o...
... o molto meglio ...
Essendo contrasti ortogonali la somma dei loro componenti aggiunge a zero per a 1 , ⋯ , a t costanti e il prodotto punto di uno qualsiasi dei due è zero. Se potessimo visualizzarli sembrerebbero qualcosa del genere:∑i=1tai=0a1,⋯,at
X0,X1,⋯.Xn
Graficamente, questo è molto più facile da capire. Confronta le medie effettive per gruppi in grandi blocchi quadrati neri con i valori previsti e vedi perché un'approssimazione in linea retta con un contributo minimo di polinomi quadratici e cubici (con curve solo approssimate con loess) è ottimale:
Se, solo per effetto, i coefficienti dell'ANOVA fossero stati così grandi per il contrasto lineare per le altre approssimazioni (quadratica e cubica), il diagramma senza senso che segue rappresenterebbe più chiaramente i grafici polinomiali di ciascun "contributo":
Il codice è qui .