Почему система sklearn train / test split плюс PCA делает мою маркировку неправильной? - PullRequest
0 голосов
/ 01 ноября 2018

Я изучаю PCA в Scikit-learn (0.20 на Python 3), используя 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()

enter image description here

Это выглядит разумно, и это подтверждается точными результатами классификации. Если я заменим bc_train = bc_data на train_test_split() вызов (даже с test_size=0), мои метки больше не будут соответствовать оригинальным.

enter image description here

Я понимаю, что train_test_split() перетасовывает мои данные (что мне вообще и нужно), но я не понимаю, почему это будет проблемой, поскольку PCA и назначение меток используют одни и те же перетасованные данные. Преобразование PCA - это всего лишь проекция, и, хотя оно, очевидно, не сохраняет те же функции (столбцы), оно не должно изменять, какая метка соответствует какому фрейму.

Как правильно перемаркировать вывод PCA?

1 Ответ

0 голосов
/ 01 ноября 2018

Вопрос состоит из трех частей:

  1. Перестановка в train_test_split() приводит к тому, что индексы в bc_train располагаются в случайном порядке (по сравнению с расположением строки).
  2. PCA работает с числовыми матрицами и эффективно удаляет индексы из входных данных. Создание нового DataFrame воссоздает индексы как последовательные (по сравнению с расположением строки).
  3. Теперь у нас есть случайные индексы в bc_train и последовательные индексы в bc_pca. Когда я bc_pca['diagnosis'] = bc_train['diagnosis'], bc_train будет переиндексирован с индексами bc_pca s . Это переупорядочивает данные bc_train так, чтобы их индексы соответствовали bc_pca с.

Другими словами, Pandas выполняет левое соединение индексов, когда я назначаю с bc_pca['diagnosis'] (т. Е. __setitem__()), а не построчную копию (аналогично update() .

Я не нахожу это интуитивно понятным, и я не смог найти документацию о поведении __setitem__() за пределами исходного кода, но я ожидаю, что это имеет смысл для более опытного пользователя Pandas, и, возможно, это задокументировано на более высоком уровне. уровень где-то я не видел.

Есть несколько способов избежать этого. Я могу сбросить индекс тренировочных / тестовых данных:

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).

...