sklearn的PCA
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sklearn的PCA相关的知识,希望对你有一定的参考价值。
参考技术A 1.1 维度对于数组和series来说,维度就是shape返回的结果,shape中返回几个数字就是几维。对图像来说,维度就是图像中特征向量的数量。降维算法中的”降维“,指的是降低特征矩阵中特征的数量。
1.2 sklearn中的降维算法
sklearn中的降维算法在模块decomposition中,这个模块的本质是一个矩阵分解模块。矩阵分解可以用在降维,深度学习,聚类分析,数据预处理,低纬度特征学习,推荐系统,大数据分析等领域。 SVD和主成分分析PCA都是通过分解特征矩阵来进行降维的 。
1.3 PCA
在降维的过程中,将会减少特征的数量,这意味着删除部分数据,数据量变少则表示模型可获取的信息变少了,模型的表现可能会因此受到影响。同时,在高维数据中,必然也有一些特征是不带有效信息的(噪音),或是有一些特征带有的信息和其他一些特征是重复的(一些特征之间可能会线性相关)。我们希望在降维的过程中,既能减少特征的数量又保留大部分有效信息,那就将带有重复信息的特征合并,并删除那些带有无效信息的特征,创建出一个能携带大部分信息,特征更少的特征矩阵。
在降维中,PCA使用的信息量衡量指标是样本方差,又称可解释性方差,方差越大,特征携带的信息量越多。
var代表一个特征的方差,n代表样本量,xi代表一个特征中每个样本的取值,xhat代表这一列样本的均值。
1.4 降维的实现
步骤3中,我们用来找出n个新特征向量,让数据能够被压缩到少数特征上并且中信息量不损失太多的技术就是矩阵分解,PCA与SVD是两种不同的降维算法,但是都遵从上面的过程来降维,只是两种算法的矩阵分解的方法不同,信息量的衡量指标不同。PCA使用方差作为信息量的衡量指标,并且使用特征值分解来找出空间V。降维时,它会产生协方差矩阵 将特征矩阵分解为以下三个矩阵,其中Q和 是辅助的矩阵, 是一个对角矩阵(除对角线上有值,其他位置都是0的矩阵),其对角线上的元素就是方差,降维完成之后,PCA找到的每个新特征向量就叫做“主成分”,而被丢弃的特征向量被认为信息量很少,这些信息很可能就是噪音。
SVD使用奇异值分解来找出空间V,其中Σ也是一个对角矩阵,不过它对角线上的元素是奇异值,这也是SVD中用来衡量特征上的信息量的指标。U和V^T分别是左奇异矩阵和右奇异矩阵,也都是辅助矩阵。
在数学原理中,无论是PCA还是SVD都需要遍历所有的特征和样本来计算信息量指标,并且在矩阵分解的过程中,会产生比原来更大的矩阵,比如原数据的结构是(m,n),在矩阵分解中为了找出最佳新特征空间V,可能需要产生(n,n),(m,m)大小的矩阵,还需要产生协方差矩阵去计算更多的信息,因此,降维算法的计算量很大,运行比较缓慢。
PAC数据特征创造并不属于特征选择,特征选择只是从已经存在的特征中选取携带信息量最多的,选完之后特征依然具有可解释性,仍然能解释改特征在原数据集上的含义。而PCA是将已经存在的特征进行压缩,降维后的特征不是原特征矩阵中的任何一个特征,而是通过某些方式组合起来的新特征。在新的特征矩阵生成之前,我们无法得知PCA是建立在怎么样的新特征向量上,所以新特征矩阵生成之后不再具有可读性,我们无法判断新特征矩阵的特征是从原数据中的什么特征组合而来,新特征虽然带有原始数据的信息,却已经不是原数据上代表着的含义了。PCA一般不适用于探索特征和标签之间的关系的模型(如线性回归),因为无法解释的新特征和标签之间的关系不具有意义。
1.5 sklearn.decomposition.PCA
class sklearn.decomposition.PCA (n_components=None, copy=True, whiten=False, svd_solver=’auto’, tol=0.0,iterated_power=’auto’, random_state=None)
n_components就是降维后需要保留的特征数量,即降维流程中第二步里面需要确认的k值,一般输入[0,min(X.shape)]范围中的整数,k的值会影响到模型的表现,如果k值太大,留下的特征太多,达不到降维的效果,如果k值太小,留下的特征太少,那新特征向量可能无法容纳原始数据集中的大部分信息。n_components取值如何选呢?
a. 选择最好的n_components:累积可解释方差贡献率曲线。
当参数n_components中不填写任何值,则默认返回min(X.shape)个特征,一般来说,样本量都会大于特征数目,所以什么都不填就相当于转换了新特征空间,但没有减少特征的个数。一般来说,不会使用这种输入方式。但我们却可以使用这种输入方式来画出累计可解释方差贡献率曲线,以此选择最好的n_components的整数取值。累计可解释方差贡献率曲线是一天以降维后保留的特征个数为横坐标,降维后新特征捕捉到的可解释方差贡献率为纵坐标的曲线,能帮助我们决定n_components的最好取值.
b.最大似然估计自选超参数
PCA用最大似然估计(maximum likelihoodestimation)自选超参数的方法,输入“mle”作为n_components的参数输入,就可以调用这种方法。
c.按信息量占比选超参数
输入[0,1]之间的浮点数,并且让参数svd_solver =='full',表示希望降维后的总解释性方差占比大于n_components指定的百分比,即是说,希望保留百分之多少的信息量。比如说,如果我们希望保留97%的信息量,就可以输入n_components = 0.97,PCA会自动选出能够让保留的信息量超过97%的特征数量
svd_solver是奇异值分解器的意思,PCA中为什么会有关奇异值分解的参数呢?SVD有一个惊人的数学性质,它能跳过数学神秘宇宙,不计算协方差矩阵,直接找出一个新特征向量组成的n维空间,而这个n维空间就是奇异值分解后的右矩阵 (就是降维过程中所说的生成新特征向量组成的空间V,并非巧合,而特指奇异值分解中的矩阵 )
右奇异矩阵 有着如下性质:
k就是n_compoents,是我们降维后希望得到的维度。若X为(m,n)的特征矩阵, 就是结构为(n,n)的矩阵,取这个矩阵的前k行(进行切片),即将V转化为结构是(k,n)的矩阵。而 与原矩阵X相乘,即可得到降维后的特征矩阵X_dr, 这是说,奇异值分解可以不计算协方差矩阵等等结构复杂计算冗长的矩阵,就直接求出新特征空间和降维后的特征矩阵。
简而言之,SVD在矩阵分解中的过程比PCA简单快速,但是遗憾的是,SVD的信息量衡量指标比较复杂,要理解”奇异值“远不如理解”方差“来得容易,因此,sklearn将降维流程拆分为了两部分,一部分是计算特征空间的V,由奇异值分解完成,另一部分是映射数据和求解新特征矩阵,由主成分分析完成,实现了用SVD的性质减少计算量,却让信息量的评估指标是方差,具体的流程如下图:
1.6 重要参数 svd_solver与random_state
参数svd_solver是在降维过程中,用来控制矩阵分解的一些细节的参数。有四种模式可选:"auto", "full", "arpack","randomized",默认”auto"。
1.'auto':基于X.shape和n_compoents的默认策略来选择分解器,如果输入数据的尺寸大于500X500且要提取的特征小于数据最小维度的min(X.shape)的80%,就用效果更高的‘randomized’方法,否则就精确完整的SVD将被计算,截断将会在矩阵被分解完成后有选择的发生。
2.‘full’:从scipy.linalg.svd中调用标准的LAPACK分解器来生成精确完整的SVD,适合数据量比较适中,计算时间充足的情况,生成的精确完整的SVD的结构为:
3.‘arpack’:从scipy.sparse.linalg.svds调用ARPACK分解器来运行截断奇异值分解(SVD truncated),分解时就将特征数量降到n_components中输入的数值k,可以加快运算速度,适合特征矩阵很大的时候,但一般用于特征矩阵为稀疏矩阵的情况,此过程包含一定的随机性。截断后的SVD分解出的结构为:
4.‘randomized’:通过Halko等人的随机方法进行随机SVD。在"full"方法中,分解器会根据原始数据和输入的n_components值去计算和寻找符合需求的新特征向量,但是在"randomized"方法中,分解器会先生成多个随机向量,然后一一去检测这些随机向量中是否有任何一个符合我们的分解需求,如果符合,就保留这个随机向量,并基于这个随机向量来构建后续的向量空间。这个方法已经被Halko等人证明,比"full"模式下计算快很多,并且还能够保证模型运行效果。适合特征矩阵巨大,计算量庞大的情况。
而参数random_state在参数svd_solver的值为"arpack" or "randomized"的时候生效,可以控制这两种SVD模式中的随机模式。通常我们就选用”auto“,不必对这个参数纠结太多。
使用 sklearn 提取 PCA 组件
【中文标题】使用 sklearn 提取 PCA 组件【英文标题】:Extracting PCA components with sklearn 【发布时间】:2014-04-03 07:37:45 【问题描述】:我正在使用sklearn's PCA 对大量图像进行降维处理。安装 PCA 后,我想看看组件是什么样子。
可以通过查看components_
属性来做到这一点。没有意识到这是可用的,我做了其他事情:
each_component = np.eye(total_components)
component_im_array = pca.inverse_transform(each_component)
for i in range(num_components):
component_im = component_im_array[i, :].reshape(height, width)
# do something with component_im
换句话说,我在 PCA 空间中创建了一个图像,其中除了 1 之外的所有特征都设置为 0。通过对它们进行逆变换,我应该得到原始空间中的图像,一旦变换,就可以单独用那个 PCA 组件。
下图显示了结果。左边是使用我的方法计算的分量。右边直接是pca.components_[i]
。此外,使用我的方法,大多数图像非常相似(但它们不同),而通过访问components_
,图像与我预期的非常不同
我的方法是否存在概念问题?显然来自pca.components_[i]
的组件比我得到的组件正确(或至少更正确)。谢谢!
【问题讨论】:
【参考方案1】:分量和逆变换是两个不同的东西。逆变换将分量映射回原始图像空间
#Create a PCA model with two principal components
pca = PCA(2)
pca.fit(data)
#Get the components from transforming the original data.
scores = pca.transform(data)
# Reconstruct from the 2 dimensional scores
reconstruct = pca.inverse_transform(scores )
#The residual is the amount not explained by the first two components
residual=data-reconstruct
因此,您是在对原始数据而不是组件进行逆变换,因此它们是完全不同的。您几乎从不对原始数据进行逆转换。 pca.components_ 是表示用于将数据投影到 pca 空间的基础轴的实际向量。
【讨论】:
感谢您的回答。也许我们有一个误解:我不是在对原始数据进行逆变换,而是一个除一个位置外全为零的向量。在这样做时,我希望我正在对图像[0,0,...,0,1,0,...,0]
进行逆变换,该图像必须来自看起来像组件的原始图像【参考方案2】:
在单位矩阵上获取components_
和执行inverse_transform
之间的区别在于后者添加了每个特征的经验平均值。即:
def inverse_transform(self, X):
return np.dot(X, self.components_) + self.mean_
self.mean_
是从训练集中估计出来的。
【讨论】:
宾果游戏。不知道为什么不早点自己看源码。谢谢!但是,平均值在 PCA._fit(X) 中计算为self.mean_ = np.mean(X, axis=0)
,其中 X 是 n_samples
行和 n_features
列的数组,因此平均值是每个特征的特征平均值,所以这是当然可能会主导组件实际具有的任何贡献,这就是所有图像看起来几乎相同的原因。全部解释清楚,谢谢!以上是关于sklearn的PCA的主要内容,如果未能解决你的问题,请参考以下文章