为何提取y=0对应PCA特征的两个命令返回不同结果?
问题描述
我有一个形状为(2250,2)的NumPy数组x_pcaed,以及一个包含2250行的Pandas DataFrameseeds_train,其中包含一列值为0或1的y列。
我执行了以下操作:
- 将
x_pcaed转换为DataFrame:pca_df = pd.DataFrame(data = x_pcaed, columns=['pr_comp_1', 'pr_comp_2']) - 拼接生成新的DataFrame:
test1 = pd.concat([pca_df, seeds_train[['y']]], axis=1)
但以下两个命令返回的结果不一致,我认为它们应该输出相同结果,肯定遗漏了某些细节:
- 命令1:
test1.loc[test1['y']==0,'pr_comp_1'].values - 命令2:
x_pcaed[seeds_train.y==0, 0]
完整代码
import pandas as pd from sklearn.model_selection import train_test_split from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler seeds = pd.read_excel('Pumpkin_Seeds_Dataset.xlsx') seeds['y'] = 0 seeds.loc[seeds.Class=='Ürgüp Sivrisi', 'y']=1 seeds_train, seeds_test = train_test_split(seeds.copy(), shuffle=True, random_state=123, test_size=.1, stratify=seeds.y.values) features = seeds_train.columns[:-2] x = seeds_train.loc[:,features].values scaler = StandardScaler() x_scaled = scaler.fit_transform(x) pca = PCA(n_components = 2) x_pcaed = pca.fit_transform(x_scaled) pca_df = pd.DataFrame(data = x_pcaed, columns=['pr_comp_1', 'pr_comp_2']) test1 = pd.concat([pca_df, seeds_train[['y']]], axis=1) print(test1.loc[test1['y']==0,'pr_comp_1'].values) print('----------') print(x_pcaed[seeds_train.y==0, 0])
输出结果
[-0.79984874 -2.75176272 -0.26329661 ... -2.03461928 -2.38149466 -1.46663563] ---------- [-1.36392527 -0.26329661 -4.91873745 ... -1.46508442 -1.07096868 -4.79462993]
问题原因
核心问题是索引不匹配:
train_test_split开启shuffle=True后,seeds_train的索引会被打乱(不再是从0开始的连续整数)。- 创建
pca_df时,Pandas会自动生成从0开始的连续默认索引。 - 使用
pd.concat拼接时,是按照索引对齐来合并数据的,这就导致pca_df里的PCA结果和seeds_train里的y值对应关系错乱了——pca_df的第i行对应原数据的第i行,但seeds_train的第i行(按索引)已经是洗牌后的另一行数据。
而x_pcaed[seeds_train.y==0, 0]是直接用seeds_train的布尔索引提取x_pcaed的行,这里x_pcaed的行顺序和seeds_train的行顺序完全一致(因为x是从seeds_train提取的,后续标准化、PCA都是按原顺序处理),所以这个结果是正确的。
解决方法
有两种可行的修正方式:
方法1:统一索引,确保拼接时行对应
可以在创建pca_df时指定其索引与seeds_train一致,或者重置seeds_train的索引:
# 方式1:创建pca_df时指定索引 pca_df = pd.DataFrame(data = x_pcaed, columns=['pr_comp_1', 'pr_comp_2'], index=seeds_train.index) test1 = pd.concat([pca_df, seeds_train[['y']]], axis=1) # 方式2:重置seeds_train的索引(丢弃原索引) seeds_train = seeds_train.reset_index(drop=True) pca_df = pd.DataFrame(data = x_pcaed, columns=['pr_comp_1', 'pr_comp_2']) test1 = pd.concat([pca_df, seeds_train[['y']]], axis=1)
方法2:用原DataFrame的布尔索引提取
如果不想修改索引,直接用seeds_train的布尔索引去取test1的对应行,就能得到和x_pcaed[seeds_train.y==0, 0]一致的结果:
test1.loc[seeds_train.y==0, 'pr_comp_1'].values
内容的提问来源于stack exchange,提问作者user21222252
相关产品推荐
相关产品推荐

