PCA是机器学习的入门算法之一,涉及到线性代数中矩阵的相关知识,基础理论比较多,主要涉及到奇异值分解。基础理论这里不多说了,大家可以去以下博客学习,用例子说明是最轻松的理解过程。
主成分分析原理详解:https://blog.csdn.net/program_developer/article/details/80632779
这篇文章从基向量变换的方向说明降维,更加直白理解pca:https://blog.csdn.net/shizhixin/article/details/51181379
如果你看完了上面的pca基础理论,并且学习了一些小基础,想找个练手的例子,那么来这里看就对了。
第一个例子,自己写pca函数实现图像的降维。这里是对图像的列进行降维,即宽度上进行压缩。
网上找的喵主子是这样的:
首先我们用载入函数将它转换成灰度图像
def loadImage(path):
img = Image.open(path)
# 将图像转换成灰度图
img = img.convert("L")
# 图像的大小在size中是(宽,高)
# 所以width取size的第一个值,height取第二个
width = img.size[0]
height = img.size[1]
data = img.getdata()
# 为了避免溢出,这里对数据进行一个缩放,缩小100倍
data = np.array(data).reshape(height,width)/100
# 查看原图的话,需要还原数据
new_im = Image.fromarray(data*100)
new_im.show()
return data
转换之后是这样的
接着我们定义我们的pca函数,如果你看了上面的推荐的博客的话,你应该知道这里对列进行降维应该用到哪个矩阵,在奇异值分解中,对任意矩阵A,有 A = USVT ,其中U对应是在行即高度上进行降维,V是对应在列上降维的正定矩阵。要求得V,采用方阵的特征值分解,构造ATA(AT表示A的转置)= VS2VT , 类似的求U, 有 AAT= US2UT。详情请看上面推荐的博客内容。所以注意到pca函数中这里的代码
这里用的矩阵的转置乘矩阵,对应求V
matrix_ = np.dot(np.transpose(normal_data),normal_data)
def pca(data,k):
""
:param data: 图像数据
:param k: 保留前k个主成分
:return:
"""
n_samples,n_features = data.shape
# 求均值
mean = np.array([np.mean(data[:,i]) for i in range(n_features)])
# 去中心化
normal_data = data - mean
# 得到协方差矩阵
matrix_ = np.dot(np.transpose(normal_data),normal_data)
# 有时会出现复数特征值,导致无法继续计算,这里用了不同的图像,有时候会出现复数特征,但是经过
sklearn中的pca处理同样图像可以得到结果,如果你知道,请留言告诉我。
我能知道的是协方差矩阵肯定是实对称矩阵的
eig_val,eig_vec = np.linalg.eig(matrix_)
# print(matrix_.shape)
# print(eig_val)
# 第一种求前k个向量
# eig_pairs = [(np.abs(eig_val[i]),eig_vec[:,i]) for i in range(n_features)]
# eig_pairs.sort(reverse=True)
# feature = np.array([ele[1] for ele in eig_pairs[:k]])
# new_data = np.dot(normal_data,np.transpose(feature))
# 第二种求前k个向量
eigIndex = np.argsort(eig_val)
eigVecIndex = eigIndex[:-(k+1):-1]
feature = eig_vec[:,eigVecIndex]
new_data = np.dot(normal_data,feature)
# 将降维后的数据映射回原空间
rec_data = np.dot(new_data,np.transpose(feature))+ mean
# print(rec_data)
# 压缩后的数据也需要乘100还原成RGB值的范围
newImage = Image.fromarray(rec_data*100)
newImage.show()
return rec_data
当我们保留前10个主成分时,得到如下图像
虽然得到了降维后的图像,但是怎么知道我们降维后的图像保留了多小信息呢?根据pca的误差计算方式,编写函数如下
def error(data,recdata):
sum1 = 0
sum2 = 0
# 计算两幅图像之间的差值矩阵
D_value = data - recdata
# 计算两幅图像之间的误差率,即信息丢失率
for i in range(data.shape[0]):
sum1 += np.dot(data[i],data[i])
sum2 += np.dot(D_value[i], D_value[i])
error = sum2/sum1
print(sum2, sum1, error)
当k=10时,我们得到这个值,最后一个数值是误差比,也就是说,我们降维后的数据保留了99%的原始信息,当k=20时,这个数大概是0.005.你们可以自己运行一下。
23076.032446296413 2261348.8400000017 0.010204543429175834
通过自己编写pca的实现代码可以加深印象,但是python的强大在于各种第三方库,sklearn是机器学习最重要的一个库,里面包含了pca函数,我们试着调用一下
import numpy as np
from sklearn.decomposition import PCA
import numpy as np
from PIL import Image
def loadImage(path):...
def error(data, recdata):...
if __name__ == '__main__':
data = loadImage("timg.jpg")
pca = PCA(n_components=10).fit(data)
# 降维
x_new = pca.transform(data)
# 还原降维后的数据到原空间
recdata = pca.inverse_transform(x_new)
# 计算误差
error(data, recdata)
# 还原降维后的数据
newImg = Image.fromarray(recdata*100)
newImg.show()
# error(data, recdata)
得到的值课我们自己写的差不多
23076.032452099163 2261348.8400000017 0.010204543431741892
好了,例子就到这里了。欢迎留言反馈
参考文章
【1】主成分分析(PCA)原理详解
【2】机器学习算法笔记系列之深入理解主成分分析PCA-原理篇
【3】【机器学习】Sklearn库主成分分析PCA降维的运用实战