PCA主成分分析(降维)
PCA(Principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据降维算法。PCA的主要思想是将n维特征映射到k维上,这k维是全新的正交特征也被称为主成分,是在原有n维特征的基础上重新构造出来的k维特征。PCA的工作就是从原始的空间中顺序地找一组相互正交的坐标轴,新的坐标轴的选择与数据本身是密切相关的。其中,第一个新坐标轴选择是原始数据中方差最大的方向,第二个新坐标轴选取是与第一个坐标轴正交的平面中使得方差最大的,第三个轴是与第1,2个轴正交的平面中方差最大的。依次类推,可以得到n个这样的坐标轴。通过这种方式获得的新的坐标轴,我们发现,大部分方差都包含在前面k个坐标轴中,后面的坐标轴所含的方差几乎为0。于是,我们可以忽略余下的坐标轴,只保留前面k个含有绝大部分方差的坐标轴。事实上,这相当于只保留包含绝大部分方差的维度特征,而忽略包含方差几乎为0的特征维度,实现对数据特征的降维处理。
基(变换矩阵,由特征向量组成)*需要降维的数据矩阵=降维的数据矩阵
【我们要明白我们要做的,比如原始数据矩阵是n*4,我们要变换成n*2,这,变换矩阵是4*2即可,(n*4)*(4*2)=(n*2),因此我们要求出满足我们条件的最好的特征向量】
矩阵的乘法,两个矩阵相乘,将右边矩阵的每一列列向量变换到左边矩阵中每一行行向量为基所表示的空间中去。
性质:一个n*n的实对称矩阵一定可以找到n个单位正交特征向量(基)。实对称矩阵可以对角化,根据特征值的从大到小,将特征向量,从上向下排列(因为特征值越大,特征向量越重要),则用前k行组成的矩阵乘以原始矩阵X,就得到我们需要降维的数据矩阵Y。
摘录一下公式:
PCA降维代码样例:
import numpy as np
import pandas as pd
df = pd.read_csv('iris.data') # 鸢尾花数据集
# df.head()
df.columns=['sepal_len', 'sepal_wid', 'petal_len', 'petal_wid', 'class']
# df.head()
得到的数据样式如下:
数据可视化展示:
from matplotlib import pyplot as plt
import math
X = df.ix[:,0:4].values # 表象特征值
y = df.ix[:,4].values # 花的种类
label_dict = {1: 'Iris-Setosa',
2: 'Iris-Versicolor',
3: 'Iris-Virgnica'}
feature_dict = {0: 'sepal length [cm]',
1: 'sepal width [cm]',
2: 'petal length [cm]',
3: 'petal width [cm]'}
plt.figure(figsize=(8, 6))
# 下边就是针对每一列特征值的不同种类别,一个类别一个类别的,一张一张的画图
for cnt in range(4):
plt.subplot(2, 2, cnt+1)
for lab in ('Iris-setosa', 'Iris-versicolor', 'Iris-virginica'):
plt.hist(X[y==lab, cnt],
label=lab,
bins=10,
alpha=0.3,)
plt.xlabel(feature_dict[cnt]) # x轴标题
plt.legend(loc='upper right', fancybox=True, fontsize=8) # 右上角标志
plt.tight_layout() # 自动调节图图间距
plt.show()
可视化效果:
先标准化(归一化)
from sklearn.preprocessing import StandardScaler
X_std = StandardScaler().fit_transform(X) # 标准化
mean_vec = np.mean(X_std, axis=0) # axis=0将得到按列计算的均值
cov_mat = (X_std - mean_vec).T.dot((X_std - mean_vec)) / (X_std.shape[0]-1)
# 按照公式代入得到协方差矩阵
print('Covariance matrix \n%s' %cov_mat)
print('NumPy covariance matrix: \n%s' %np.cov(X_std.T)) # 也可以直接用已有的求解方法
cov_mat = np.cov(X_std.T)
# 此处传入X_std.T,转置矩阵,是因为该函数的默认情况,矩阵的行代表属性,列代表观测值,cov()函数具体参数见下
eig_vals, eig_vecs = np.linalg.eig(cov_mat) # 求特征值和特征向量
print('Eigenvectors \n%s' %eig_vecs)
print('\nEigenvalues \n%s' %eig_vals)
特征值特征向量输出如下:
# 特征值和特征向量之间是一一对应的关系,具体可以查看输出结果
# Make a list of (eigenvalue, eigenvector) tuples
eig_pairs = [(np.abs(eig_vals[i]), eig_vecs[:,i]) for i in range(len(eig_vals))]
print (eig_pairs)
print ('----------')
# Sort the (eigenvalue, eigenvector) tuples from high to low
eig_pairs.sort(key=lambda x: x[0], reverse=True)
# Visually confirm that the list is correctly sorted by decreasing eigenvalues
print('Eigenvalues in descending order:')
for i in eig_pairs:
print(i[0])
输出元祖如下:
cov函数详解:
cov(m, y=None, rowvar=True, bias=False, ddof=None, fweights=None,aweights=None)
m:一维或则二维的数组,默认情况下每一行代表一个变量(属性),每一列代表一个观测
y:与m具有一样的形式的一组数据
rowvar:默认为True,此时每一行代表一个变量(属性),每一列代表一个观测;为False时,则反之
bias:默认为False,此时标准化时除以n-1;反之为n。其中n为观测数
ddof:类型是int,当其值非None时,bias参数作用将失效。当ddof=1时,将会返回无偏估计(除以n-1),即使指定了fweights和aweights参数;当ddof=0时,则返回简单平均值。
frequency weights:一维数组,代表每个观测要重复的次数(相当于给观测赋予权重)
analytic weights:一维数组,代表观测矢量权重。对于被认为“重要”的观察,这些相对权重通常很大,而对于被认为不太重要的观察,这些相对权重较小。如果ddof = 0,则可以使用权重数组将概率分配给观测向量。
tot = sum(eig_vals)
var_exp = [(i / tot)*100 for i in sorted(eig_vals, reverse=True)]
print (var_exp) # 求各特征值占比
cum_var_exp = np.cumsum(var_exp) #输出每一个值与前一个和值的加和
print(cum_var_exp)
plt.figure(figsize=(6, 4))
plt.bar(range(4), var_exp, alpha=0.5, align='center',
label='individual explained variance')
plt.step(range(4), cum_var_exp, where='mid',
label='cumulative explained variance')
plt.ylabel('Explained variance ratio')
plt.xlabel('Principal components')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
按照较大的特征值,取得对应的特征向量,并组合,得到了4*2的矩阵:
matrix_w = np.hstack((eig_pairs[0][1].reshape(4,1),
eig_pairs[1][1].reshape(4,1)))
print('Matrix W:\n', matrix_w)
输出:
Y = X_std.dot(matrix_w) #目标降维数据,下面进行展示
plt.figure(figsize=(6, 4))
for lab, col in zip(('Iris-setosa', 'Iris-versicolor', 'Iris-virginica'),
('blue', 'red', 'green')):
plt.scatter(X[y==lab, 0],
X[y==lab, 1],
label=lab,
c=col)
plt.xlabel('sepal_len')
plt.ylabel('sepal_wid')
plt.legend(loc='best')
plt.tight_layout()
plt.show()
plt.figure(figsize=(6, 4))
for lab, col in zip(('Iris-setosa', 'Iris-versicolor', 'Iris-virginica'),
('blue', 'red', 'green')):
plt.scatter(Y[y==lab, 0],
Y[y==lab, 1],
label=lab,
c=col)
plt.xlabel('Principal Component 1')
plt.ylabel('Principal Component 2')
plt.legend(loc='lower center')
plt.tight_layout()
plt.show()
PCA降维后,数据不再具有物理意义或者真实意义,很难说某列属性数据代表什么具体属性了。