Je travaille dans R grâce à un excellent tutoriel PCA par Lindsay I Smith et je suis coincé dans la dernière étape. Le script R ci-dessous nous amène à l'étape (à la p.19) où les données originales sont reconstruites à partir de la composante principale (singulière dans ce cas), ce qui devrait produire un tracé en ligne droite le long de l'axe PCA1 (étant donné que les données n'a que 2 dimensions, dont la seconde est intentionnellement supprimée).
d = data.frame(x=c(2.5,0.5,2.2,1.9,3.1,2.3,2.0,1.0,1.5,1.1),
y=c(2.4,0.7,2.9,2.2,3.0,2.7,1.6,1.1,1.6,0.9))
# mean-adjusted values
d$x_adj = d$x - mean(d$x)
d$y_adj = d$y - mean(d$y)
# calculate covariance matrix and eigenvectors/values
(cm = cov(d[,1:2]))
#### outputs #############
# x y
# x 0.6165556 0.6154444
# y 0.6154444 0.7165556
##########################
(e = eigen(cm))
##### outputs ##############
# $values
# [1] 1.2840277 0.0490834
#
# $vectors
# [,1] [,2]
# [1,] 0.6778734 -0.7351787
# [2,] 0.7351787 0.6778734
###########################
# principal component vector slopes
s1 = e$vectors[1,1] / e$vectors[2,1] # PC1
s2 = e$vectors[1,2] / e$vectors[2,2] # PC2
plot(d$x_adj, d$y_adj, asp=T, pch=16, xlab='x', ylab='y')
abline(a=0, b=s1, col='red')
abline(a=0, b=s2)
# PCA data = rowFeatureVector (transposed eigenvectors) * RowDataAdjust (mean adjusted, also transposed)
feat_vec = t(e$vectors)
row_data_adj = t(d[,3:4])
final_data = data.frame(t(feat_vec %*% row_data_adj)) # ?matmult for details
names(final_data) = c('x','y')
#### outputs ###############
# final_data
# x y
# 1 0.82797019 -0.17511531
# 2 -1.77758033 0.14285723
# 3 0.99219749 0.38437499
# 4 0.27421042 0.13041721
# 5 1.67580142 -0.20949846
# 6 0.91294910 0.17528244
# 7 -0.09910944 -0.34982470
# 8 -1.14457216 0.04641726
# 9 -0.43804614 0.01776463
# 10 -1.22382056 -0.16267529
############################
# final_data[[1]] = -final_data[[1]] # for some reason the x-axis data is negative the tutorial's result
plot(final_data, asp=T, xlab='PCA 1', ylab='PCA 2', pch=16)
C'est aussi loin que j'ai, et tout va bien jusqu'à présent. Mais je ne peux pas comprendre comment les données sont obtenues pour le tracé final - la variance attribuable à l'ACP 1 - que Smith trace comme:
Voici ce que j'ai essayé (qui ignore l'ajout des moyens d'origine):
trans_data = final_data
trans_data[,2] = 0
row_orig_data = t(t(feat_vec[1,]) %*% t(trans_data))
plot(row_orig_data, asp=T, pch=16)
.. et a obtenu une erreur:
.. parce que j'ai perdu une dimension de données d'une manière ou d'une autre dans la multiplication matricielle. Je serais très reconnaissant d'avoir une idée de ce qui ne va pas ici.
* Éditer *
Je me demande si c'est la bonne formule:
row_orig_data = t(t(feat_vec) %*% t(trans_data))
plot(row_orig_data, asp=T, pch=16, cex=.5)
abline(a=0, b=s1, col='red')
Mais je suis un peu confus si oui car (a) je comprends les rowVectorFeature
besoins à réduire à la dimensionnalité souhaitée (le vecteur propre pour PCA1), et (b) il ne correspond pas à l'abline PCA1:
Toutes vues très appréciées.
s1
Réponses:
Vous étiez très près de là et vous avez été pris par un problème subtil en travaillant avec des matrices dans R. J'ai travaillé avec vous
final_data
et j'ai obtenu les bons résultats indépendamment. Ensuite, j'ai regardé de plus près votre code. Pour abréger une longue histoire, où vous avez écrittu aurais été d'accord si tu avais écrit
trans_data
t(feat_vec[1,])
row_orig_data = t(as.matrix(feat_vec[1,],ncol=1,nrow=2) %*% t(trans_data))
non-conformable arguments
final_data
row_orig_data
t(t(p) %*% t(q)) = q %*% t
Écrire
puis pour récupérer vos données dans leur base d'origine, vous avez besoin
Vous pouvez mettre à zéro les parties de vos données qui sont projetées le long du deuxième composant à l'aide de
et vous pouvez ensuite transformer comme avant
Le fait de les tracer sur le même tracé, ainsi que la ligne des composants principaux en vert, vous montre comment fonctionne l'approximation.
Revenons à ce que vous aviez. Cette ligne était ok
feat_vec %*% row_data_adj
Ensuite, vous aviez
C'est correct: vous mettez à zéro les parties de vos données qui sont projetées le long du deuxième composant. Là où ça va mal, c'est
t(feat_vec[1,]) %*% t(trans_data)
la source
Je pense que vous avez la bonne idée, mais que vous êtes tombé sur une caractéristique désagréable de R. Ici encore, le morceau de code pertinent comme vous l'avez dit:
final_data
Contient essentiellement les coordonnées des points d'origine par rapport au système de coordonnées défini par les vecteurs propres de la matrice de covariance. Pour reconstruire les points d'origine, il faut donc multiplier chaque vecteur propre avec la coordonnée transformée associée, par exemplece qui donnerait les coordonnées d'origine du premier point. Dans votre question , vous définissez correctement le second composant à zéro,
trans_data[,2] = 0
. Si vous (comme vous l'avez déjà modifié) calculezvous calculez la formule (1) pour tous les points simultanément. Votre première approche
calcule quelque chose de différent et ne fonctionne que parce que R supprime automatiquement l'attribut dimension pour
feat_vec[1,]
, il n'est donc plus un vecteur ligne mais traité comme un vecteur colonne. La transposition suivante en fait à nouveau un vecteur ligne et c'est la raison pour laquelle au moins le calcul ne produit pas d'erreur, mais si vous passez par le calcul, vous verrez que c'est quelque chose de différent de (1). En général, c'est une bonne idée dans les multiplications matricielles de supprimer la suppression de l'attribut de dimension qui peut être obtenue par ledrop
paramètre, par exemplefeat_vec[1,,drop=FALSE]
.la source
drop=F
argument.Après avoir exploré cet exercice, vous pouvez essayer les méthodes les plus simples dans R. Il existe deux fonctions populaires pour effectuer l'ACP:
princomp
etprcomp
. Laprincomp
fonction effectue la décomposition des valeurs propres comme dans votre exercice. Laprcomp
fonction utilise la décomposition en valeurs singulières. Les deux méthodes donneront les mêmes résultats presque tout le temps: cette réponse explique les différences de R, tandis que cette réponse explique les mathématiques . (Merci à TooTone pour les commentaires désormais intégrés à ce message.)Ici, nous utilisons les deux pour reproduire l'exercice dans R. Tout d'abord en utilisant
princomp
:Deuxième utilisation
prcomp
:De toute évidence, les signes sont inversés, mais l'explication de la variation est équivalente.
la source