原创不易,转载前请注明博主的连接地址:Blessy_Zhu https://blog.csdn.net/weixin_42555080
本次代码的环境:
运行平台: Windows
Python版本: Python3.x
IDE: PyCharmjava
在上一篇博文机器学习笔记(七)-主成分分析PCA 中,已经介绍了主成分分析PCA的基本内容。接下来的这篇文章,主要是经过一个多维的数据集,一步步去了解PCA的实现过程和原理。最后经过逻辑回归来拟合用PCA降维处理后的数据集。ios
本次选取数据集是UCI(网址:https://archive.ics.uci.edu/ml/datasets/ )上的数据集Wine Data Set (红酒数据集)。首先对这原始数据集进行简明扼要的介绍。
Wine Data Set主要是经过使用化学分析肯定葡萄酒的来源。数据集的相关信息以下表1-1所示:
Wine Data Set是由Stefan Aeberhard(电子邮件:stefan ‘@’ coral.cs.jcu.edu.au)捐助的。这些数据是对意大利同一地区种植的葡萄酒进行化学分析的结果,这些葡萄酒来自三个不一样的品种。该分析肯定了三种葡萄酒中每种葡萄酒中含有的13种成分的数量。不一样种类的酒品,它的成分也有所不一样,经过对这些成分的分析就能够对不一样的特定的葡萄酒进行分类分析。Wine Data Set原始 数据集共有178个样本数、3种数据类别、每一个样本的有13个属性。这13个属性分别是:酒精、苹果酸、灰、灰分的碱度、镁、总酚、黄酮类化合物、非黄烷类酚类、原花色素、颜色强度、色调、稀释葡萄酒的OD280 / OD31五、脯氨酸。web
在展开内容介绍以前,先来回顾一下本次须要用到的数学知识。算法
假设咱们有个样本集X,其中的样本为X=[1,2,3,4,5],求平均值的公式以下:
X的平均值为:
Python实现方式是:数组
import numpy as np X=np.array([1,2,3,4,5]) np.mean(X)
然而,样本均值对于极差较大的数据来讲,并不能很好的反应数据的性质,这样,就可使用样本均值来展现数据的分散程度:
Python代码实现是:less
import numpy as np X=np.array([1,2,3,4,5]) np.std(X)
方差和标准差只能操做一维的数据集,可是实际样本通常会有不少维的=。高维数据,虽然更好的表示了数据的特征,可是对于数据的分析和可视化来讲倒是很大的难题。若是能够经过判断数据维度之间的关系,从而实现降维的目的,那就太好了。而协方差就是这个目标中的一个重要步骤。协方差是测量样本特征之间的关系,好比:样本有2个特征,一个是学习时间,一个是成绩,那么正常状况下,必定是你的学习时间越长,你的成绩越好。
假设有两个特征X,Y。计算它们之间的协方差公式为:
协方差具体的大小并不重要,可是它的正负是重要的。dom
在真实数据集中,样本的维度不可能只有2个。在这种状况下用协方差矩阵表示。假设样本有n个特征,这里,用1,2,3,4,…,n来表示每一个特征。协方差矩阵以下所示:
上面C是一个n∗n维的矩阵,能够看到对角线上红色是本身与本身的协方差,也就是方差。而对角线两侧的协方差是对称的,所以协方差矩阵是一个关于对角线对称的方阵。
用以下两维数据:学习时间(Time)和分数(Score)的例子来演示一下协方差:
Python代码以下:机器学习
import numpy as np T=np.array([9,15,25,14,10,18,0,16,5,19,16,20]) S=np.array([39,56,93,61,50,75,32,85,42,70,66,80]) T=T[:,np.newaxis] #构造为二维数组 S=S[:,np.newaxis] X=np.hstack((T,S)) np.cov(X.T) # 协方差输出以下 array([[ 47.71969697, 122.9469697 ], [ 122.9469697 , 370.08333333]])
从上面的输出结果能够看到,cov(T,S)=cov(S,T)=122.9469697,这是正数,所以说明学习时间越长,分数越高。svg
v是一个非零向量,要想v是线性变换T的特征向量,则T(v)是一个标量值乘上v,它能够被写成以下形式:post
T(v)=λv (λ是一个标量,而且它也是关联着特征向量v的特征值)
若是线性变换T被表示成做为一个方阵A的变换,那么上面的等式能够写成以下形式:
Av=λv (v是列向量)
举个例子:假设上面的方阵A,则:
上面的(3@2)为特征向量,4为特征值。
这里须要注意一下几点:
PCA对数据缩放是至关敏感的,所以,在实现PCA的时候,若是数据特征在不一样的范围上,要先对数据集标准化。可使用scikit-learn对数据进行标准化,代码以下:
import pandas as pd df_wine = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data', header=None) # 加载葡萄酒数据集 from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values # 把分类属性与常规属性分开 X_train, X_test, y_train, y_test = train_test_split(X, y,test_size=0.3, random_state=0) # 把整个数据集的70%分为训练集,30%为测试集 # 下面3行代码把数据集标准化为单位方差和0均值 sc = StandardScaler() X_train_std = sc.fit_transform(X_train) X_test_std = sc.fit_transform(X_test)
由于每一个样本有13个属性,因此协方差矩阵的维数应该是13 * 13的方阵:
import numpy as np cov_mat = np.cov(X_train_std.T)
协方差矩阵是方阵,因此咱们能够计算它的特征向量和特征值。
import numpy as np eigen_vals, eigen_vecs = np.linalg.eig(cov_mat) # 下面的输出为eigen_vals array([ 4.8923083 , 2.46635032, 1.42809973, 1.01233462, 0.84906459, 0.60181514, 0.52251546, 0.08414846, 0.33051429, 0.29595018, 0.16831254, 0.21432212, 0.2399553 ])
因为特征向量是单位向量。可是,这些方向单位向量,哪一个方向上保留的方差最大呢?这其实并不难,求出的特征值的意义就是特征向量的大小,所以只要找出最大特征值所对应的特征向量就能够知道哪一个方向保留的方差最大。
接下来通过方差解释率(variance explained ratios),也就是每一个特征值占全部特征值和的比,来展现不一样维度对数据描述的贡献值。
tot = sum(eigen_vals) # 求出特征值的和 var_exp = [(i / tot) for i in sorted(eigen_vals, reverse=True)] # 求出每一个特征值占的比例(降序) cum_var_exp = np.cumsum(var_exp) # 返回var_exp的累积和 import matplotlib.pyplot as plt # 下面的代码都是绘图的,涉及的参数建议去查看官方文档 plt.bar(range(len(eigen_vals)), var_exp, width=1.0, bottom=0.0, alpha=0.5, label='individual explained variance') plt.step(range(len(eigen_vals)), cum_var_exp, where='post', label='cumulative explained variance') plt.ylabel('Explained variance ratio') plt.xlabel('Principal components') plt.legend(loc='best') plt.show()
这里须要介绍一下Cumulative explained variance(累计解释总方差)和Individual explained variance(单个解释方差)这两个概念:
从上图能够看到了,其实2个特征就已经保留了数据集的大部分信息,可见在实际应用中,大部分的特征都是冗余的。注意,PCA是无监督学习算法,这就意味着它会忽视类标签信息(即分类属性)。
上面已经成功地把协方差方阵转换成了特征向量和特征值,如今把葡萄酒数据集映射到新的主成分坐标轴。为了数据的可视化,把数据集映射到2个保留最多方差的主成分。所以,须要从大到小排序特征值,选出前2个特征值对应的特征向量,并用这2个特征向量构建映射矩阵,用这个映射矩阵把数据集转换到2维空间。
eigen_pairs =[(np.abs(eigen_vals[i]),eigen_vecs[:,i]) for i in range(len(eigen_vals))] # 把特征值和对应的特征向量组成对 eigen_pairs.sort(reverse=True) # 用特征值排序
下面,选出前2对来构建映射矩阵,可是在实际应用中,应该权衡计算效率和分类器之间的性能来选择恰当的主成分数量。
first = eigen_pairs[0][1] second = eigen_pairs[1][1] first = first[:,np.newaxis] second = second[:,np.newaxis] w = np.hstack((first,second))
如今,已经构建出了13×2维的映射矩阵 W,接下来能够用这个映射矩阵来转换训练集X_train_std(124×13维)到只包含2个特征的子空间,用X_train_pca=X_train_stdW,如今这个2维的新空间可视化了,代码以下:
import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus']=False X_train_pca = X_train_std.dot(w) # 转换训练集 colors = ['r', 'b', 'g'] markers = ['s', 'x', 'o'] for l, c, m in zip(np.unique(y_train), colors, markers): plt.scatter(X_train_pca[y_train==l, 0], X_train_pca[y_train==l, 1], c=c, label=l, marker=m) # 散点图 plt.xlabel('PC 1') plt.ylabel('PC 2') plt.legend(loc='lower left') plt.show()
如今,能够看到数据是线性可分的。
from sklearn.linear_model import LogisticRegression from sklearn.decomposition import PCA pca = PCA(n_components=2) # 保留2个主成分 lr = LogisticRegression() # 建立逻辑回归对象 X_train_pca = pca.fit_transform(X_train_std) # 把原始训练集映射到主成分组成的子空间中 X_test_pca = pca.transform(X_test_std) # 把原始测试集映射到主成分组成的子空间中 lr.fit(X_train_pca, y_train) # 用逻辑回归拟合数据 plot_decision_regions(X_train_pca, y_train, classifier=lr) lr.score(X_test_pca, y_test) # 0.98 在测试集上的平均正确率为0.98 plt.xlabel('PC1') plt.ylabel('PC2') plt.legend(loc='lower left') plt.show()
从上图能够看出,用PCA压缩数据之后,依然很好对样本进行分类。
本篇文章主要介绍了PCA降维Wine Data Set的详细过程。这篇文章就到这里了,欢迎大佬们多批评指正,也欢迎你们积极评论多多交流。