Примечание. Вы также можете прочитать эту историю в моем блоге:



У AUC много названий: AUC, AUC-ROC, ROC-AUC, площадь под кривой и т. д. Это чрезвычайно важный показатель для оценки моделей машинного обучения и очень популярный вопрос на собеседовании в области науки о данных. Кроме того, по крайней мере, по моему опыту, это единственная метрика, которую чаще всего неправильно понимают в науке о данных.

Я слышал несколько распространенных недоразумений или откровенной лжи от людей в самых разных ролях, обсуждающих AUC. Самые большие обиды, как правило, происходят из-за чрезмерного усложнения темы. Легко увидеть страницу Википедии для кривой ROC и быть сбитым с толку, напуганным или комбинацией того и другого. ROC основывается на других фундаментальных концепциях науки о данных — долях истинных и ложных срабатываний классификатора — поэтому это, безусловно, не самое подходящее место для начала изучения метрик для оценки производительности моделей.

Наиболее распространенная причина путаницы с AUC, по-видимому, связана с графиком кривой ROC, и ничего особенного в самой AUC. Как правило, я слышу, как AUC объясняется как площадь под кривой ROC, и все дело в проверке того, насколько хорошо ваша модель уравновешивает ложные срабатывания и ложные отрицания. Это все хорошо, но это не дает новичку в AUC никакого интуитивного понимания того, что AUC фактически означает на практике. Например, давайте представим, что мы пытаемся предсказать вероятность того, что студент будет принят в Карлтон-колледж — довольно распространенная проблема в CollegeVine! Как фраза «AUC говорит мне о том, как моя модель уравновешивает ложноотрицательные и ложноположительные результаты» говорит мне что-либо о том, насколько хорошо моя модель предсказывает шансы этого ученика?

Основная проблема, с которой я столкнулся в связи с этим фактическим, но бесполезным объяснением AUC, заключается в следующем: хотя это может быть правдой, оно не достигает сути. И что еще хуже, его иногда используют как костыль: запасной ответ, когда кто-то чувствует себя застрявшим, когда его спрашивают, как интерпретировать AUC в реальных, практических терминах.

Итак, в этом посте я сосредоточусь только на одном: ответе на вопрос выше о том, как интерпретировать AUC.

Что такое АУК?

Как я уже упоминал, обычно бесполезно пытаться объяснить кому-то AUC, говоря им, что это просто площадь под кривой ROC или что это показатель, который вы можете использовать для прогнозирования вероятностей, а не для прогнозирования. классы или что это метрика, пытающаяся сбалансировать ложноположительные и ложноотрицательные результаты. Ни одна из этих вещей не затрагивает суть проблемы.

Так что же такое есть AUC? Это довольно просто: давайте представим, что модель M оценивается на данных X, где X содержит несколько экземпляров истинного класса и несколько экземпляров ложного класса. AUC для M на X — это вероятность того, что случайный элемент из X, принадлежащий к классу true (T), и другой случайный элемент из X, принадлежащий к классу false ( F), что модель предсказывает, что вероятность истинности T (принадлежности к истинному классу) выше, чем вероятность истинности F (принадлежности к истинному классу).

Вернемся к примеру с поступлением в Карлтон и представим, что у нас есть модель, которая дает вероятность поступления в Карлтон при наличии некоторой информации о студенте. Если я даю модели одного случайного принятого учащегося и одного случайного отклоненного учащегося, AUC модели представляет собой вероятность того, что принятый учащийся имел более высокие шансы на зачисление (по оценке моделью), чем отвергнутый студент.

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

Простая реализация

Самый простой способ передать эту идею — показать простую реализацию AUC. Ниже приведен код R.

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

  1. Выберите случайный предмет из класса true.
  2. Выберите случайный предмет из класса false.
  3. Сделайте прогноз по каждому из двух пунктов.
  4. Если прогнозируемая вероятность для действительно истинного элемента больше, чем прогнозируемая вероятность для фактически ложного элемента, возвращается значение true. В противном случае вернуть ложь. Если они равны, подбросьте монетку.
  5. Повторите 1–4 много раз и рассчитайте долю времени, в течение которого ваша модель угадывала правильно. Это ваш АУК.

Теперь давайте напишем это на R с небольшой помощью векторизации.

library(rlang)
library(dplyr)
library(tibble)
## Our AUC implementation
## In this implementation, we take a data frame containing a "truth" (i.e. whether
## the example is _actually_ in either the true class or the false class)
## and an "estimate" (our predicted probability).
## This implementation is in line with how {{yardstick}} implements all of its metrics
interpretable_auc <- function(data, N, truth_col = "truth", estimate_col = "estimate") {
  
  ## First, subset the data down to just trues and just falses, separately
  trues <- filter(data, .data[[truth_col]] == 1)
  falses <- filter(data, .data[[truth_col]] == 0)
  
  ## Sample the predicted probabilities for N `true` examples, with replacement
  random_trues <- sample(trues[[estimate_col]], size = N, replace = TRUE)
  
  ## Do the same for N `false` examples
  random_falses <- sample(falses[[estimate_col]], size = N, replace = TRUE)
  ## If the predicted probability for the actually true
  ##  item is greater than that of the actually false item,
  ##  return `true`. 
  ## If the two are equal, flip a coin.
  ## Otherwise, return false.
  true_wins <- ifelse(
    random_trues == random_falses,
    runif(N) > 0.50,
    random_trues > random_falses
  )
  
  ## Compute the percentage of the time our model was "right"
  mean(true_wins)
}

Затем мы можем протестировать нашу простую реализацию против yardstick на некоторых реальных данных. Для демонстрации я просто использовал встроенные данные mtcars. Вот как выглядят данные:

library(knitr)
library(kableExtra)
## Doing a little data wrangling
data <- mtcars %>%
  transmute(
    vs = as.factor(vs),
    mpg,
    cyl
  ) %>%
  as_tibble()
data %>%
  slice_sample(n = 6) %>%
  kable("html", caption = 'Six rows of our training data') %>%
  kable_styling(position = "center", full_width = TRUE)

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

library(purrr)
library(yardstick)
## Simplest model -- Just an intercept. AUC should be 50%
model1 <- glm(vs ~ 1, data = data, family = binomial)
## Adding another predictor
model2 <- glm(vs ~ mpg, data = data, family = binomial)
## And another
model3 <- glm(vs ~ mpg + cyl, data = data, family = binomial)
## Make predictions for all three models
preds <- tibble(
  truth = data$vs,
  m1 = predict(model1, type = "response"),
  m2 = predict(model2, type = "response"),
  m3 = predict(model3, type = "response")
)
## For each model, compute AUC with both methods: Yardstick (library) and "homemade"
map_dfr(
  c("m1", "m2", "m3"),
  ~ {
    yardstick <- roc_auc(preds, truth = truth, estimate = !!.x, event_level = "second")$.estimate
    homemade <- interpretable_auc(preds, N = 100000, truth_col = "truth", estimate_col = .x)
    tibble(
      model = .x,
      yardstick = round(yardstick, digits = 2),
      homemade = round(homemade, digits = 2)
    )
  }
) %>%
  kable("html", caption = 'Yardstick vs. Our Implementation') %>%
  kable_styling(position = "center", full_width = TRUE)

Как мы видели здесь, AUC на самом деле не должен вызывать путаницы! Мне нравится формулировать это следующим образом: AUC вашей модели показывает, насколько хорошо ваша модель делает ставки с равными шансами. Если я предоставлю вашей модели два варианта и попрошу ее выбрать наиболее вероятный, «лучшая» модель (по стандартам AUC) будет чаще определять истинный класс.

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

Дополнительные мысли

Я также часто слышу неправильное представление о том, что AUC чувствителен к таким вещам, как дисбаланс классов. Это означает, что если истинный класс составляет непропорционально большую (или маленькую) долю оценочных данных, это может исказить AUC. Но, основываясь на интуиции, которую мы только что построили ранее, это, конечно, не так. Главное помнить, что модели дается один верный и один ложный пример. При их выборе не имеет значения, составляет ли истинный класс только 0,005% всех примеров в оценочных данных: AUC оценивает модель только по ее способности определять, какой из двух это истинный класс.

Тем не менее, есть одна вещь, связанная с дисбалансом классов и размером выборки в целом, которая будет влиять на AUC, а именно количество примеров каждого класса в оценочных данных. Если, например, у вас был только один экземпляр класса true в оценочном наборе, то AUC модели полностью определяется тем, насколько хороши прогнозы модели на этом единственном примере. Например, если у нас есть один класс true, и модель предсказывает 100%-ю вероятность того, что он верен, тогда, предполагая, что прогнозы для всех других примеров в оценочном наборе не 100%, AUC модели, оцененная по этим данным, составляет 100%. Это не обязательно потому, что модель «хороша» в каком-либо смысле, а просто потому, что модель чрезмерно индексирует один хороший прогноз в наборе оценок. Однако на практике эта оценка AUC не может быть обобщена. По мере того, как мы получали больше данных, предсказания для всех истинных классов определенно не были бы стопроцентными, поэтому AUC модели со временем снижалась.

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

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

Надеюсь, этот пост помог лучше понять, что такое AUC на самом деле! Пара основных выводов:

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