Apenas para recapitular (e caso os hiperlinks do OP falhem no futuro), estamos analisando um conjunto de dados da seguinte hsb2
forma:
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
que pode ser importado aqui .
Transformamos a variável read
em e variável ordenada / ordinal:
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
Agora estamos todos prontos para executar uma ANOVA regular - sim, é R, e basicamente temos uma variável dependente contínua write
e uma variável explicativa com vários níveis readcat
. Em R podemos usarlm(write ~ readcat, hsb2)
1. Gerando a matriz de contraste:
Existem quatro níveis diferentes para a variável ordenada readcat
, portanto, teremos contrastes.n−1=3
table(hsb2$readcat)
(28,40] (40,52] (52,64] (64,76]
22 93 55 30
Primeiro, vamos pelo dinheiro e dê uma olhada na função R embutida:
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
Agora vamos dissecar o que aconteceu embaixo do capô:
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⎤⎦⎥⎥⎥⎥
O que aconteceu lá? o outer(a, b, "^")
eleva os elementos de a
para os elementos de b
, de modo que a primeira coluna resulta das operações, , ( - 0,5 ) 0 , 0,5 0 e 1,5 0 ; a segunda coluna de ( - 1,5 ) 1 , ( - 0,5 ) 1 , 0,5 1 e 1,5 1 ; o terceiro 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 e 1,5 2 = 2,25 ; e o 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
Em seguida, fazer um decomposição orthonormal desta matriz e tomar a representação compacta de Q ( ). Alguns dos trabalhos internos das funções usadas na fatoração QR em R usados neste post são mais explicados aqui .QRc_Q = qr(X)$qr
⎡⎣⎢⎢⎢⎢- 20,50,50,50 0- 2,2360,4470,894- 2,50 02- 0,92960 0- 4,5840 0- 1,342⎤⎦⎥⎥⎥⎥
... dos quais salvamos apenas a diagonal ( z = c_Q * (row(c_Q) == col(c_Q))
). O que se encontra na diagonal: Apenas o "fundo" entradas do parte do Q R decomposição. Somente? bem, não ... Acontece que a diagonal de uma matriz triangular superior contém os autovalores da matriz!RQ R
A seguir, chamamos a seguinte função:, raw = qr.qy(qr(X), z)
cujo resultado pode ser replicado "manualmente" por duas operações: 1. Transformando a forma compacta de , isto é , em Q , uma transformação que pode ser alcançada com , e 2. Executando o multiplicação de matrizes Q z , como em .Qqr(X)$qr
QQ = qr.Q(qr(X))
Q zQ %*% z
Fundamentalmente, a multiplicação de pelos autovalores de R não altera a ortogonalidade dos vetores da coluna constituinte, mas dado que o valor absoluto dos autovalores aparece em ordem decrescente do canto superior esquerdo para o inferior direito, a multiplicação de Q z tenderá a diminuir a valores nas colunas polinomiais de ordem superior:QRQ z
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
Comparar os valores nos vectores de coluna posteriores (quadráticos e cúbicos) antes e após as operações fatoração, e para as não afectadas duas primeiras colunas.Q R
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
Finalmente, chamamos (Z <- sweep(raw, 2L, apply(raw, 2L, function(x) sqrt(sum(x^2))), "/", check.margin = FALSE))
transformar a matriz raw
em vetores ortonormais :
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
"/"
∑col.x2Eu-------√( I ) apply(raw, 2, function(x)sqrt(sum(x^2)))
2 2.236 2 1.341
( Ii )( I )
R4contr.poly(4)
⎡⎣⎢⎢⎢⎢- 0,6708204- 0,22260680,22360680.67082040,5- 0,5- 0,50,5- 0,22260680.6708204- 0,67082040,2236068⎤⎦⎥⎥⎥⎥
(sum(Z[,3]^2))^(1/4) = 1
z[,3]%*%z[,4] = 0
pontuações - média123
2. Quais contrastes (colunas) contribuem significativamente para explicar as diferenças entre os níveis na variável explicativa?
Podemos apenas executar a ANOVA e olhar o resumo ...
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
... ver que existe um efeito linear de readcat
on write
, para que os valores originais (no terceiro pedaço de código no início do post) possam ser reproduzidos como:
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 muito melhor ...
∑i = 1tumaEu= 0uma1, ⋯ , umat
X0 0, X1, ⋯ . Xn
Graficamente, isso é muito mais fácil de entender. Compare as médias reais por grupos em grandes blocos quadrados pretos com os valores estimados e veja por que uma aproximação de linha reta com contribuição mínima de polinômios quadráticos e cúbicos (com curvas apenas aproximadas com loess) é ideal:
Se, apenas por efeito, os coeficientes da ANOVA tivessem sido tão grandes para o contraste linear para as outras aproximações (quadráticas e cúbicas), o gráfico sem sentido a seguir retrataria mais claramente os gráficos polinomiais de cada "contribuição":
O código está aqui .