Python机器学习实战:维数约简的6种常⽤⽅法
机器学习实战:这⾥没有艰深晦涩的数学理论,我们将⽤简单的案例和⼤量的⽰例代码,向⼤家介绍机器学习的核⼼概念。我们的⽬标是教会⼤家⽤Python构建机器学习模型,解决现实世界的难题。
为什么要约简维数?
当数据集包含⼤量特征,有的特征包含⼤量预测信息,有的仅包含少量信息或纯粹是噪⾳,很多特征之间也可能⾼度相关。维数约简的⽬的在于剔除噪⾳,只保留有意义的特征,这不仅使数据集更容易管理和理解,预测模型的准确性也会相应提⾼。
常⽤⽅法有哪些?
1. 相关系数矩阵
2. 主成分分析
3. 随机PCA
4. 因⼦分析
5. 线性判别分析
6. 核PCA
1. 相关系数矩阵
[−1,1]
相关系数:度量数值变量同向/反向运动的关联程度,取值范围,1表⽰完全正相关,-1表⽰完全负相关,0表⽰线性⽆关。
Python实现:pd.corr(), np.corrcoef()⽤于计算相关系数矩阵,sns.heatmap()创建热⼒图可视化。
解读:如果两个特征⾼度相关,可以保留其中⼀个,尽可能保留相互独⽴的变量。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.style.use("ggplot")
使⽤iris数据集。
from sklearn.datasets import load_iris
iris = load_iris()
iris_df = pd.DataFrame(iris.data, columns=iris.feature_names)
iris_df.head()
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)
0  5.1  3.5  1.40.2
1  4.9  3.0  1.40.2
2  4.7  3.2  1.30.2
random在python中的意思
3  4.6  3.1  1.50.2
4  5.0  3.6  1.40.2
计算相关系数矩阵。
cor_matrix = ()
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)
sepal length (cm)  1.00-0.120.870.82
sepal width (cm)-0.12  1.00-0.43-0.37
petal length (cm)0.87-0.43  1.000.96
petal width (cm)0.82-0.370.96  1.00
创建热⼒图,可视化相关系数矩阵。
fig, ax = plt.subplots(figsize=(10,8))
ax = sns.heatmap(
cor_matrix,
annot=True,# 将数值添加到单元格
vmin=-1,# 根据数值范围调整颜⾊区间
vmax=1,
center=0,
linewidths=0.5,# 控制单元格之间的间隙
#mask=np.abs(cor_matrix) < 0.6,  # 仅显⽰相关系数⼤于0.6的单元格
ax=ax
)
热⼒图显⽰,sepal length和petal length,petal width⾼度正相关,petal length和petal width⾼度相关。所以,可以考虑剔除petal length和petal width两个特征。
这个简单的例⼦仅⽤于说明如何⽤相关系数矩阵约简维数,考虑到原始数据只有4个特征,完全没有必要约简维数。
2. 主成分分析
主成分分析(PCA)是最常⽤的降维技术之⼀,它把⼤量相关变量转化为⼏组⽆关变量,这些⽆关变量称为“主成分”。
sklearn提供接⼝PCA类实现主成分分析。
拟合PCA模型前要先选择约简维数,即主成分个数,有两种常⽤⽅法:1. 参考相关⽂献的研究成果;2. 从相关系数矩阵获得启发。
from sklearn.decomposition import PCA
# 选择主成分个数,这⾥选择2
pca = PCA(n_components=2)
res = pca.fit_transform(iris_df)
print("original shape: ", iris_df.shape)
print("transformed shape: ", res.shape)
original shape:  (150, 4)
transformed shape:  (150, 2)
调⽤pca.fit_transform得到⼀个n维数组,每⼀列代表⼀个“主成分”,它们是原始特征的线性组合。
第⼀个主成分对原始数据的变异(⽅差)解释最⼤,第⼆个主成分与第⼀个主成分正交(⽆相关关系),它包含了剩余变异的⼤部分,第三个主成分与前两个主成分正交,并包含剩余变异的⼤部分,以此类推。
res[:5,:]
array([[-2.68412563,  0.31939725],
[-2.71414169, -0.17700123],
[-2.88899057, -0.14494943],
[-2.74534286, -0.31829898],
[-2.72871654,  0.32675451]])
⽤散点图查看主成分的关系,它们是线性⽆关的。
fig, ax = plt.subplots(figsize=(10,7))
ax = plot(x=res[:,0], y=res[:,1], scatter=True, fit_reg=False, ax=ax)
ax.set_xlabel("First Main Component")
ax.set_ylabel("Second Main Component")
explained_variance_ratio_包含了所有主成分对原始数据⽅差的解释⽐率。降维不可避免地损失了原始数据的部分信息,降维的同时要尽可能多地保留信息。
var_ratio = plained_variance_ratio_
for idx, val in enumerate(var_ratio,1):
print("principle component %d: %.2f%%"%(idx, val *100))
print("total: %.2f%%"% np.sum(var_ratio *100))
principle component 1: 92.46%
principle component 2: 5.31%
total: 97.77%
主成分个数等于2,就保留了原始数据集约98%的变异。
除了根据经验或相关系数矩阵外,可以⽤数据挖掘的⽅法选择主成分个数。拟合PCA模型时令主成分个数等于原始特征的数⽬,然后查看主成分的累积解释⽅差⽐率,选择令⼈满意的临界点对应的主成分个数。
# n_components=None, 主成分个数等于原始特征的数量
pca2 = PCA(n_components=None)
pca2.fit(iris_df)
evr = plained_variance_ratio_ *100
for idx, val in enumerate(evr,1):
print("principle component %d: %.2f%%"%(idx, val))
print("total: %.2f%%"% np.sum(evr))
fig, ax = plt.subplots(figsize=(10,7))
ax.plot(np.arange(1,len(evr)+1), np.cumsum(evr),"r-o")
ax.set_title("Cumulative Explained Variance Ratio")
ax.set_xlabel("Number of components")
ax.set_ylabel("Explained Variance Ratio(%)")
principle component 1: 92.46%
principle component 2: 5.31%
principle component 3: 1.71%
principle component 4: 0.52%
total: 100.00%
也可以先选择最低的累计解释⽅差⽐率,让模型⾃动选择最优的主成分个数。
target =0.95# 最低累计解释⽅差⽐率
res = PCA(n_components=target).fit_transform(iris_df)
res[:5,:]
array([[-2.68412563,  0.31939725],
[-2.71414169, -0.17700123],
[-2.88899057, -0.14494943],
[-2.74534286, -0.31829898],
[-2.72871654,  0.32675451]])
3. 随机PCA
PCA类默认使⽤奇异值分解算法(SVD),处理⼤数据时速度很慢,Randomized PCA采取基于随机SVD的算法,计算速度⾮常快,结果与经典SVD差异不⼤,特别适⽤于⼤型数据集。
先创建⼀个虚拟⼤型数据集,然后分别使⽤经典SVD和随机SVD算法,对⽐计算时间和最终结果。
from sklearn.datasets import make_classification
from sklearn.decomposition import PCA
X, y = make_classification(
n_samples=10000,# 10000个观测值
n_features=1000,# 1000个特征
n_informative=100,# 100个有预测作⽤的特征
n_redundant=900,# 900个冗余的特征
n_classes=2,# ⽬标变量有两个类别
random_state=123
)
评估经典SVD算法需要的时间。
%%time
pca_svd = PCA(n_components=50, svd_solver="full")
res_svd = pca_svd.fit_transform(X)
CPU times: user 3.26 s, sys: 63.1 ms, total: 3.33 s
Wall time: 665 ms
评估随机SVD算法需要的时间。
%%time
pca_rsvd = PCA(n_components=50, svd_solver="randomized", random_state=123)
res_rsvd = pca_rsvd.fit_transform(X)
CPU times: user 1.36 s, sys: 97.9 ms, total: 1.46 s
Wall time: 316 ms
对⽐主成分和累计解释⽅差⽐率。
print(res_svd[:5,:5])
print(np.sum(plained_variance_ratio_))
[[ -35.31540007  -39.98628806 -274.32980501  -27.4946712    77.54435473]
[-107.77935017  37.53502538 -159.77096307  131.49349957  25.25804827]
[ 108.37551655  -15.40239858  -62.96425787 -132.79963657  -63.94973487]
[-105.79569613  358.60693594  24.7166602  -17.55204505  134.10581326]
[-117.80092422  56.90329203 -333.89478323 -105.58694003 -203.47273697]]
0.7461276067240424
print(res_rsvd[:5,:5])
print(np.sum(plained_variance_ratio_))
[[ -35.31811083  -39.98782647 -274.3356045  -27.49536884  77.58832675]
[-107.77688031  37.53173418 -159.76762465  131.50093451  25.2763213 ]
[ 108.37756582  -15.40584496  -62.95926132 -132.81009813  -63.95606976]
[-105.79345418  358.60456052  24.71247005  -17.5314516  134.07833206]
[-117.80396459  56.90223403 -333.90297705 -105.57181181 -203.4748604 ]]
0.7456404795597943
结果对⽐显⽰,随机SVD算法耗费的时间显著低于SVD,主成分和累计解释⽅差⽐率的差异⾮常⼩。
4. 因⼦分析
因⼦分析(Factor Analysis):假设原始特征同时受到"潜在变量"的影响,因⼦分析旨在提权潜在因⼦。PCA和FA的区别是什么?
两种⽅法都⽤于降维,但它们的核⼼原理是不同的。PCA根据原始特征集创建主成分,每⼀个主成分都是特征的线性组合,FA旨在从原始特征中挖掘潜在因⼦,这些潜在因⼦同时影响多个特征并导致变量相关。
如下图所⽰,左边的图表描述了PCA的原理,右边的图表描述了FA的原理。
也可以⽤数学公式简单描述两种⽅法的降维原理,假设有4个特征:⽤PCA创建两个主成分:
是主成分,是加权因⼦,主成分是所有特征的线性组合。
⽤FA提取两个潜在因⼦:
是潜在因⼦,是加权因⼦,代表没有被潜在因⼦解释的其它因素,理解为随机冲击。
假设iris有两个潜在因⼦,采⽤因⼦分析降维。
Sklearn提供FactorAnalysis类实现,建模步骤与PCA⾮常相似,先选择潜在因⼦的数量,拟合模型并旋转,最后输出结果。
from  sklearn .decomposition import  FactorAnalysis fa = FactorAnalysis (n_components =2)fa_res = fa .fit_transform (iris_df )print (fa_res [:5, :])print (fa_res .shape )
[[-1.32761727 -0.56131076] [-1.33763854 -0.00279765] [-1.40281483  0.30634949] [-1.30104274  0.71882683] [-1.33342439 -0.36458899]](150, 2)
PCA和FA的建模步骤如此相似,⼜都⽤于降维,那么在处理实际问题时应该如何选择?答案取决于研究⽬的,经验之谈:
X ,X ,X ,X 1234C =1a ∗1X +1a ∗2X +2a ∗3X +3a ∗4X 4
C =2b ∗1X +1b ∗2X +2b ∗3X +3b ∗4X 4
C ,C 12a ,b i i X =1α∗1F +1β∗1F +2ϵ1
X =2α∗2F +1β∗2F +2ϵ2
X =3α∗3F +1β∗3F +2ϵ3
X =4α∗4F +1β∗4F +2ϵ4
F ,F 12α,βi i ϵi