原创不易,转载前请注明博主的链接地址:Blessy_Zhu https://blog.csdn.net/weixin_42555080
本次代码的环境:
运行平台: Windows
Python版本: Python3.x
IDE: PyCharm
一、 前言
在上一篇博文机器学习笔记(七)-主成分分析PCA 中,已经介绍了主成分分析PCA的基本内容。接下来的这篇文章,主要是通过一个多维的数据集,一步步去了解PCA的实现过程和原理。最后通过逻辑回归来拟合用PCA降维处理后的数据集。
二、数据集
本次选取数据集是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 / OD315、脯氨酸。
三、准备工作
在展开内容介绍之前,先来回顾一下本次需要用到的数学知识。
3.1 均值(mean)、标准差(Standard Deviation)
假设我们有个样本集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代码实现是:
import numpy as np
X=np.array([1,2,3,4,5])
np.std(X)
3.2 协方差(Covariance)
方差和标准差只能操作一维的数据集,但是实际样本一般会有很多维的=。高维数据,虽然更好的表示了数据的特征,但是对于数据的分析和可视化来说却是很大的难题。如果可以通过判断数据维度之间的关系,从而实现降维的目的,那就太好了。而协方差就是这个目标中的一个重要步骤。协方差是测量样本特征之间的关系,比如:样本有2个特征,一个是学习时间,一个是成绩,那么正常情况下,一定是你的学习时间越长,你的成绩越好。
假设有两个特征X,Y。计算它们之间的协方差公式为:
协方差具体的大小并不重要,但是它的正负是重要的。
- 如果它的值是正的,这表明两个特征之间同时增加或减小;
- 如果它的值是负的,这表明两个特征之间有一个增加而另一个减小。
- 如果它的值为0,则表明两个特征之间是独立的。
在真实数据集中,样本的维度不可能只有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,这是正数,因此说明学习时间越长,分数越高。
3.3 特征向量(Eigen vectors)与特征值(Eigen values)
v是一个非零向量,要想v是线性变换T的特征向量,则T(v)是一个标量值乘上v,它可以被写成如下形式:
T(v)=λv (λ是一个标量,并且它也是关联着特征向量v的特征值)
如果线性变换T被表示成作为一个方阵A的变换,那么上面的等式可以写成如下形式:
Av=λv (v是列向量)
举个例子:假设上面的方阵A,则:
上面的(3@2)为特征向量,4为特征值。
这里需要注意一下几点:
- 只有方阵才能求出特征向量,但是,并不是每个方阵都有特征向量。假设我有一个n * n的矩阵,那么就有n个特征向量。
- 一个矩阵中的所有特征向量都是相互垂直的,无论数据集中有多少特征。
- 向量的大小不能影响它是不是一个特征向量,但是,它的方向可以。因此,在我们找到特征向量以后要把它们单位化,使所有的特征向量都有相同的长度。
四、PCA处理Wine Data Set
4.1 数据标准化
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)
4.2 计算协方差矩阵
因为每个样本有13个属性,所以协方差矩阵的维数应该是13 * 13的方阵:
import numpy as np
cov_mat = np.cov(X_train_std.T)
4.3 求协方差矩阵的特征向量和特征值
协方差矩阵是方阵,所以我们可以计算它的特征向量和特征值。
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(单个解释方差)这两个概念:
- Individual explained variance(单个解释方差):就是单个属性(比如上图中的第一个属性)对数据描述的贡献值,也就是说,属性0,30%-40%的概率可以准确描述样本。
- Cumulative explained variance(累计解释总方差):将每个属性的贡献值加起来,其最大值为100%。也就是说,上图的样本有13个属性,那么这13个属性可以100%描述样本。即完全代表原来的变量信息(当然这是不可能的)
从上图可以看到了,其实2个特征就已经保留了数据集的大部分信息,可见在实际应用中,大部分的特征都是冗余的。注意,PCA是无监督学习算法,这就意味着它会忽视类标签信息(即分类属性)。
4.4 特征变换(Feature transformation)
上面已经成功地把协方差方阵转换成了特征向量和特征值,现在把葡萄酒数据集映射到新的主成分坐标轴。为了数据的可视化,把数据集映射到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()
现在,可以看到数据是线性可分的。
五 LR实现Wine Data Set数据分类
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的详细过程。这篇文章就到这里了,欢迎大佬们多批评指正,也欢迎大家积极评论多多交流。
