没有运行时错误,但虹膜 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)
编辑:StandardScaler
和 normalize
之间的区别
这里是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 感谢您确认我的回答很有帮助。我更新了我的答案,试图解决StandardScaler
和normalize
之间的区别。尽管StandardScaler
更常见且更“标准”,但我认为使用哪一个仍取决于您和您的数据。
您可能应该使用sklearn.pipeline.make_pipeline(StandardScaler(), model)
来避免数据窥探
@eickenberg 感谢您的 cmets。我对“数据窥探”或“泄漏”不太熟悉。你能解释一下吗?或者指出一些学习的起点。
如果您想将数据拆分为训练集和测试集以用于某些机器学习方法,那么您不应该在拆分前进行标准化,而是估计训练集的均值和标准差并使用它们进行标准化测试集。也许您对预测不感兴趣 - 在这种情况下,请忽略此评论。我向任何想要干净利落地做预测模型的人指出这一点。以上是关于没有运行时错误,但虹膜 PCA 绘图错误的主要内容,如果未能解决你的问题,请参考以下文章