A pergunta é sobre "identificar relações [lineares" subjacentes "entre variáveis.
A maneira rápida e fácil de detectar relacionamentos é regredir qualquer outra variável (use uma constante, par) contra essas variáveis usando o seu software favorito: qualquer bom procedimento de regressão irá detectar e diagnosticar colinearidade. (Você nem se preocupará em olhar para os resultados da regressão: estamos apenas contando com um efeito colateral útil para configurar e analisar a matriz de regressão.)
Supondo que a colinearidade seja detectada, o que vem a seguir? A Análise de Componentes Principais (PCA) é exatamente o que é necessário: seus menores componentes correspondem a relações quase lineares. Essas relações podem ser lidas diretamente das "cargas", que são combinações lineares das variáveis originais. Carregamentos pequenos (ou seja, aqueles associados a pequenos autovalores) correspondem a quase colinearidades. Um valor próprio de corresponderia a uma relação linear perfeita. Valores próprios ligeiramente maiores que ainda são muito menores que os maiores corresponderiam a relações lineares aproximadas.0
(Existe uma arte e bastante literatura associada à identificação do que é um carregamento "pequeno". Para modelar uma variável dependente, sugiro incluí-lo nas variáveis independentes no PCA para identificar os componentes - independentemente de seus tamanhos - nos quais a variável dependente desempenha um papel importante. Desse ponto de vista, "pequeno" significa muito menor que qualquer componente desse tipo.)
Vejamos alguns exemplos. (Eles são usados R
para cálculos e plotagem.) Comece com uma função para executar o PCA, procure por pequenos componentes, plote-os e retorne as relações lineares entre eles.
pca <- function(x, threshold, ...) {
fit <- princomp(x)
#
# Compute the relations among "small" components.
#
if(missing(threshold)) threshold <- max(fit$sdev) / ncol(x)
i <- which(fit$sdev < threshold)
relations <- fit$loadings[, i, drop=FALSE]
relations <- round(t(t(relations) / apply(relations, 2, max)), digits=2)
#
# Plot the loadings, highlighting those for the small components.
#
matplot(x, pch=1, cex=.8, col="Gray", xlab="Observation", ylab="Value", ...)
suppressWarnings(matplot(x %*% relations, pch=19, col="#e0404080", add=TRUE))
return(t(relations))
}
B,C,D,EA
process <- function(z, beta, sd, ...) {
x <- z %*% beta; colnames(x) <- "A"
pca(cbind(x, z + rnorm(length(x), sd=sd)), ...)
}
B,…,EA=B+C+D+EA=B+(C+D)/2+Esweep
n.obs <- 80 # Number of cases
n.vars <- 4 # Number of independent variables
set.seed(17)
z <- matrix(rnorm(n.obs*(n.vars)), ncol=n.vars)
z.mean <- apply(z, 2, mean)
z <- sweep(z, 2, z.mean)
colnames(z) <- c("B","C","D","E") # Optional; modify to match `n.vars` in length
B,…,EA
A saída associada ao painel superior esquerdo foi
A B C D E
Comp.5 1 -1 -1 -1 -1
00≈A−B−C−D−E
A saída para o painel do meio superior foi
A B C D E
Comp.5 1 -0.95 -1.03 -0.98 -1.02
(A,B,C,D,E)
A B C D E
Comp.5 1 -1.33 -0.77 -0.74 -1.07
A′=B′+C′+D′+E′
1,1/2,1/2,1
Na prática, muitas vezes não é o caso de uma variável ser apontada como uma combinação óbvia das outras: todos os coeficientes podem ter tamanhos comparáveis e sinais variados. Além disso, quando há mais de uma dimensão de relações, não há uma maneira única de especificá-las: análises adicionais (como redução de linha) são necessárias para identificar uma base útil para essas relações. É assim que o mundo funciona: tudo o que você pode dizer é que essas combinações específicas produzidas pelo PCA correspondem a quase nenhuma variação nos dados. Para lidar com isso, algumas pessoas usam os componentes maiores ("principais") diretamente como variáveis independentes na regressão ou na análise subsequente, qualquer que seja a forma que possa assumir. Se você fizer isso, não esqueça primeiro de remover a variável dependente do conjunto de variáveis e refazer o PCA!
Aqui está o código para reproduzir esta figura:
par(mfrow=c(2,3))
beta <- c(1,1,1,1) # Also can be a matrix with `n.obs` rows: try it!
process(z, beta, sd=0, main="A=B+C+D+E; No error")
process(z, beta, sd=1/10, main="A=B+C+D+E; Small error")
process(z, beta, sd=1/3, threshold=2/3, main="A=B+C+D+E; Large error")
beta <- c(1,1/2,1/2,1)
process(z, beta, sd=0, main="A=B+(C+D)/2+E; No error")
process(z, beta, sd=1/10, main="A=B+(C+D)/2+E; Small error")
process(z, beta, sd=1/3, threshold=2/3, main="A=B+(C+D)/2+E; Large error")
(Eu tive que mexer com o limite nos casos de erro grande para exibir apenas um único componente: essa é a razão para fornecer esse valor como parâmetro process
.)
O usuário ttnphns direcionou nossa atenção para um tópico relacionado. Uma de suas respostas (por JM) sugere a abordagem descrita aqui.