Каждая проблема машинного обучения включает в себя различные этапы, начиная от очистки данных и заканчивая оценкой модели. Эта статья посвящена важному и ценному шагу в процессе оценки модели, более важному для задач классификации. Поговорим о перестановочном тесте. Его также называют тестом передискретизации.
ПРИМЕЧАНИЕ. В статье предполагается, что вы знакомы с методами машинного обучения.
Давайте разберемся, в чем заключается идея перестановочного теста. Основная предпосылка теста - выяснить, как наша обученная модель сравнивается со случайной моделью. Другими словами, мы хотим выяснить, какова вероятность того, что (лучшая) точность/производительность, которую мы получили от нашей обученной модели, не является случайностью. Это важный вопрос, над которым стоит подумать, особенно когда мы используем такие процедуры, как вложенная перекрестная проверка, когда обучающий набор влияет на окончательную производительность модели. Если мы глубоко задумаемся об этом, вы можете начать понимать, что в конечном итоге мы вычислим p-значение, чтобы сказать нам, насколько мы уверены в производительности нашей модели.
Концепцию лучше всего понять на примере. Я буду использовать простую задачу бинарной классификации в Python, чтобы проиллюстрировать тест. Набор данных, который мы будем использовать, — это набор данных радужной оболочки.
Давайте остановимся на секунду и подумаем… Если бы у нас было только два класса в целевой переменной y, то какова была бы точность модели бинарной классификации, если модель предсказывает целевую переменную случайным образом?
Это верно! Было бы 50%. Если это неясно, подумайте, почему это так. Как вы увидите, большая часть кода — это стандартный код машинного обучения. Хорошо, теперь давайте напишем код.
Во-первых, давайте импортируем необходимые библиотеки.
import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn import datasets
from sklearn import metrics
from sklearn.model_selection import train_test_split
Давайте загрузим набор данных радужной оболочки, а затем функции и цели. Здесь следует отметить, что набор данных имеет три целевых переменных вместо двух.
iris = datasets.load_iris()
X = iris.data
y = iris.target
В качестве следующего шага давайте разделим набор данных на обучающую и тестовую части.
# Obtain train test splits.
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=42, stratify=y)
И самое интересное... обучение модели.
Поскольку у нас есть проблема классификации, мы будем использовать логистическую регрессию в качестве нашей модели.
ПРИМЕЧАНИЕ. Модель LogisticRegression scikit-learn автоматически меняется на «многочленный» решатель, когда количество классов превышает два.
# Fit a model
model = LogisticRegression()
model.fit(X_train, y_train)
Наконец, давайте получим точность, сравнив прогнозы со значениями истинности.
preds = model.predict(X_test) print("Accuracy: {0}/100".format(metrics.accuracy_score(preds, y_test)*100))Accuracy: 96.66666666666667/100
Вау! Точность ~96,67%!
Теперь давайте зададимся вопросом: «Отличается ли этот результат от производительности, которую может обеспечить случайная модель?»
Чтобы смоделировать случайную модель, мы перемешиваем (переставляем) назначения выборок целевым значениям. Другими словами, мы случайным образом присваиваем целевые метки соответствующим образцам. Почему это работает? Это работает, потому что это создает сценарий, в котором нет связи между входными образцами (X) и выходными метками (y). Другими словами, поскольку все назначения меток образцам случайны, лучшая модель будет случайным образом назначать метки образцам.
В идеале мы запускаем тест перестановки много раз, потому что он дает нам лучшую оценку, оценивая различные случайные назначения. Если бы мы оценили только одну случайную перетасовку, то вполне возможно, что конкретное случайное назначение привело бы к довольно хорошей модели. Это может случиться, но это редко.
Итак, давайте запустим нашу модель для 100 перестановок. Поскольку наш набор данных небольшой, код будет работать довольно быстро.
Код, показанный ниже, является точно таким же кодом выше, но с небольшим изменением. На каждой итерации «перестановки» мы перемешиваем метки/цели, чтобы имитировать случайное назначение.
# Permutation test or the resampling test.
permuted_accuracies = []
permutation_iters = 100 # We run the procedure many times to have a 'good enough' estimate of the accuracy of a chance model.
for i in range(permutation_iters):
# Shuffle the dataset here so that the target species/labels are `randomly` assigned to the samples.
np.random.shuffle(y)
# When we obtain train and test splits, the assignments are random.
X_train, X_test, y_train, y_test = train_test_split(X,y, test_size=0.2, random_state=42, stratify=y)
model = LogisticRegression(max_iter=1000)
model.fit(X_train, y_train)
preds = model.predict(X_test)
permuted_accuracies.append(metrics.accuracy_score(preds, y_test)*100)
Давайте посмотрим, насколько хороша наша модель шансов.
print("Average permuted accuracy is: ", np.mean(permuted_accuracies))Average permuted accuracy is: 33.06666666666667
Точность вероятности близка к 33%, потому что у нас есть три класса в цели «y». Это означает, что модель не может изучить связь между входными выборками и целевыми метками и, таким образом, случайным образом предсказывает метки.
Вот и все! Это перестановочный тест, чтобы оценить, насколько хороша наша модель по сравнению со случайной моделью.
Хотя мы можем непосредственно видеть, что точность ~ 98% больше, чем случайная точность 33%, нам все же нужно получить меру, которая количественно определяет этот эффект. Другими словами, получите меру, которая скажет нам, значительно ли наши неперестановочные результаты выше случайных. Для этого мы можем рассчитать p-значение, о котором мы расскажем в другом посте!
Некоторые полезные ресурсы и документы:
- Наглядное объяснение перестановочного теста.
- Перестановочный тест для изучения производительности классификатора.
Если вам понравилась эта статья, подумайте о том, чтобы купить мне кофе :)