实验目的
了解基本数据降维的基本原理,并掌握Python语言中实现数据降维算法的函数方法
实验原理
主成分分析(PCA)是一种无监督的学习方式,是一种常用的线性降维方法。如果遇到多因素分析,想要很多个自变量与因变量进行线性回归分析,一般都必须进行降维处理,而主成分分析是一种很好的解决方案。
实验步骤
一、PCA简介
PCA是将数据的n维特征映射到k维上(k<n),k维是全新的正交特征。这里的k维是重新构造出来的k维特征,而不是简单的从n维特征中找出k维。
PCA求解的一般流程为:
(1)将原始数据进行标准化;
(2)计算标准化数据集的协方差矩阵;
(3)计算协方差矩阵的特征值和特征向量;
(4)保留最重要的k个特征(k<n),可以选择一个阈值,让前k个特征值之和减去后面n-k个特征值之和大于这 个阈值,找到这个k值,计算主成分变量值;
(5)找到这k个特征值对应的特征向量;
(6)将m乘n的数据集乘以k个n维的特征向量(n乘k),得到最终降维的数据集;
其实PCA的本质就是对角化协方差矩阵,解释一下为什么将特征值按照从大到小排序后再选择。首先解释一下特征值和特征向量表示什么。在线性代数中,对一个n*n的对称矩阵进行分解,我们可以求出它的特征值和特征向量,就会产生n个n维的正交基,每个正交基会对应一个特征值。然后把矩阵投影到这n个正交基上,此时特征值的模就表示矩阵在该基的投影长度。特征值越大,表示矩阵在对应的特征向量上的方差越大,样本越离散,越容易区分,信息量也越多。因此,特征值最大的对应的特征向量方向上所包含的信息量就越多。如果某几个特征值很小,那么说明在该方向上的信息量非常少,我们就可以删除小特征值所对应方向的数据,只保留大特征值方向对应的数据,这样做以后数据量越小,但是有用的信息量都保留下来了。
二、PCA的python实现
注意:python2中print语句不加括号,python3中print语句打印内容要加括号!
点击下载数据:https://github.com/csuldw/MachineLearning/blob/master/PCA/data.txt
矩阵运算需要用到numpy包以及numpy包中的genfromtxt函数,这个函数是可以读取txt文件;还需要用到matplotlib进行画图.
首先,计算均值,要求输入数据为numpy的矩阵格式,行表示样本数,列表示特征 。计算方差,传入的是一个numpy的矩阵格式,行表示样本数,列表示特征 。标准化,传入的是一个numpy的矩阵格式,行表示样本数,列表示特征。
- # -*- coding: utf-8 -*-
- import numpy as np
- import pandas as pd
- import matplotlib.pyplot as plt
- #计算均值,要求输入数据为numpy的矩阵格式,行表示样本数,列表示特征
- def meanX(dataX):
- return np.mean(dataX,axis=0)#axis=0表示按照列来求均值,如果输入list,则axis=1
- #计算方差,传入的是一个numpy的矩阵格式,行表示样本数,列表示特征
- def variance(X):
- m, n = np.shape(X)
- mu = meanX(X)
- muAll = np.tile(mu, (m, 1))
- X1 = X - muAll
- variance = 1./m * np.diag(X1.T * X1)
return variance
#标准化,传入的是一个numpy的矩阵格式,行表示样本数,列表示特征
def normalize(X):
m, n = np.shape(X)
- mu = meanX(X)
- muAll = np.tile(mu, (m, 1))
- X1 = X - muAll
- X2 = np.tile(np.diag(X.T * X), (m, 1))
- XNorm = X1/X2
return XNorm
"""
参数:
- XMat:传入的是一个numpy的矩阵格式,行表示样本数,列表示特征
- k:表示取前k个特征值对应的特征向量
- 返回值:
- finalData:参数一指的是返回的低维矩阵,对应于输入参数二
- reconData:参数二对应的是移动坐标轴后的矩阵
- """
- def pca(XMat, k):
- average = meanX(XMat)
- m, n = np.shape(XMat)
- data_adjust = []
- avgs = np.tile(average, (m, 1))
- data_adjust = XMat - avgs
- covX = np.cov(data_adjust.T) #计算协方差矩阵
- featValue, featVec= np.linalg.eig(covX) #求解协方差矩阵的特征值和特征向量
- index = np.argsort(-featValue) #按照featValue进行从大到小排序
- finalData = []
- if k > n:
- print ("k must lower than feature number")
- return
- else:
- #注意特征向量时列向量,而numpy的二维矩阵(数组)a[m][n]中,a[1]表示第1行值
- selectVec = np.matrix(featVec.T[index[:k]]) #所以这里需要进行转置
- finalData = data_adjust * selectVec.T
- reconData = (finalData * selectVec) + average
- return finalData, reconData
- def loaddata(datafile):
- return np.array(pd.read_csv(datafile,sep="\t",header=-1)).astype(np.float)
- def plotBestFit(data1, data2):
- dataArr1 = np.array(data1)
- dataArr2 = np.array(data2)
- m = np.shape(dataArr1)[0]
- axis_x1 = []
- axis_y1 = []
- axis_x2 = []
- axis_y2 = []
- for i in range(m):
- axis_x1.append(dataArr1[i,0])
- axis_y1.append(dataArr1[i,1])
- axis_x2.append(dataArr2[i,0])
- axis_y2.append(dataArr2[i,1])
- fig = plt.figure()
- ax = fig.add_subplot(111)
- ax.scatter(axis_x1, axis_y1, s=50, c='red', marker='s')
- ax.scatter(axis_x2, axis_y2, s=50, c='blue')
- plt.xlabel('x1'); plt.ylabel('x2');
- plt.savefig("outfile.png")
- plt.show()
接下来进行测试:
- #测试
- def test():
- X = [[2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2, 1, 1.5, 1.1],
- [2.4, 0.7, 2.9, 2.2, 3.0, 2.7, 1.6, 1.1, 1.6, 0.9]]
- XMat = np.matrix(X).T
- k = 2
- return pca(XMat, k)
- #根据数据集data.txt
- def main():
- datafile = "data.txt"
- XMat = loaddata(datafile)
- k = 2
- return pca(XMat, k)
- if __name__ == "__main__":
- finalData, reconMat = main()
- plotBestFit(finalData, reconMat)
得到结果: