为什么 sklearn 的 train/test split plus PCA 使我的标签不正确?
Why does sklearn's train/test split plus PCA make my labelling incorrect?
我正在 Scikit-learn 中探索 PCA(Python 3 上的 0.20)使用 Pandas 构建我的数据。当我应用 test/train 拆分时(且仅当),我的输入标签似乎不再与 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_train = bc_data
替换为 train_test_split()
调用(即使使用 test_size=0
),我的标签似乎不再对应于原始标签。
我意识到 train_test_split()
正在改组我的数据(通常我希望这样做),但我不明白为什么这会成为问题,因为 PCA 和标签分配使用相同的混洗数据。 PCA的转换只是一个投影,虽然它显然不保留相同的特征(列),但它不应该改变哪个标签对应哪个帧。
如何正确地重新标记我的 PCA 输出?
问题分为三个部分:
train_test_split()
中的改组导致 bc_train
中的索引处于随机顺序(与行位置相比)。
- PCA 对数值矩阵进行运算,并有效地从输入中去除索引。创建新的
DataFrame
会重新创建顺序索引(与行位置相比)。
- 现在我们在
bc_train
中有随机索引,在 bc_pca
中有顺序索引。当我做 bc_pca['diagnosis'] = bc_train['diagnosis']
时,bc_train
是 reindexed 和 bc_pca
s 索引 。这将重新排序 bc_train
数据,使其索引匹配 bc_pca
s.
换句话说,当我用 bc_pca['diagnosis']
(即 __setitem__()
)分配时,Pandas 对索引进行左连接,而不是逐行复制(类似于 update()
.
我觉得这不直观,而且我找不到关于 __setitem__()
超出源代码的行为的文档,但我希望它对更有经验的 Pandas 用户有意义,也许它在我没见过的更高层次上有记录。
有很多方法可以避免这种情况。我可以重置 training/test 数据的索引:
bc_train, _ = train_test_split(bc_data, test_size=0)
bc_train.reset_index(inplace=True)
或者我可以从 values
成员分配:
bc_pca['diagnosis'] = bc_train['diagnosis'].values
我也可以在构建 DataFrame 之前做类似的事情(可以说更明智,因为 PCA 在 bc_train[feature_names].values
上有效运行)。
我正在 Scikit-learn 中探索 PCA(Python 3 上的 0.20)使用 Pandas 构建我的数据。当我应用 test/train 拆分时(且仅当),我的输入标签似乎不再与 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_train = bc_data
替换为 train_test_split()
调用(即使使用 test_size=0
),我的标签似乎不再对应于原始标签。
我意识到 train_test_split()
正在改组我的数据(通常我希望这样做),但我不明白为什么这会成为问题,因为 PCA 和标签分配使用相同的混洗数据。 PCA的转换只是一个投影,虽然它显然不保留相同的特征(列),但它不应该改变哪个标签对应哪个帧。
如何正确地重新标记我的 PCA 输出?
问题分为三个部分:
train_test_split()
中的改组导致bc_train
中的索引处于随机顺序(与行位置相比)。- PCA 对数值矩阵进行运算,并有效地从输入中去除索引。创建新的
DataFrame
会重新创建顺序索引(与行位置相比)。 - 现在我们在
bc_train
中有随机索引,在bc_pca
中有顺序索引。当我做bc_pca['diagnosis'] = bc_train['diagnosis']
时,bc_train
是 reindexed 和bc_pca
s 索引 。这将重新排序bc_train
数据,使其索引匹配bc_pca
s.
换句话说,当我用 bc_pca['diagnosis']
(即 __setitem__()
)分配时,Pandas 对索引进行左连接,而不是逐行复制(类似于 update()
.
我觉得这不直观,而且我找不到关于 __setitem__()
超出源代码的行为的文档,但我希望它对更有经验的 Pandas 用户有意义,也许它在我没见过的更高层次上有记录。
有很多方法可以避免这种情况。我可以重置 training/test 数据的索引:
bc_train, _ = train_test_split(bc_data, test_size=0)
bc_train.reset_index(inplace=True)
或者我可以从 values
成员分配:
bc_pca['diagnosis'] = bc_train['diagnosis'].values
我也可以在构建 DataFrame 之前做类似的事情(可以说更明智,因为 PCA 在 bc_train[feature_names].values
上有效运行)。