NannyML выпустила DLE, алгоритм, способный предсказывать MAE и MSE вашей регрессионной модели в отсутствие достоверной информации.

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

Это стало возможным благодаря разработанному NannyML алгоритму под названием Оценка производительности на основе достоверности (CBPE), который использует вероятности, предсказанные моделью, для получения надежной оценки любой метрики классификации. Естественный вопрос:

Можем ли мы сделать это и для регрессионных моделей?

Согласно NannyML, да, можем. Они разработали метод под названием Прямая оценка потерь (DLE), который позволяет оценить производительность (в частности, среднюю абсолютную ошибку и среднеквадратичную ошибку) любой регрессионной модели, когда основная правда недоступна.

Они заявляют здесь, что — как универсальное решение для оценки производительности — DLE превосходит другие подходы, такие как байесовский метод или конформализованная квантильная регрессия. Но пока мы не увидим, мы не поверим, верно? Итак, в этой статье мы рассмотрим DLE, попробуем его на реальном наборе данных и посмотрим, действительно ли он работает так, как обещает NannyML.

Главная идея

Интуиция, стоящая за DLE, очень проста. Настолько просто, что кажется слишком хорошим, чтобы быть правдой. По сути, идея состоит в том, чтобы напрямую прогнозировать ошибки, допущенные моделью.

Я знаю, что вы думаете. Вы, вероятно, настроены скептически, потому что слышали, что:

«Вы не можете заставить модель предсказывать ошибки другой модели».

Но так ли это? Чтобы ответить на этот вопрос, нам нужно начать с апостериорного распределения.

Знакомство с апостериорным распределением

Мы привыкли к моделям, которые возвращают одно значение для каждого наблюдения, что также называется точечным прогнозированием. Однако мы должны помнить, что за этим точечным предсказанием всегда стоит полное распределение. Если вам нравятся причудливые статистические термины, вы можете назвать это «апостериорным распределением».

В чем смысл апостериорного распределения?

Апостериорное распределение дает вам полный отчет о неопределенности прогноза.

Попробуем понять это с помощью примера.

Предположим, мы обучили модель прогнозировать доход человека на основе его страны, пола, возраста, семейного положения и работы. Теперь представьте, что у нас есть 10 000 человек со следующими характеристиками:

  • Страна: США.
  • Женский пол.
  • Возраст: 27 лет.
  • Семейное положение: женат.
  • Должность: продавец.

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

Давайте сгенерируем апостериорное распределение в Python:

# generate posterior distribution
import numpy as np
posterior_distribution = np.random.lognormal(0, .25, 10000) * 50000

Это гистограмма распределения:

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

Однако большинство прогностических моделей предназначены для получения точечного прогноза. Действительно, при наличии 10 000 человек, указанных выше, ваша модель будет предсказывать одинаковый доход для каждого из них. Как вы можете догадаться, модели обычно предназначены для прогнозирования среднего значения апостериорного распределения.

np.mean(posterior_distribution)

В нашем случае это 50 000$. Итак, это предсказание модели.

Почему нет смысла предсказывать ошибку…

Для каждого из наших людей ошибка определяется разницей между предсказанием точки и истинным значением. Например, если доход человека составляет 65 000 долларов, ошибка модели составит -15 000 долларов.

error_distribution = point_prediction - posterior_distribution

И если вы возьмете среднюю ошибку:

mean_error = np.mean(error_distribution)

Это, конечно, ноль по определению.

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

На этом этапе легко понять, не имеет смысла предсказывать ошибку. Потому что это означало бы попытку предсказать что-то, что по определению равно null.***

А разве мы не говорили, что DLE основан именно на предсказании ошибки? Итак, в чем подвох?

***Мы предполагаем, что модель предсказывает среднее значение апостериорного распределения. Это не всегда так. Например, если вы используете функцию потерь, отличную от MSE, ваши ошибки могут не центрироваться на 0. Однако в этом случае предсказание ошибки со знаком по-прежнему было бы бессмысленным: это было бы похоже на «исправление» функции потерь, которую вы выбрали в первую очередь.

… Но есть смысл предсказать абсолютную ошибку.

Дело в том, что DLE предсказывает не знаковую ошибку, а абсолютную ошибку!

Может показаться, что разница небольшая, но на самом деле это совсем другая история. На самом деле, вопреки подписанной ошибке:

Абсолютная ошибка – это показатель того, насколько ненадежен наш прогноз точки.

Имея апостериорное распределение, мы можем вычислить абсолютные ошибки:

absolute_error_distribution = np.abs(point_prediction - posterior_distribution)

И если мы возьмем среднее значение, мы получим среднюю абсолютную ошибку:

mean_absolute_error = np.mean(absolute_error_distribution)

При смоделированном нами распределении средняя абсолютная ошибка составляет около 10 000 долларов. Это означает, что в среднем фактический доход на 10 000 долларов отличается от точечного прогноза, данного нашей моделью.

Подводить итоги:

  • Пытаться предсказать ошибку со знаком бессмысленно, потому что мы пытаемся исправить модель, которую считаем лучшей.
  • Попытка предсказать абсолютную (квадратичную) ошибку имеет большой смысл, потому что мы пытаемся количественно определить неопределенность, связанную с предсказанием.

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

Описание алгоритма DLE

На практике DLE обучает новую модель, которая изучает неопределенность, связанную с предсказаниями исходной модели. Фактически:

  • Исходная модель делает точечные прогнозы (как всегда).
  • Модель, представленная DLE, предсказывает абсолютные (или квадратичные) ошибки, допущенные основной моделью. NannyML называет это «моделью няни» (по очевидным причинам).

Мы можем суммировать весь процесс в 4 шага.

Как обычно, все начинается с обучения модели на обучающем наборе данных.

Затем модель используется для прогнозирования тестового набора данных. Получив прогнозы, мы также можем рассчитать абсолютные ошибки как абсолютную разницу между целью и прогнозом:

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

Наконец, когда модель используется в производственной среде для прогнозирования, мы можем использовать первую модель для прогнозирования целевой переменной, а модель-няня — для прогнозирования абсолютных ошибок.

Подводя итог, это представление всего процесса (без различия между обучающими, тестовыми и производственными наборами данных для ясности):

Прогнозирование производительности на реальном наборе данных

Давайте посмотрим, работает ли DLE на реальном наборе данных.

Мы будем использовать набор данных Superconductor, набор данных с открытым исходным кодом от UCI. Этот набор данных состоит из 21 263 материалов с 81 зарегистрированной характеристикой, касающейся атомной массы, атомного радиуса, плотности и других. Цель состоит в том, чтобы предсказать критическую температуру.

Мы разделим набор данных на обучающий, тестовый и рабочий набор данных.

# load data and split into train, test, prod
import pandas as pd
df = pd.read_csv(‘/kaggle/input/superconductor-dataset/train.csv’).sample(frac=1, random_state=123)
df_train = df.iloc[:int(len(df)/5)]
df_test = df.iloc[int(len(df)/5):int(len(df)/5*2)]
df_prod = df.iloc[int(len(df)/5*2):]
X_train = df_train.drop("critical_temp", axis=1)
X_test = df_test.drop("critical_temp", axis=1)
X_prod = df_prod.drop("critical_temp", axis=1)
 
y_train = df_train["critical_temp"]
y_test = df_test["critical_temp"]
y_prod = df_prod["critical_temp"]

На данный момент мы готовы обучить нашу модель:

# train model
from lightgbm import LGBMRegressor
model = LGBMRegressor().fit(X=X_train,y=y_train)

Затем мы используем тестовый набор данных для вычисления ошибок, допущенных моделью.

# compute observed errors made by the model on test data
pred_test = pd.Series(model.predict(X_test),
  index=X_test.index).clip(0)
error_test = pred_test — y_test

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

# train model to predict the absolute error
model_abs_error = LGBMRegressor().fit(
  X=pd.concat([X_test, pred_test], axis=1),
  y=error_test.abs()
)

В производственном наборе данных мы сначала используем основную модель для получения прогнозов. Затем мы используем модель няни, чтобы получить предсказанные абсолютные ошибки.

# predict the absolute errors on production data
pred_prod = pd.Series(model.predict(X_prod), index=X_prod.index).clip(0)
pred_abs_error_prod = pd.Series(model_abs_error.predict(pd.concat([X_prod, pred_prod], axis=1)), index=X_prod.index)

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

# predict MAE on production set
pred_mae_prod = np.mean(pred_abs_error_prod)

Тестирование DLE на предмет дрейфа данных

Вся цель DLE состоит в том, чтобы предсказать MAE (или MSE) нашей модели, когда у нас нет достоверной информации. Это чрезвычайно полезно в реальном сценарии, когда мы хотим заранее знать, есть ли ухудшение производительности нашей модели.

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

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

Результаты впечатляют. MAE, предсказанное с помощью модели няни, практически совпадает с фактическим MAE.

Попробуем с MSE:

И в этом случае результаты поразительно хороши.

Что произойдет, если мы попытаемся оценить ошибку (а не абсолютную ошибку)?

Мы уже видели выше, что попытка оценить ошибку со знаком не имеет смысла с теоретической точки зрения. Но поскольку специалисты по данным предпочитают практику теории, давайте все равно попробуем это сделать.

Другими словами, это означает повторение описанной выше процедуры, но вместо обучения модели-няни на абсолютных ошибках теста, обучение ее на тестовых ошибках со знаком.

В переводе на Python это означает следующее:

# train model to predict the error (which makes no sense)
model_error = LGBMRegressor().fit(
  X=pd.concat([X_test, pred_test], axis=1),
  y=error_test
)

Теперь мы можем получить прогноз ошибки со знаком для каждого наблюдения в тестовом наборе. Если мы возьмем эти прогнозы, возьмем их абсолютное значение, а затем усредним их, это будет новая оценка MAE.

Давайте посмотрим, как это будет работать на тех же тестовых сгибах, что и выше:

Очевидно, что при использовании этой новой стратегии предсказанная MAE систематически занижает фактическую MAE.

Это еще хуже, если мы попытаемся сделать это для MSE:

Это еще одно доказательство того, что предсказание абсолютной ошибки полностью отличается от предсказания ошибки со знаком и последующего принятия абсолютной ошибки.

И если вы не хотите изобретать велосипед…

В этой статье мы реализовали DLE с нуля, чтобы показать, как это работает внутри. Однако в реальной жизни часто предпочтительнее использовать библиотеки, которые хорошо поддерживаются.

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

# use DLE directly with NannyML
import nannyml as nml
estimator = nml.DLE(
    feature_column_names=features,
    y_pred='y_pred',
    y_true='critical_temp',
    metrics=['mae', 'mse'],
    chunk_number=10,
    tune_hyperparameters=False
)
estimator.fit(df_test)
results = estimator.estimate(df_prod_drifted)

Более того, вы можете легко получить причудливые графики производительности вашей модели с помощью одной строки кода:

results.plot(metric=’mae’)

Когда это не сработает

При использовании DLE для оценки производительности есть несколько предположений, на которые следует обратить внимание. Действительно, если некоторые из этих предположений нарушаются, производительность, оцениваемая DLE, может быть уже ненадежной. Это предположения:

  • Нет дрейфа концепций. Если отношение между функциями и целевой переменной изменяется непредвиденным образом, ошибка, которую вы пытаетесь предсказать, также изменяется, и поэтому модель-няня может дать сбой.
  • Во входном пространстве нет ковариантного сдвига к ранее невидимым областям. И основная модель, и модель-няня учатся на оригинальных чертах. Если функции дрейфуют к значениям, не замеченным на этапах обучения/проверки, модели могут сделать неверное предположение.
  • Выборка данных достаточно велика. Конечно, набор данных для обучения и проверки должен быть достаточно большим, чтобы обе модели были надежными.

Подведение итогов

В этой статье мы увидели, как надежно прогнозировать ожидаемую производительность (в частности, MAE и MSE) регрессионной модели, когда достоверные данные недоступны.

Этот алгоритм, называемый Прямая оценка потерь (DLE), был предложен в этой статье NannyML (библиотека с открытым исходным кодом, ориентированная на науку о данных после развертывания).

DLE основан на интуитивном прогнозировании абсолютной (или квадратичной) ошибки каждого отдельного наблюдения. Мы протестировали его на наборе данных Superconductor и получили выдающиеся результаты.

Вы можете найти весь код, использованный для этой статьи, в этом репозитории Github.

Спасибо, что прочитали! Надеюсь, вам понравилась эта статья. Если хотите, добавьте меня в Linkedin!