Quelqu'un pourrait-il trouver du code R pour tracer une ellipse à partir des valeurs propres et des vecteurs propres de la matrice suivante
Quelqu'un pourrait-il trouver du code R pour tracer une ellipse à partir des valeurs propres et des vecteurs propres de la matrice suivante
Réponses:
Vous pouvez extraire les vecteurs propres et les valeurs via eigen(A). Cependant, il est plus simple d'utiliser la décomposition de Cholesky. Notez que lorsque vous tracez des ellipses de confiance pour des données, les axes d'ellipse sont généralement mis à l'échelle pour avoir la longueur = racine carrée des valeurs propres correspondantes, et c'est ce que donne la décomposition de Cholesky.
ctr <- c(0, 0) # data centroid -> colMeans(dataMatrix)
A <- matrix(c(2.2, 0.4, 0.4, 2.8), nrow=2) # covariance matrix -> cov(dataMatrix)
RR <- chol(A) # Cholesky decomposition
angles <- seq(0, 2*pi, length.out=200) # angles for ellipse
ell <- 1 * cbind(cos(angles), sin(angles)) %*% RR # ellipse scaled with factor 1
ellCtr <- sweep(ell, 2, ctr, "+") # center ellipse to the data centroid
plot(ellCtr, type="l", lwd=2, asp=1) # plot ellipse
points(ctr[1], ctr[2], pch=4, lwd=2) # plot data centroid
library(car) # verify with car's ellipse() function
ellipse(c(0, 0), shape=A, radius=0.98, col="red", lty=2)
Edit: pour tracer également les vecteurs propres, vous devez utiliser l'approche la plus compliquée. C'est équivalent à la réponse de suncoolsu, il utilise simplement la notation matricielle pour raccourcir le code.
eigVal <- eigen(A)$values
eigVec <- eigen(A)$vectors
eigScl <- eigVec %*% diag(sqrt(eigVal)) # scale eigenvectors to length = square-root
xMat <- rbind(ctr[1] + eigScl[1, ], ctr[1] - eigScl[1, ])
yMat <- rbind(ctr[2] + eigScl[2, ], ctr[2] - eigScl[2, ])
ellBase <- cbind(sqrt(eigVal[1])*cos(angles), sqrt(eigVal[2])*sin(angles)) # normal ellipse
ellRot <- eigVec %*% t(ellBase) # rotated ellipse
plot((ellRot+ctr)[1, ], (ellRot+ctr)[2, ], asp=1, type="l", lwd=2)
matlines(xMat, yMat, lty=1, lwd=2, col="green")
points(ctr[1], ctr[2], pch=4, col="red", lwd=3)

Je pense que c'est le code R que vous voulez. J'ai emprunté le code R à ce fil sur la liste de diffusion. L'idée est essentiellement: les demi-diamètres majeurs et mineurs sont les deux valeurs propres et vous faites pivoter l'ellipse de la quantité d'angle entre le premier vecteur propre et l'axe des x
mat <- matrix(c(2.2, 0.4, 0.4, 2.8), 2, 2)
eigens <- eigen(mat)
evs <- sqrt(eigens$values)
evecs <- eigens$vectors
a <- evs[1]
b <- evs[2]
x0 <- 0
y0 <- 0
alpha <- atan(evecs[ , 1][2] / evecs[ , 1][1])
theta <- seq(0, 2 * pi, length=(1000))
x <- x0 + a * cos(theta) * cos(alpha) - b * sin(theta) * sin(alpha)
y <- y0 + a * cos(theta) * sin(alpha) + b * sin(theta) * cos(alpha)
png("graph.png")
plot(x, y, type = "l", main = expression("x = a cos " * theta * " + " * x[0] * " and y = b sin " * theta * " + " * y[0]), asp = 1)
arrows(0, 0, a * evecs[ , 1][2], a * evecs[ , 1][2])
arrows(0, 0, b * evecs[ , 2][3], b * evecs[ , 2][2])
dev.off()

asp=1pour avoir un rapport d'aspect de 1 et des flèches perpendiculaires. Changer votre code evs <- sqrt(eigens$values)donne la même ellipse que ma réponse.