10.2. Утечка данных

Утечка данных происходит, когда при построении модели используется информация, которая не была бы доступна во время прогнозирования. Это приводит к чрезмерно оптимистичным оценкам производительности, например, на основе перекрестной проверки , и, следовательно, к снижению производительности, когда модель используется на фактически новых данных, например, во время производства.

Распространенной причиной является то, что подмножества тестовых и обучающих данных не хранятся отдельно. Никогда не следует использовать тестовые данные для выбора модели. Общее правило — никогда не запрашивать fit тестовые данные . Хотя это может показаться очевидным, в некоторых случаях это легко упустить, например, при применении определенных этапов предварительной обработки.

Хотя подмножества обучающих и тестовых данных должны получать одно и то же преобразование предварительной обработки (как описано в предыдущем разделе), важно, чтобы эти преобразования извлекались только из обучающих данных. Например, если у вас есть этап нормализации, на котором вы делите на среднее значение, среднее значение должно быть средним для подмножества поездов, а не для всех данных. Если тестовое подмножество включено в вычисление среднего значения, информация из тестового подмножества влияет на модель.

Пример утечки данных во время предварительной обработки подробно описан ниже.

10.2.1. Утечка данных при предварительной обработке

Примечание

Здесь мы решили проиллюстрировать утечку данных с помощью шага выбора функции. Этот риск утечки, однако отношение практически со всеми преобразованиями в scikit учиться, в том числе (но не ограничиваясь ими) StandardScalerSimpleImputer и PCA.

В scikit-learn доступен ряд функций выбора функций. Они могут помочь удалить нерелевантные, избыточные и зашумленные функции, а также сократить время построения и производительность вашей модели. Как и в случае с любым другим типом предварительной обработки, при выборе функций следует использовать только обучающие данные. Включение тестовых данных в выбор функций приведет к оптимистическому смещению вашей модели.

Чтобы продемонстрировать, мы создадим эту задачу двоичной классификации с 10000 случайно сгенерированными функциями:

>>> import numpy as np
>>> n_samples, n_features, n_classes = 200, 10000, 2
>>> rng = np.random.RandomState(42)
>>> X = rng.standard_normal((n_samples, n_features))
>>> y = rng.choice(n_classes, n_samples)

Неправильный

Использование всех данных для выполнения выбора функций приводит к тому, что оценка точности намного выше, чем вероятность, даже если наши цели полностью случайны. Эта случайность означает, что наши X и y независимы, и поэтому мы ожидаем, что точность будет около 0,5. Однако, поскольку этап выбора функции «видит» тестовые данные, модель имеет нечестное преимущество. В приведенном ниже некорректном примере мы сначала используем все данные для выбора функций, а затем разделяем данные на обучающие и тестовые подмножества для подбора модели. Результат — гораздо более высокий, чем ожидалось, показатель точности:

>>> from sklearn.model_selection import train_test_split
>>> from sklearn.feature_selection import SelectKBest
>>> from sklearn.ensemble import GradientBoostingClassifier
>>> from sklearn.metrics import accuracy_score

>>> # Incorrect preprocessing: the entire data is transformed
>>> X_selected = SelectKBest(k=25).fit_transform(X, y)

>>> X_train, X_test, y_train, y_test = train_test_split(
...     X_selected, y, random_state=42)
>>> gbc = GradientBoostingClassifier(random_state=1)
>>> gbc.fit(X_train, y_train)
GradientBoostingClassifier(random_state=1)

>>> y_pred = gbc.predict(X_test)
>>> accuracy_score(y_test, y_pred)
0.76

Верно

Чтобы предотвратить утечку данных, рекомендуется сначала разделить данные на обучающие и тестовые подмножества . Затем выбор функций может быть сформирован с использованием только набора данных поезда. Обратите внимание, что всякий раз, когда мы используем fit или fit_transform, мы используем только набор данных поезда. Теперь результат такой, какой мы ожидаем от данных, почти случайный:

>>> X_train, X_test, y_train, y_test = train_test_split(
...     X, y, random_state=42)
>>> select = SelectKBest(k=25)
>>> X_train_selected = select.fit_transform(X_train, y_train)

>>> gbc = GradientBoostingClassifier(random_state=1)
>>> gbc.fit(X_train_selected, y_train)
GradientBoostingClassifier(random_state=1)

>>> X_test_selected = select.transform(X_test)
>>> y_pred = gbc.predict(X_test_selected)
>>> accuracy_score(y_test, y_pred)
0.46

Здесь мы снова рекомендуем использовать, Pipeline чтобы связать воедино выбор функций и оценки модели. Конвейер гарантирует, что при выполнении используются только обучающие данные, fit а тестовые данные используются только для вычисления оценки точности:

>>> from sklearn.pipeline import make_pipeline
>>> X_train, X_test, y_train, y_test = train_test_split(
...     X, y, random_state=42)
>>> pipeline = make_pipeline(SelectKBest(k=25),
...                          GradientBoostingClassifier(random_state=1))
>>> pipeline.fit(X_train, y_train)
Pipeline(steps=[('selectkbest', SelectKBest(k=25)),
                ('gradientboostingclassifier',
                GradientBoostingClassifier(random_state=1))])

>>> y_pred = pipeline.predict(X_test)
>>> accuracy_score(y_test, y_pred)
0.46

Конвейер также может быть передан в функцию перекрестной проверки, например cross_val_score. Опять же, конвейер гарантирует, что во время подбора и прогнозирования используются правильные подмножества данных и метод оценки:

>>> from sklearn.model_selection import cross_val_score
>>> scores = cross_val_score(pipeline, X, y)
>>> print(f"Mean accuracy: {scores.mean():.2f}+/-{scores.std():.2f}")
Mean accuracy: 0.45+/-0.07

10.2.2. Как избежать утечки данных

Ниже приведены несколько советов по предотвращению утечки данных:

  • Всегда сначала разделяйте данные на обучающие и тестовые подмножества, особенно перед любыми этапами предварительной обработки.
  • Никогда не включайте тестовые данные при использовании fit и fit_transform методов. Использование всех данных, например fit(X), может привести к чрезмерно оптимистичным оценкам.И наоборот, этот transformметод следует использовать как для обучающих, так и для тестовых подмножеств, поскольку ко всем данным должна применяться одинаковая предварительная обработка. Этого можно достичь, используя fit_transform подмножество поездов и transformтестовое подмножество.
  • Scikit-learn пайплайн является отличным способом , чтобы предотвратить утечку данных , поскольку это гарантирует , что соответствующий метод выполняется на правильном подмножестве данных. Конвейер идеально подходит для использования в функциях перекрестной проверки и настройки гиперпараметров.