【数据挖掘】PCA算法的复现实验

本次实验内容为基于python的PCA算法的复现。本实验将以主成分分析(PCA)原理详解中的数据为例,展示使用PCA算法从二维数据降维为一维数据的代码复现。若理解有误,欢迎批评指正。

一、算法基本思路

算法可简单概括为五个步骤,即1.数据中心化;2.求求特征协方差矩阵3. 求协方差特征值λ和特征向量4. 选取k个特征值最大的特征向量构造矩阵5. 做矩阵投影得到降维后的数据。思路概括如下图所示。
【数据挖掘】PCA算法的复现实验
首先读入二维数据。

list = [[2.5,2.4],[0.5,0.7],[2.2,2.9],[1.9,2.2],[3.1,3.0],[2.3,2.7],[2,1.6],[1,1.1],[1.5,1.6],[1.1,0.9]]

为计算每个维度的平均值,我选择分别保存x,y维度的样本数值为列表,直接计算列表的平均值

for x,y in list:#分别存储所有x值y值
    list_x.append(x)
    list_y.append(y)
#print(list_x)

#1.求均值
ave_x = np.mean(list_x)

ave_y = np.mean(list_y)

后继续用列表保存中心化后的数值,中心化x,y维度数值后,再重新合并x,y维度的数值,重新保存

for i in range(0,len(list)):
    x = round(list_x[i]-ave_x,2)#保留两位小数,下同
    y = round(list_y[i]-ave_y,2)
    new_list_index=[x,y]
    new_list.append(new_list_index)    
#得到中心化矩阵

接下来调用函数,求得协方差矩阵,通过协方差矩阵推算特征值和特征向量

#2.求特征协方差矩阵
new_list=np.array(new_list)#数据类型转换
C=np.cov(new_list.T)#求协方差矩阵

#3.求协方差特征值与特征向量
eigen_vals, eigen_vecs = np.linalg.eig(C)#同时求出特征值和特征向量
#特征值是eigen_vals,特征向量是eigen_vecs,#特征向量是按列放的,即一列代表一个特征向量

最后根据特征值大小关系选取特征向量,这里因为做得是二维降维为一维,所以直接取了最大值,正常降到k维应当先大小排序,再选取前k个最大的特征值。

I = eigen_vals.tolist()

#需要先将eigen_vals转换为list类型,否则eigen_vals.index(max(eigen_vals))将会报错'numpy.ndarray' object has no attribute 'index'
#选取的特征值已确定为eigen_vals,其对应特征向量索引为eigen_vals.index(max(eigen_vals)
#即该列为保留的特征向量(非该行)

根据特征值选取特征向量。

A = []#用于存储选取的特征向量矩阵
count = 0#计数器
#print(I.index(max(I)))
for data in eigen_vecs:
    for j in data:
        #先把所有特征向量平铺
        print(j)
        count +=1
        #print(count)
        if count%(I.index(max(I))+1)==0:
            A.append(j)

这里选择平铺所有数据后选值,其实将该矩阵转置为矩阵A后直接用矩阵A[eigen_vals.index(max(eigen_vals)]把元素取出也是可以的。

最后将样本投影到选取的特征向量上,new_list.dot(A)相当于new_list矩阵和A矩阵相乘。

#做矩阵乘法
#print(A)
B = new_list
#print(B)
PCA_list = new_list.dot(A)

二、实验代码

# -*- coding: utf-8 -*-
"""
Created on Thu Nov  5 19:03:56 2020

@author: 纸羊同学
"""
#PCA算法复现
import numpy as np

#0.数据准备(数据来自https://blog.csdn.net/zhongkelee/article/details/44064401)
list = [[2.5,2.4],[0.5,0.7],[2.2,2.9],[1.9,2.2],[3.1,3.0],[2.3,2.7],[2,1.6],[1,1.1],[1.5,1.6],[1.1,0.9]]
list_x = []#用于存储所有x值
list_y = []#用于存储所有y值
new_list = []#用于存储中心化后的列表
new_list_index = []#用于存储中心化后的列表元素
PCA_list=[]#用于存储PCA降维后的数据

for x,y in list:#分别存储所有x值y值
    list_x.append(x)
    list_y.append(y)
#print(list_x)

#1.求均值
ave_x = np.mean(list_x)

ave_y = np.mean(list_y)

#然后做数据中心化处理,即所有样本减去各自维度均值
for i in range(0,len(list)):
    x = round(list_x[i]-ave_x,2)#保留两位小数,下同
    y = round(list_y[i]-ave_y,2)
    new_list_index=[x,y]
    new_list.append(new_list_index)    
#得到中心化矩阵
print("数据中心化:n",new_list)
print("n--------------------我是分割线--------------------")

#2.求特征协方差矩阵
new_list=np.array(new_list)#数据类型转换
C=np.cov(new_list.T)#求协方差矩阵

print("协方差矩阵:n",C)
print("--------------------我是分割线--------------------")

#3.求协方差特征值与特征向量
eigen_vals, eigen_vecs = np.linalg.eig(C)#同时求出特征值和特征向量
#特征值是eigen_vals,特征向量是eigen_vecs,#特征向量是按列放的,即一列代表一个特征向量
print("特征值n",eigen_vals,"^T","n","特征向量n",eigen_vecs,"n")
print("--------------------我是分割线--------------------")

#4.将特征值按照从大到小的顺序排序,选择其中最大的k个,然后将其对应的k个特征向量分别作为列向量组成特征向量矩阵。
I = eigen_vals.tolist()

#需要先将eigen_vals转换为list类型,否则eigen_vals.index(max(eigen_vals))将会报错'numpy.ndarray' object has no attribute 'index'
#选取的特征值已确定为eigen_vals,其对应特征向量索引为eigen_vals.index(max(eigen_vals)
#即该列为保留的特征向量(非该行)
A = []#用于存储选取的特征向量矩阵
count = 0#计数器
#print(I.index(max(I)))
for data in eigen_vecs:
    for j in data:
        #先把所有特征向量平铺
        print(j)
        count +=1
        #print(count)
        if count%(I.index(max(I))+1)==0:
            A.append(j)
        

print("特征值最大值是",max(eigen_vals),"n故特征向量矩阵为",A,"^T")
print("n--------------------我是分割线--------------------")
'''
5.将样本点投影到选取的特征向量上。
假设样例数为m,特征数为n,减去均值后的样本矩阵为DataAdjust(m*n),协方差矩阵是n*n,选取的k个特征向量组成的矩阵为EigenVectors(n*k)。
那么投影后的数据FinalData为
FinalData(10*1) = DataAdjust(10*2矩阵) x 特征向量(-0.677873399, -0.735178656)^T
'''
#做矩阵乘法
#print(A)
B = new_list
#print(B)
PCA_list = new_list.dot(A)
PCA_list.transpose()
print("经PCA降维后的结果为:n",PCA_list)

运行结果如下
【数据挖掘】PCA算法的复现实验

三、对比检验

直接调用PCA包运行算法

# -*- coding: utf-8 -*-
"""
Created on Thu Nov  5 18:52:21 2020

@author: 纸羊同学
直接调用PCA包进行降维计算的代码
"""
#0.数据准备(数据来自https://blog.csdn.net/zhongkelee/article/details/44064401)
'''
x = [2.5,0.5,2.2,1.9,3.1,2.3,2,1,1.5,1.1]
y = [2.4,0.7,2.9,2.2,3.0,2.7,1.6,1.1,1.6,0.9]
list = [x]
list.append(y)
'''
list = [[2.5,2.4],[0.5,0.7],[2.2,2.9],[1.9,2.2],[3.1,3.0],[2.3,2.7],[2,1.6],[1,1.1],[1.5,1.6],[1.1,0.9]]

#print(list)
from sklearn.decomposition import PCA

pca = PCA(n_components=1)#降成一维数据

newlist=pca.fit_transform(list)

print(newlist)

得到降维数据如下,与复现结果一致。
【数据挖掘】PCA算法的复现实验

四、代码不足

本实验的复现代码仅支持从二维到一维的PCA降维。若要实现从m维到n维的降维,需要修改0.数据准备1. 求均值部分,不能将原始数据仅仅分为x维和y维;以及第四部分,不能简单得选取最大值。

匿名

发表评论

匿名网友