(小小:机器学习的经典算法与应用)
(小小:机器学习理论(一)KNN-k近邻算法)
(小小:机器学习理论(二)简单线性回归)
(小小:机器学习理论(三)多元线性回归)
(小小:机器学习理论(四)线性回归中的梯度下降法)
(小小:机器学习理论(五)主成分分析法)
(小小:机器学习理论(六)多项式回归)
(小小:机器学习理论(七)模型泛化)
(小小:机器学习理论(八)逻辑回归)
(小小:机器学习理论(九)分类算法的评价)
(小小:机器学习理论(十)支持向量机)
(小小:机器学习理论(十一)决策树)
(小小:机器学习理论(十二)集成学习)
(小小:机器学习理论(十三)Kmeans聚类)
一、主成分分析的理解
二、使用梯度上升法求解PCA
三、求数据的前n个主成分
四、将高维数据向低维数据映射
五、scikit-learn中的PCA
六、对真实数据集MNIST使用PCA
七、使用PCA降噪
八、PCA与人脸识别
前言
主成分分析法:(Principle Component Analysis, PCA),是一个非监督机器学习算法,主要用于数据降维,通过降维,可以发现便于人们理解的特征,其他应用:可视化和去噪等。主成分分析(Principal Component Analysis,PCA), 是一种统计方法。通过正交变换将一组可能存在相关性的变量转换为一组线性不相关的变量,转换后的这组变量叫主成分。
一、主成分分析的理解
先假设用数据的两个特征画出散点图,如果我们只保留特征1或者只保留特征2。那么此时就有一个问题,留个哪个特征比较好呢?
通过上面对两个特征的映射结果可以发现保留特征1比较好,因为保留特征1,当把所有的点映射到x轴上以后,点和点之间的距离相对较大,也就是说,拥有更高的可区分度,同时还保留着部分映射之前的空间信息。那么如果把点都映射到y轴上,发现点与点距离更近了,这不符合数据原来的空间分布。所以保留特征1相比保留特征2更加合适,但是这是最好的方案吗?
也就是说,我们需要找到让这个样本间距最大的轴?那么如何定义样本之间的间距呢?一般我们会使用方差(Variance),
第一步:将样本进行均值归0,此时
- 第二步:需要定义一个轴的方向w=(w1, w2),使得我们的样本,映射到w以后,有:
其实括号中的部分是一个向量,更加准确的描述应该是
因为前面已经去均值,所以,这里只需
设w为单位向量,
最终,
所以,最终只需
目标:求w,使得
一个目标函数优化问题,使用梯度上升法解决。
二、使用梯度上升法求解PCA
目标:求w,使得
同样,我们希望得到的是列向量对上式结果进行转置。
首先生成一组数据:
import
测试:
init_w
输出结果:array([0.84612666, 0.53298187])
w
这只是一个从2维降到1维的情况,但在实际应用中往往都不这么简单。
三、求数据的前n个主成分
求出第一主成分以后,如何求出下一个主成分?数据进行改变,将数据在第一个主成分上的分量去掉。然后在新的数据上求第一主成分。
第一步:先求出第一主成分
import
输出结果: array([0.71849226, 0.69553495])
第二步:去掉第一主成分
X2
第三步:求第二主成分
init_w2
输出结果: array([ 0.98482183, -0.17356834])
第四步:画出主成分
plt
import
输出结果:[array([0.75978266, 0.65017714]), array([ 0.96416996, -0.26528531])]
四、将高维数据向低维数据映射
假设有数据矩阵X,通过主成分分析法得到前k个主成分对应的轴的单位方向向量之后,我们就可以将数据从高维向低维映射,同样也可以从低维在映射回高维空间。
import
蓝色的点是随机初始生成,红色的点就是由pca降维之后,在从低维映射到高维的描述。其实完全可以只有一个轴来表示这些红色的点,也就完成了降维。
五、scikit-learn中的PCA
from
输出结果:array([[-0.7896098, -0.6136093]])
x_reduction
接下来使用真实的数据集进行测试:
import
接下来使用KNN先进行一个简单的测试:
%%
输出结果:Wall time: 4.88 ms
knn_clf
输出结果:0.9888888888888889
接下来使用降维:
from
输出结果:Wall time: 976 µs 相比降维之前速度快了很多。
knn_clf
输出结果:0.6055555555555555,但是测试结果的准确率大打折扣。这是因为直接从64维降到2维,损失了太多信息。在sklearn中封装了一个函数,可以看出损失的详细信息。
pca
输出结果:array([0.1450646 , 0.13714246]),可以看出这两个主成分分别损失了14.51%和13.71%,加和共损失28.22%。显然这不是想要的效果。
那么我们查看一个64个主成分分别损失情况:
pca
输出结果:
array([1.45064600e-01, 1.37142456e-01, 1.19680004e-01, 8.43768923e-02,
5.87005941e-02, 5.01797333e-02, 4.34065700e-02, 3.61375740e-02,
3.39661991e-02, 3.00599249e-02, 2.38906921e-02, 2.29417581e-02,
1.81335935e-02, 1.78403959e-02, 1.47411385e-02, 1.41290045e-02,
1.29333094e-02, 1.25283166e-02, 1.01123057e-02, 9.08986879e-03,
8.98365069e-03, 7.72299807e-03, 7.62541166e-03, 7.09954951e-03,
6.96433125e-03, 5.84665284e-03, 5.77225779e-03, 5.07732970e-03,
4.84364707e-03, 4.34595748e-03, 3.73352381e-03, 3.57655938e-03,
3.30727680e-03, 3.18129431e-03, 3.06969704e-03, 2.89170006e-03,
2.51205204e-03, 2.27743660e-03, 2.22760483e-03, 2.00065017e-03,
1.89529684e-03, 1.56877138e-03, 1.42740894e-03, 1.39115781e-03,
1.20896097e-03, 1.10149976e-03, 9.81702199e-04, 8.82376601e-04,
5.69898729e-04, 4.10322729e-04, 2.32125043e-04, 8.49807543e-05,
5.37426557e-05, 5.27990816e-05, 1.03398093e-05, 6.20749843e-06,
5.03430895e-06, 1.15881302e-06, 1.09689390e-06, 5.51564753e-07,
5.65215369e-08, 1.78867947e-33, 8.83490979e-34, 8.55393580e-34])
从上面结果可以看出,64个主成分损失从大到小排列,最大14.5%,最小8.55393580e-34可以忽略不计。接下来使用曲线图绘制一下:
plt
从图中,可以大概看出当降到30维的时候,保留信息大概在96%左右,因此可以考虑降到30为左右比较合适,既能保证精度又能保证速度。其实,sklearn中已经封装好了能够实现类似功能。
pca
输出结果:28,可以发现当损失信息为5%时,可以将数据从64维降到28维。
x_train_reduction
输出结果:Wall time: 2.93 ms
knn_clf
输出结果:0.9833333333333333
对比降维前后:
- 时间上,降维前:Wall time: 4.88 ms,降维后:Wall time: 2.93 ms
- 精度上,降维前:0.9888888888888889,降维后0.9833333333333333
通过以上对比,可以发现在精度损失0.5%的情况下速度能提高一倍。这是一个比较的维度,如果维度很大,效果会更加优秀。
在整个测试的过程中,曾尝试把数据降到2维,精度损失很大,但并不能说明这样做没有意义,通常情况下,我们会将高维数据降到3维或者2维进行可视化。
pca
通过对数据进行可视化,可以发现有蓝色、红色、紫色这些点在降到2维的情况下,依旧可以实现很高的识别度。这说明这些样本在原来的高维空间中差异就比较大。所以,一般会将数据进行可视化,进行一些简单的分析。
六、对真实数据集MNIST使用PCA
首先下载MNIST数据集的时候有个坑?
import
如果直接运行会一直报错,反正就是下载不下来,但是会在datasets目录下生成一个文件夹,./datasets/mldata。所以需要下载数据集放在这个文件夹下,再次运行就可以了。
数据集地址:
链接:https://pan.baidu.com/s/15k6Sykf5TICN40KeEc6xgQ 提取码:ujrq
mnist
输出结果:(70000, 784) (70000,)
x_train
输出结果:
Wall time: 28 s
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
metric_params=None, n_jobs=None, n_neighbors=5, p=2,
weights='uniform')
%time knn_clf.score(x_test, y_test)
输出结果:
Wall time: 11min 6s
0.9688
在这里,值得一提的是,之前讨论knn的时候,由于相比较样本之间距离,所以通常会对数据进行归一化。但是这里没用使用standardscale,因为这是图像。因为图像的像素点都在0-255,所以进行距离的比较是有意的,只有当尺度不一致时,才会考虑使用归一化。
接下来使用PCA进行降维:
from
输出结果:(60000, 87) 可以发现通过降维实现了只有87维代替原来的784维,能够保留90的信息。
from
输出结果:Wall time: 436 ms 降维前使用了28s完成现在只需436ms。
x_test_reduction
将降维前后进行对比:
- 时间上:
- 训练时间-降维前:28 s,降维后:436 ms
- 测试时间-降维前:11min 6s,降维后:1min 17s
- 精度上:降维前:0.9688,降维后:0.9728
经过上面的对比,发现经过降维之后速度提高了很多很多,而且准确率反而高了,这是为什么呢?这是因为其实降维还有另外一个作用,就是去噪。
七、使用PCA降噪
import
通过这个例子,发现pca还可以降噪,将高维数据降低到低维数据,这个过程中也可以理解成降低了维度,丢失了信息,同时也去除了噪音。为了更加直观,接下来使用手写数字识别数据集。
from
接下来使用pca去噪,
from
输出结果:12,可以看出保留50%的信息,只需要12维。
components
通过这个例子,可以对pca降维有一个感性的认识。
八、PCA与人脸识别
假设X一张人脸图像,W是钱k个主成分组成的矩阵,其实可以把W看做X的一些比较明显的特征。这就是特征脸(Eigenface)。
首先下载数据集,sklearn中的lfw_people数据集:
import
这里依旧有个小坑,就是数据下载不下来,不过没事,我们可以手动下载,复制这个网址 https://ndownloader.figshare.com/files/5976015 到迅雷中,下载到完整的lfwfunneded.tgz文件。并把这个文件放在C:UsersMogulscikit_learn_datalfw_home路径下,解压。然后再次运行就可以了。
faces
faces
输出结果:Wall time: 18.4 s
pca
刚刚提到这个数据集的样本分布是不均衡的,那么接下来看看具体:
faces2
输出结果:
array(['Ariel Sharon', 'Colin Powell', 'Donald Rumsfeld', 'George W Bush',
'Gerhard Schroeder', 'Hugo Chavez', 'Junichiro Koizumi',
'Tony Blair'], dtype='<U17')
根据输出结果可以发现,最少有60张图像的数据集一共有1348张图片,只有8个人的图像大于60,使用这样的数据进行人脸识别相对就比较合理了。
我是尾巴:
本次推荐:
轻松玩转PDF
你是如何强迫自己不断学习提升的?
看过更大的世界,更优秀的人,就再也不甘心留在原地,不甘心就是动力!
继续加油~