没有运行时错误,但虹膜 PCA 绘图错误

Posted

技术标签:

【中文标题】没有运行时错误,但虹膜 PCA 绘图错误【英文标题】:No runtime error, but wrong iris PCA plotting 【发布时间】:2018-09-19 01:58:58 【问题描述】:

我正在使用以下代码对 iris 数据集执行 PCA:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns 

# get iris data to a dataframe: 
from sklearn import datasets
iris = datasets.load_iris() 
varnames = ['SL', 'SW', 'PL', 'PW']
irisdf = pd.DataFrame(data=iris.data, columns=varnames)
irisdf['Species'] = [iris.target_names[a] for a in iris.target]

# perform pca: 
from sklearn.decomposition import PCA
model = PCA(n_components=2)
scores = model.fit_transform(irisdf.iloc[:,0:4])
loadings = model.components_

# plot results: 
scoredf = pd.DataFrame(data=scores, columns=['PC1','PC2'])
scoredf['Grp'] = irisdf.Species
sns.lmplot(fit_reg=False, x="PC1", y='PC2', hue='Grp', data=scoredf) # plot point; 
loadings = loadings.T
for e, pt in enumerate(loadings):
    plt.plot([0,pt[0]], [0,pt[1]], '--b') 
    plt.text(x=pt[0], y=pt[1], s=varnames[e], color='b')
plt.show()

我得到以下情节:

但是,当我与其他网站(例如 http://marcoplebani.com/pca/ )的图进行比较时,我的图不正确。似乎存在以下差异:

    花瓣长度和花瓣宽度线的长度应该相似。 萼片长度线应该更接近花瓣长度和花瓣宽度线,而不是接近萼片宽度线。 所有 4 条线应位于 x 轴的同一侧。

为什么我的情节不正确。错误在哪里,如何纠正?

【问题讨论】:

我对 PCA 的技术细节了解得不够多,所以我不能肯定地说,但这可能会发生,因为加载的迹象和 PCA 的分数是任意的。这是一个参考:ncbi.nlm.nih.gov/pmc/articles/PMC4792409 参考文献中的相关部分:“如果特征向量乘以 -1,则等式 (2.1) 仍然有效,因此所有载荷(和分数)的符号是任意的,只有它们的相对大小和符号模式是有意义的。” 【参考方案1】:

这取决于您是否缩放方差。 “其他站点”使用scale=TRUE。如果您想使用 sklearn 执行此操作,请在拟合模型之前添加 StandardScaler,并使用缩放数据拟合模型,如下所示:

from sklearn.preprocessing import StandardScaler
X = StandardScaler().fit_transform(irisdf.iloc[:,0:4])
scores = model.fit_transform(X)

编辑:StandardScalernormalize 之间的区别

这里是an answer,它指出了一个关键区别(行与列)。即使您在这里使用normalize,您也可能需要考虑X = normalize(X.T).T。以下代码展示了转换后的一些差异:

import pandas as pd
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler, normalize

iris = datasets.load_iris() 
varnames = ['SL', 'SW', 'PL', 'PW']

fig, ax = plt.subplots(2, 2, figsize=(16, 12))

irisdf = pd.DataFrame(data=iris.data, columns=varnames)
irisdf.plot(kind='kde', title='Raw data', ax=ax[0][0])

irisdf_std = pd.DataFrame(data=StandardScaler().fit_transform(irisdf), columns=varnames)
irisdf_std.plot(kind='kde', title='StandardScaler', ax=ax[0][1])

irisdf_norm = pd.DataFrame(data=normalize(irisdf), columns=varnames)
irisdf_norm.plot(kind='kde', title='normalize', ax=ax[1][0])

irisdf_norm = pd.DataFrame(data=normalize(irisdf.T).T, columns=varnames)
irisdf_norm.plot(kind='kde', title='normalize', ax=ax[1][1])

plt.show()

我不确定算法/数学能走多远。 StandardScaler 的重点是在特征之间获得统一/一致的均值和方差。假设是具有大测量单位的变量不一定(也不应该)在 PCA 中占主导地位。换句话说,StandardScaler 使功能对 PCA 做出同等贡献。如您所见,normalize 不会给出一致的均值或方差。

【讨论】:

是的,这似乎是原因。我不知道为什么你的回答得到了反对票。我之前曾尝试使用from sklearn.preprocessing import normalize; X = normalize(X) 进行缩放,但结果不同。为什么不正确? @rnso 感谢您确认我的回答很有帮助。我更新了我的答案,试图解决StandardScalernormalize 之间的区别。尽管StandardScaler 更常见且更“标准”,但我认为使用哪一个仍取决于您和您的数据。 您可能应该使用sklearn.pipeline.make_pipeline(StandardScaler(), model) 来避免数据窥探 @eickenberg 感谢您的 cmets。我对“数据窥探”或“泄漏”不太熟悉。你能解释一下吗?或者指出一些学习的起点。 如果您想将数据拆分为训练集和测试集以用于某些机器学习方法,那么您不应该在拆分前进行标准化,而是估计训练集的均值和标准差并使用它们进行标准化测试集。也许您对预测不感兴趣 - 在这种情况下,请忽略此评论。我向任何想要干净利落地做预测模型的人指出这一点。

以上是关于没有运行时错误,但虹膜 PCA 绘图错误的主要内容,如果未能解决你的问题,请参考以下文章

Npm test 抛出错误,但应用程序运行时没有错误

OpenCV 3 中的 PCA 错误

无法在 Visual Studio 中使用 seaborn 绘图功能

运行时错误 91 没有意义

C 程序适用于我,但在线显示运行时错误

代码在控制台中完美运行,但出现错误:编织到 pdf 时没有要聚合的行