На этом шаге мы рассмотрим пример, иллюстрирующий последствия такой утечки.
Замечательный пример утечки информации при проведении перекрестной проверки дан в книге Hastie, Tibshirani, Friedman The Elements of Statistical Learning, а мы приведем здесь адаптированный вариант. Рассмотрим синтетическую задачу регрессии со 100 наблюдениями и 10000 признаками, которые извлекаем независимо друг от друга из гауссовского распределения. Мы также сгенерируем зависимую переменную из гауссовского распределения.
[In 12]: rnd = np.random.RandomState(seed=0) X = rnd.normal(size=(100, 10000)) y = rnd.normal(size=(100,))
При таком способе создания набора данных взаимосвязь между данными X и зависимой переменной y отсутствует (они независимы), поэтому невозможно построить модель на этих данных (модели нечему научиться). Теперь мы сделаем следующее. Во-первых, выберем самые информативные признаки с помощью SelectPercentile(), а затем оценим качество регрессионной модели Ridge с помощью перекрестной проверки:
[In 13]: from sklearn.feature_selection import SelectPercentile, f_regression select = SelectPercentile(score_func=f_regression, percentile=5).fit(X, y) X_selected = select.transform(X) print("форма массива X_selected: {}".format(X_selected.shape)) форма массива X_selected: (100, 500)
[In 14]: from sklearn.model_selection import cross_val_score from sklearn.linear_model import Ridge print("Правильность перекр проверки (cv только для ridge): {:.2f}".format( np.mean(cross_val_score(Ridge(), X_selected, y, cv=5)))) Правильность перекр проверки (cv только для ridge): 0.91
Среднее значение R2, вычисленное в результате перекрестной проверки, равно 0.91, что указывает на очень хорошее качество модели. Ясно, что данный результат не может быть правильным, поскольку наши данные получены совершенно случайным образом. То, что произошло здесь, обусловлено тем, что из 10000 случайных признаков были выбраны некоторые характеристики, которые (по чистой случайности) имеют сильную корреляцию с зависимой переменной. Поскольку мы осуществляли отбор признаков вне перекрестной проверки, это позволило нам найти признаки, которые коррелировали с зависимой переменной как в обучающем, так и в тестовом блоках. Информация, которая "просочилась" из тестовых наборов, была очень информативной и привела к весьма нереалистичным результатам. Давайте сравним этот результат с результатом правильной перекрестной проверки, использующей конвейер:
[In 15]: pipe = Pipeline([("select", SelectPercentile(score_func=f_regression, percentile=5)), ("ridge", Ridge())]) print("Правильность перекр проверки (конвейер): {:.2f}".format( np.mean(cross_val_score(pipe, X, y, cv=5)))) Правильность перекр проверки (конвейер): -0.25
На этот раз мы получаем отрицательное значение R2, что указывает на очень плохое качество модели. Когда используется конвейер, отбор признаков осуществляется внутри цикла перекрестной проверки. Это означает, что для отбора признаков могут использоваться только обучающие блоки, а не тестовый блок. Процедура отбора признаков находит характеристики, которые коррелируют с зависимой переменной в обучающем наборе, но поскольку данные выбраны случайным образом, то в тестовом наборе корреляции между найденными признаками и зависимой переменной не обнаруживаются. В этом примере устранение утечки информации при выборе признаков привело к получению двух взаимоисключающих выводов о качестве модели: модель работает очень хорошо и модель вообще не работает.
На следующем шаге мы рассмотрим общий интерфейс конвейера.