Python 为什么sklearn';s训练/测试分割加PCA使我的标签不正确?

Python 为什么sklearn';s训练/测试分割加PCA使我的标签不正确?,python,pandas,scikit-learn,pca,Python,Pandas,Scikit Learn,Pca,我正在Scikit learn(Python 3上的0.20)中探索PCA,使用Pandas构建数据。当我应用测试/训练分割时(仅当),我的输入标签似乎不再与PCA输出匹配 import pandas import sklearn.datasets from matplotlib import pyplot import seaborn def load_bc_as_dataframe(): data = sklearn.datasets.load_breast_cancer()

我正在Scikit learn(Python 3上的0.20)中探索PCA,使用Pandas构建数据。当我应用测试/训练分割时(仅当),我的输入标签似乎不再与PCA输出匹配

import pandas
import sklearn.datasets
from matplotlib import pyplot
import seaborn

def load_bc_as_dataframe():
    data = sklearn.datasets.load_breast_cancer()
    df = pandas.DataFrame(data.data, columns=data.feature_names)
    df['diagnosis'] = pandas.Series(data.target_names[data.target])
    return data.feature_names.tolist(), df

feature_names, bc_data = load_bc_as_dataframe()

from sklearn.model_selection import train_test_split
# bc_train, _ = train_test_split(bc_data, test_size=0)
bc_train = bc_data

from sklearn.decomposition import PCA
pca = PCA(n_components=2)
bc_pca_raw = pca.fit_transform(bc_train[feature_names])
bc_pca = pandas.DataFrame(bc_pca_raw, columns=('PCA 1', 'PCA 2'))
bc_pca['diagnosis'] = bc_train['diagnosis']

seaborn.scatterplot(
    data=bc_pca,
    x='PCA 1',
    y='PCA 2',
    hue='diagnosis',
    style='diagnosis'
)

pyplot.show()

这看起来很合理,准确的分类结果也证明了这一点。如果我将
bc\u train=bc\u data
替换为
train\u test\u split()
调用(即使使用
test\u size=0
),我的标签似乎不再与原始标签对应

我意识到
train\u test\u split()
正在洗牌我的数据(通常我希望它洗牌),但我不明白为什么会有问题,因为PCA和标签分配使用相同的洗牌数据。PCA的变换只是一个投影,虽然它显然不保留相同的特征(列),但它不应该改变哪个标签与哪个帧匹配


如何正确重新标记PCA输出?

问题分为三个部分:

  • train\u test\u split()
    中的洗牌导致
    bc\u train
    中的索引以随机顺序排列(与行位置相比)
  • PCA对数值矩阵进行操作,并有效地从输入中去除索引。创建新的
    DataFrame
    将重新创建顺序索引(与行位置相比)
  • 现在我们在
    bc\u序列中有随机索引
    ,在
    bc\u pca中有顺序索引
    。当我做
    bc\u pca['diagnosis']=bc\u train['diagnosis']
    时,
    bc\u train
    带有
    bc\u pca
    s索引。这将对
    bc_序列
    数据进行重新排序,使其索引与
    bc_pca
    s匹配
  • 换句话说,当我使用
    bc\u pca['diagnosis']
    (即
    \uuuuu setitem\uuuuu()
    )赋值时,Pandas在索引上进行左连接,而不是逐行复制(类似于

    我不觉得这很直观,我也找不到源代码以外的
    \uuuu setitem\uuu()
    行为文档,但我希望它对更有经验的Pandas用户来说是有意义的,也许它是在一个我从未见过的更高级别的地方被记录的

    有很多方法可以避免这种情况。我可以重置培训/测试数据的索引:

    bc_train, _ = train_test_split(bc_data, test_size=0)
    bc_train.reset_index(inplace=True)
    
    或者,我可以从
    成员分配值:

    bc_pca['diagnosis'] = bc_train['diagnosis'].values
    
    在构建数据帧之前,我也可以做类似的事情(可以说更合理,因为PCA在
    bc\u列[feature\u names].值上有效运行)。

    相关: