Метрика держится после перемешивания меток: диагностический эксперимент
Метрика подозрительно высокая. Один диагностический эксперимент — разрушить связь признаков с ответом и повторить обучение. Если балл почти не изменился, надо проверить вычисление метрики, состав признаков и независимость проверки.
Перемешать ответ до повторного обучения
Нельзя перемешать метки только после того, как модель уже обучилась на правильных ответах, и назвать это проверкой всего процесса. Нужен повтор той же процедуры: разделение, подготовка, обучение и оценка. Если подготовка использует данные, она должна переобучаться внутри каждого обучающего среза.
Для независимых строк permutation_test_score сравнивает исходный CV-балл с баллами при перестановках меток. Подбор алгоритма после просмотра результата превращает диагностику в ещё один эксперимент; сохраняйте, что именно запускали.
Использовать модель, которой есть что изучать
Создадим числовую задачу с информативными признаками. LogisticRegression действительно обучается, а Pipeline включает масштабирование. StratifiedKFold задаёт воспроизводимые фолды. На каждом варианте меток процедура запускается заново.
Параметр n_permutations=39 выбран для короткого учебного запуска. Он даёт грубое распределение и ограниченную точность p-value. Для исследовательского вывода число перестановок и статистический план задаются отдельно.
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import StratifiedKFold, permutation_test_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
X, y = make_classification(n_samples=150, n_features=6, n_informative=4,
n_redundant=0, class_sep=2, random_state=4)
model = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000))
cv = StratifiedKFold(3, shuffle=True, random_state=2)
score, shuffled, pvalue = permutation_test_score(model, X, y, cv=cv,
scoring="balanced_accuracy", n_permutations=39, random_state=3, n_jobs=1)
print({"original": round(score, 3), "shuffled_mean": round(shuffled.mean(), 3),
"pvalue": pvalue})
assert len(shuffled) == 39 and score > shuffled.mean()
assert 0 < pvalue <= 1Исходный балл и среднее переставленных считаются из реальных обучений. Небольшой p-value означает, что такой исходный балл редко возникал при проверенной схеме разрушения связи. Он сам по себе не доказывает отсутствие утечки: признак, скопированный из исходной цели, тоже способен создать сильную связь.
Что делать при странном результате
Если балл остаётся высоким, сначала убедитесь, что код действительно передаёт перемешанный y в fit и сравнивает predict с соответствующим проверочным y. Затем проверьте неизменённые копии цели, кэшированные прогнозы и случайное вычисление метрики на train.
Для групп и времени обычное перемешивание строк может нарушать структуру данных. Определите, какую нулевую гипотезу проверяете и какие перестановки допустимы. Диагностический контроль должен сохранять необходимые зависимости, иначе его распределение отвечает на другой вопрос.
Сохраните seed, фолды, исходный балл и все переставленные значения. При изменении пайплайна повторите эксперимент целиком. Это полезная проверка здравого смысла рядом с аудитом признаков, но решение о честности оценки требует также предметной границы доступной информации.
Закрепить на практике
В бесплатном уроке train_test_split вы научитесь сохранять соответствие X и y при разделении. После базовой практики переходите к повторному обучению с переставленными метками из статьи. Откройте бесплатный урок и задачи. Полная последовательность тем — в бесплатном курсе.
Продолжить на практике
- Машинное обучение с нуля на Python: первая модель ↗
Бесплатный курс машинного обучения на Python: обучите первую модель в scikit-learn, проверьте её качество и решите 106 задач в браузере.
