###1.主成分分析计算步骤
实现过程如下:
(1)计算标准化的值z-score(z=(x-mu)/delta)关于为什么要用z-score做标准化的原因是:减去均值等同于坐标的移动,把原始数据点的重心移到和原点重合,这样利于很多表达,比如数据的协方差矩阵可以写成XX’,若没有减去均值,则XX‘后面还要减去一些东西(还不明白可以参考多元统计分析的书)。除以标准差是为了统一并消除量纲。一个矩阵中有多个向量,有些可能表示了长度,有些表示了重量,除以标准差,才能让它们仅以“数”的概念一起比较运算。
(2)计算z-score的协方差矩阵,根据协方差矩阵计算特征值和特征向量
(3)将特征值进行有大到小排列,保留所有特征值中的前N个特征值,并保留其对应的特征向量
(4)将获得的N个特征向量映射到新的空间
###2. python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| import numpy as np from scipy import linalg from sklearn.datasets import load_iris from numpy import * def qr(A): n, m = A.shape R = A.copy() Q = np.eye(n) for k in range(m-1): x = np.zeros((n, 1)) x[k:, 0] = R[k:, k] v = x v[k] = x[k] + np.sign(x[k,0]) * np.linalg.norm(x) s = np.linalg.norm(v) if s != 0: u = v / s R -= 2 * np.dot(u, np.dot(u.T, R)) Q -= 2 * np.dot(u, np.dot(u.T, Q)) Q = Q.T return Q, R def eigen_qr(A): T = 1000 A_copy = A.copy() r, c = A_copy.shape V = np.random.random_sample((r, r)) for i in range(T): Q, _ = qr(V) V = np.dot(A_copy, Q) Q, R = qr(V) return R.diagonal(), Q def my_pca(A, topNfeat=5): meanVals = mean(A, axis=0) meanRemoved = A - meanVals stded = meanRemoved / std(A,axis=0) covA=cov(stded, rowvar=0) eigVals, eigVects=eigen_qr(covA) eigValInd = argsort(eigVals) eigValInd = eigValInd[:-(topNfeat + 1):-1] Lambda = np.array(eigVals)[eigValInd]**0.5 Q = eigVects[:, eigValInd] return Lambda, Q iris = load_iris() my_pca(iris.data)
|
国内很多网站有类似的PCA用python实现的代码,但里面有些小错误,std()这个函数如果axis不加,那么它默认对整个矩阵A求标准差,结果是一个值,如果是加上axis=0那么就是对列求标准差。
###3. R语言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| myqr <- function(A) { n = nrow(A) m = ncol(A) R = A Q = diag(n) for (k in 1:(m-1)) { x = matrix(rep(0, n), nrow = n) x[k:n, 1] = R[k:n, k] g = sqrt(sum(x^2)) v = x v[k] = x[k] + sign(x[k,1])*g s = sqrt(sum(v^2)) if (s != 0) { u = v / s R = R - 2 * u %*% t(u) %*% R Q = Q - 2 * u %*% t(u) %*% Q } } result <- list(t(Q), R) names(result) <- c("Q", "R") result } myeigen <- function(A) { T = 1000 n = nrow(A) V = matrix(rnorm(n*n), nrow=n) for (i in 1:T) { V = myqr(V)$Q V = A %*% V } B = myqr(V) result <- list(B$Q, diag(B$R)) names(result) <- c("vectors", "values") result } my_pca <- function(A,topNfeat) { sd=scale(A,center=TRUE,scale=TRUE) covA=cov(sd) eigen=myeigen(covA) result <- list(t(eigen$vector[1:topNfeat,]),eigen$values[1:topNfeat]^0.5) names(result) <- c("Q","lambda") result } iris_data_frame = data.frame(iris[,1:4]) kk=my_pca(iris_data_frame,4)
|
两个代码思路是一样的一些矩阵操作依据语言不同而略显差异。