其他分享
首页 > 其他分享> > 数据压缩·课前任务二(PCA)

数据压缩·课前任务二(PCA)

作者:互联网

要求:主成分分析:步骤、应用及代码实现

  1. 中心化/零均值化:对矩阵的每一列求平均值得到meanVal,并让矩阵中的每一个元素减去对应列的均值得到newData;
  2. 求协方差矩阵covMat;
  3. 求协方差矩阵的特征向量(要归一化为单位向量)和特征值;
  4. 将特征值从大到小排序,选取最大的k个,然后将其对应的k个特征向量分别作为列向量组成特征向量矩阵;
  5. 将样本值投影到选取的特征向量上
import numpy as np

dataMat=[[1,2,3,4,3],[5,10,15,20,15],[3,6,2,12,20],[4,18,12,16,12]]
dataMat=np.mat(dataMat)
print(dataMat)

# 进行中心化/零均值化
def centralize(dataMat):
    meanVal=np.mean(dataMat,axis=0) # 先对dataMat的每一列求均值,注意np.mean的用法
    newData=dataMat-meanVal #dataMat中每列的每个数都减去对应列的均值
    return  newData,meanVal

# 求协方差矩阵
def covmat(dataMat):
    newData=centralize(dataMat)[0]
    covMat=np.cov(newData,rowvar=0)
    return covMat

# 如何选择k值
def selectK(eigVal, percentage):
    sum = 0
    sum_eigVal=0
    for i in range(len(eigVal)):
        sum_eigVal += abs(eigVal[i])
    for i in range(len(eigVal)):
        sum += abs(eigVal[i])
        if sum >= sum_eigVal * percentage:
            return i+1
            break

# 求协方差矩阵的特征向量与特征值,并对原数据dataMat进行降维以及数据重构
def pca(dataMat,percentage):
    newData,meanVal=centralize(dataMat)
    eigVal,eigVec=np.linalg.eig(covmat(dataMat))#求特征值及特征向量
    eigVal=sorted(eigVal,reverse=True)#对特征值进行由大到小的排序
    k=selectK(eigVal,percentage)

    # 取对应k个特征向量
    sort=np.argsort(eigVal)#对eigVal进行排序,结果是排好序元素对下标
    eigVal_sort=sort[-1:-(k+1):-1]#取最大的k个特征值的下标
    k_eigVec=eigVec[:,eigVal_sort]#这k个特征值对应的特征向量

    lowData=np.dot(newData,k_eigVec) #把经过中心化的样本值降维
    reconData=np.dot(lowData,np.transpose(k_eigVec))+meanVal #重构数据,k_eigVec为正交矩阵,所以它的逆等于它的转制
    return lowData,reconData

lowdata,recondata=pca(dataMat,0.99)
print(lowdata)

#结果:
[[ 1  2  3  4]
 [ 5 10 15 20]
 [ 3  6  2 12]]
[[  9.52768035  -2.58219897]
 [-12.33411712  -1.14629811]
 [  2.80643676   3.72849708]]
import numpy as np
from PIL import Image

# 将图像转化为可处理的矩阵
def loadImage(path):
    img = Image.open(path)
    # 将图像转换成灰度图
    img=img.convert('L')
    # 图像的大小在size中是(宽,高)
    # 所以width取size的第一个值,height取第二个
    width = img.size[0]
    height = img.size[1]
    dataMat = np.mat(img.getdata())

    print(dataMat)
    # 为了避免溢出,这里对数据进行一个缩放,缩小100倍
    # dataMat = np.array(dataMat).reshape(height,width)/100
    dataMat = dataMat.reshape(height, width) / 100

    # 查看原图的话,需要还原数据
    new_im = Image.fromarray(dataMat*100)
    new_im.show()
    return dataMat

dataMat=loadImage('path')

# 进行中心化/零均值化
def centralize(dataMat):
    meanVal=np.mean(dataMat,axis=0) # 先对dataMat的每一列求均值,注意np.mean的用法
    newData=dataMat-meanVal #dataMat中每列的每个数都减去对应列的均值
    return  newData,meanVal

# 求协方差矩阵
def covmat(dataMat):
    newData=centralize(dataMat)[0]
    covMat=np.cov(newData,rowvar=0)
    return covMat

# 如何选择k值
def selectK(eigVal, percentage):
    sum = 0
    sum_eigVal=0
    for i in range(len(eigVal)):
        sum_eigVal += abs(eigVal[i])
    for i in range(len(eigVal)):
        sum += abs(eigVal[i])
        if sum >= sum_eigVal * percentage:
            return i+1
            break

# 求协方差矩阵的特征向量与特征值,并对原数据dataMat进行降维以及数据重构
def pca(dataMat,percentage):
    newData,meanVal=centralize(dataMat)
    eigVal,eigVec=np.linalg.eig(covmat(dataMat))#求特征值及特征向量
    eigVal=sorted(eigVal,reverse=True)
    k=selectK(eigVal,percentage)

    # 取对应k个特征向量
    sort=np.argsort(eigVal)
    eigVal_sort=sort[-1:-(k+1):-1]
    k_eigVec=eigVec[:,eigVal_sort]

    lowData=np.dot(newData,k_eigVec) #把经过中心化的样本值降维
    reconData=np.real(np.dot(lowData,np.transpose(k_eigVec))+meanVal) #重构数据,k_eigVec为正交矩阵,所以它的逆等于它的转制,
                                                               # 为了保证可以重构数据,取实值
    print(reconData)
    newImage = Image.fromarray(reconData * 100)
    newImage.show()

    return reconData

pca(dataMat,0.99)

结果:
原图:
在这里插入图片描述

转为灰度后:
在这里插入图片描述
降维处理后:
在这里插入图片描述

很明显的我们发现降维后的图片在图像横向方向进行了压缩(因为我们处理的时候去掉了一些特征值较小的对应的列向量)。

qq_42949426 发布了2 篇原创文章 · 获赞 0 · 访问量 46 私信 关注

标签:eigVal,矩阵,任务,np,dataMat,PCA,newData,数据压缩,eigVec
来源: https://blog.csdn.net/qq_42949426/article/details/104620475