Juste pour récapituler (et au cas où les hyperliens OP échoueraient à l'avenir), nous examinons un ensemble hsb2
de données en tant que tel:
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
qui peut être importé ici .
Nous transformons la variable read
en variable ordonnée / ordinale:
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
Maintenant , nous sommes tous mis à courir juste un ANOVA régulier - oui, il est R, et nous avons essentiellement une variable dépendante continue, write
et une variable explicative avec plusieurs niveaux, readcat
. Dans R, nous pouvons utiliserlm(write ~ readcat, hsb2)
1. Génération de la matrice de contraste:
Il existe quatre niveaux différents pour la variable ordonnée readcat
, nous aurons donc contrastes.n−1=3
table(hsb2$readcat)
(28,40] (40,52] (52,64] (64,76]
22 93 55 30
Tout d'abord, allons-y pour l'argent, et jetons un coup d'œil à la fonction R intégrée:
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
Décortiquons maintenant ce qui s'est passé sous le capot:
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⎤⎦⎥⎥⎥⎥
Que s'est-il passé là-bas? le outer(a, b, "^")
élève les éléments de a
aux éléments de b
, de sorte que la première colonne résulte des opérations, , ( - 0,5 ) 0 , 0,5 0 et 1,5 0 ; la deuxième colonne de ( - 1,5 ) 1 , ( - 0,5 ) 1 , 0,5 1 et 1,5 1 ; le troisième de ( - 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 et 1,5 2 = 2,25 ; et le quatrième, ( - 1,5 ) 3 = - 3,375 , ( - 0,5 ) 3 = - 0,125 , 0,5 3 = 0,125 et 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
Ensuite, nous faisons une décomposition orthonormée de cette matrice et prenons la représentation compacte de Q ( ). Certains des fonctionnements internes des fonctions utilisées dans la factorisation QR dans R utilisées dans ce post sont expliqués plus en détail ici .QRc_Q = qr(X)$qr
⎡⎣⎢⎢⎢⎢−20.50.50.50−2.2360.4470.894−2.502−0.92960−4.5840−1.342⎤⎦⎥⎥⎥⎥
... dont nous enregistrons uniquement la diagonale ( z = c_Q * (row(c_Q) == col(c_Q))
). Ce qui se trouve dans la diagonale: juste les entrées "inférieures" de la partie de la décomposition Q R. Juste? eh bien, non ... Il s'avère que la diagonale d'une matrice triangulaire supérieure contient les valeurs propres de la matrice!RQR
Ensuite, nous appelons la fonction suivante:, raw = qr.qy(qr(X), z)
dont le résultat peut être répliqué "manuellement" par deux opérations: 1. Transformer la forme compacte de , c'est -à- dire en Q , une transformation qui peut être réalisée avec , et 2. Effectuer la multiplication matricielle Q z , comme dans .Qqr(X)$qr
QQ = qr.Q(qr(X))
QzQ %*% z
Crucialement, la multiplication de par les valeurs propres de R ne change pas l'orthogonalité des vecteurs de colonne constitutifs, mais étant donné que la valeur absolue des valeurs propres apparaît dans l'ordre décroissant du haut à gauche vers le bas à droite, la multiplication de Q z aura tendance à diminuer la valeurs dans les colonnes polynomiales d'ordre supérieur: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
Comparez les valeurs des derniers vecteurs de colonne (quadratique et cubique) avant et après les opérations de factorisation , et aux deux premières colonnes non affectées.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
Enfin, nous appelons la (Z <- sweep(raw, 2L, apply(raw, 2L, function(x) sqrt(sum(x^2))), "/", check.margin = FALSE))
transformation de la matrice raw
en vecteurs orthonormés :
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
Cette fonction "normalise" simplement la matrice en divisant ( "/"
) dans les colonnes chaque élément par le . Il peut donc être décomposé en deux étapes:(i), cequi donne les dénominateurs pour chaque colonne de(ii)où chaque élément d'une colonne est divisé par la valeur correspondante de(i).∑col.x2i−−−−−−−√(i) apply(raw, 2, function(x)sqrt(sum(x^2)))
2 2.236 2 1.341
(ii)(i)
À ce stade, les vecteurs de colonne forment une base orthonormée de , jusqu'à ce que nous nous débarrassions de la première colonne, qui sera l'ordonnée à l'origine, et nous avons reproduit le résultat de :R4contr.poly(4)
⎡⎣⎢⎢⎢⎢−0.6708204−0.22360680.22360680.67082040.5−0.5−0.50.5−0.22360680.6708204−0.67082040.2236068⎤⎦⎥⎥⎥⎥
Les colonnes de cette matrice sont orthonormées , comme le montrent (sum(Z[,3]^2))^(1/4) = 1
et z[,3]%*%z[,4] = 0
par exemple (incidemment, il en va de même pour les lignes). Et, chaque colonne est le résultat de l' élévation des premiers pour le 1 -st, 2 -ND et 3 alimentation -rd, respectivement - c. -à- linéaire, quadratique et cubique .scores - mean123
2. Quels contrastes (colonnes) contribuent de manière significative à expliquer les différences entre les niveaux de la variable explicative?
Nous pouvons simplement exécuter l'ANOVA et regarder le résumé ...
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
... pour voir qu'il y a un effet linéaire de readcat
on write
, de sorte que les valeurs d'origine (dans le troisième morceau de code au début de l'article) peuvent être reproduites comme:
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
... ou...
... ou bien mieux ...
Étant des contrastes orthogonaux, la somme de leurs composantes ajoute à zéro pour a 1 , ⋯ , a t constantes, et le produit scalaire de deux d'entre elles est nul. Si nous pouvions les visualiser, ils ressembleraient à ceci:∑i=1tai=0a1,⋯,at
X0,X1,⋯.Xn
Graphiquement, c'est beaucoup plus facile à comprendre. Comparez les moyennes réelles par groupes dans de grands blocs noirs carrés aux valeurs prédites, et voyez pourquoi une approximation en ligne droite avec une contribution minimale des polynômes quadratiques et cubiques (avec des courbes uniquement approximées avec du loess) est optimale:
Si, juste pour l'effet, les coefficients de l'ANOVA avaient été aussi importants pour le contraste linéaire pour les autres approximations (quadratique et cubique), le tracé absurde qui suit représenterait plus clairement les diagrammes polynomiaux de chaque "contribution":
Le code est ici .