млн операций в секунду

Как обнаружить дрейф данных с помощью проверки гипотез

Подсказка: забудьте о p-значениях

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

Одномерное обнаружение дрейфа

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

Вероятной причиной наблюдаемого снижения производительности является дрейф данных. Дрейф данных — это изменение распределения входных данных модели между обучающими и производственными данными. Обнаружение и анализ характера дрейфа данных может помочь вернуть ухудшенную модель в нужное русло. Что касается того, как (и сколько) затронуты функции, дрейф данных может принимать одну из двух форм: следует различать многомерный и одномерный дрейф данных.

Многомерный дрейф — это ситуация, в которой распределения отдельных признаков не обязательно меняются, но меняется их совместное распределение. Это сложно заметить, так как наблюдение за каждой особенностью модели в отдельности не раскроет ее. Если вы заинтересованы в обнаружении многомерного дрейфа, ознакомьтесь с этой статьей о том, как это сделать на основе ошибок реконструкции PCA.

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

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

Учебник по проверке гипотез

Для конкретики давайте сосредоточимся на тесте хи-квадрат, который часто используется для сравнения распределений категориальных переменных. Критерий хи-квадрат находит широкое применение в тестировании A/B/C, где он используется для проверки того, демонстрируют ли пользователи, подвергшиеся разным воздействиям (например, показ рекламы A, B или C), разные модели поведения (например, частота покупок). ).

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

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

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

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

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

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

Чи-2 тест

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

H₀: различия в обучении/обслуживании являются результатом случайного шума.
H₁: различия в обучении/обслуживании являются результатом дрейфа данных.

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

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

Чи-2 статистика

Статистика хи-2 определяется как нормализованная сумма квадратов разностей между ожидаемой и наблюдаемой частотами. Давайте сейчас раскроем это утверждение.

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

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

cont_table = pd.DataFrame([
  [35_252, 30_299],
  [3_516, 3_187]
])

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

margsums = [cont_table.values.sum(axis=x) for x in [1, 0]]

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

from functools import reduce

margsums[0] = margsums[0].reshape(2, -1)
expected = reduce(np.multiply, margsums) / cont_table.values.sum()

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

diff = expected - cont_table.values
direction = np.sign(diff)
magnitude = np.minimum(0.5, np.abs(diff))
observed = cont_table.values + magnitude * direction

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

chisq = np.sum(((observed - expected) ** 2) / expected)

Это дает нам 4,23, и мы также знаем, что эта статистика соответствует распределению хи-2. Это все, что нам нужно для проверки нашей нулевой гипотезы.

Проверка гипотезы

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

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

Значение хи-2, скажем, 10, было бы очень, очень маловероятно увидеть под нулем. Если бы мы это увидели, мы, вероятно, пришли бы к выводу, что нулевая гипотеза должна быть ложной и данные сместились.

С другой стороны, если бы мы получили значение хи-2, равное 0,5, мы бы утверждали, что это наблюдаемое значение не является действительно удивительным при нулевой гипотезе, или, другими словами, различия в частотах устройства между обучающие и обслуживающие данные могли быть получены случайно. В целом это означает отсутствие оснований для отказа в нулевом статусе.

Но у нас получилось 4,23. Как мы решаем, отвергать нулевую гипотезу или нет?

р-значение

Входит печально известное p-значение. Это число отвечает на вопрос: какова вероятность наблюдать полученное нами значение хи-2 или даже более экстремальное значение, если нулевая гипотеза верна? Или, используя некоторые обозначения, p-значение представляет вероятность наблюдения данных при условии, что нулевая гипотеза верна: P(data|H₀) (точнее, p-значение определяется как P(test_static(data) > T | H₀), где T — выбранный порог для тестовой статистики). Обратите внимание, как это отличается от того, что нас на самом деле интересует, а именно вероятность того, что наша гипотеза верна, учитывая данные, которые мы наблюдали: P(H₀|данные).

какое значение p представляет: P(данные|H₀)
что нам обычно нужно: P(H₀|данные)

Графически говоря, p-значение представляет собой сумму синей плотности вероятности справа от красной линии. Самый простой способ вычислить его — вычислить единицу минус кумулятивное распределение при наблюдаемом значении, то есть единицу минус массу вероятности в левой части.

1 - chi2.cdf(chisq, df=1)

Это дает нам 0,0396. Если бы не было дрейфа данных, мы получили бы имеющуюся у нас тестовую статистику или даже больше примерно в 4% случаев. Ведь не так уж и редко. В большинстве случаев использования p-значение обычно сравнивают с уровнем значимости 1% или 5%. Если он ниже, то нуль отбрасывается. Давайте будем консервативны и будем следовать порогу значимости в 1%. В нашем случае с p-значением почти 4% недостаточно доказательств, чтобы отвергнуть его. Таким образом, дрейф данных не был обнаружен.

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

from scipy.stats import chi2_contingency

chisq, pvalue, df, expected = chi2_contingency(cont_table)
print(chisq, pvalue)

4.232914541135393 0.03964730311588313

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

Статистическая значимость в сравнении с мониторинговой значимостью

Статистика в самом широком смысле — это наука о выводах о целых популяциях на основе небольших выборок. Когда знаменитый t-критерий был впервые опубликован в начале 20-го века, все расчеты производились ручкой и бумагой. Даже сегодня слушатели курсов STATS101 узнают, что «большая выборка» начинается с 30 наблюдений.

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

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

Чтобы проиллюстрировать это явление, сравните две компании, A и B, с точки зрения соотношения полов среди их сотрудников. Представим два сценария. Во-первых, давайте возьмем случайную выборку из 10 сотрудников из каждой компании. В компании А 6 из 10 женщин, а в компании Б 4 из 10 женщин. Во-вторых, увеличим размер выборки до 1000. В компании А 600 из 1000 — женщины, а в Б — 400. В обоих сценариях соотношение полов было одинаковым. Тем не менее, больше данных, кажется, предлагает более убедительные доказательства того факта, что в компании А занято пропорционально больше женщин, чем в компании А, не так ли?

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

Давайте посмотрим, верно ли это для нашего критерия хи-2 для разницы частот категориальной переменной. В исходном примере обслуживающий набор был примерно в десять раз меньше обучающего набора. Давайте умножим частоты в наборе обслуживания на набор коэффициентов масштабирования от 1/100 до 10 и каждый раз будем вычислять статистику хи-2 и p-значение теста. Обратите внимание, что умножение всех частот в обслуживающем наборе на одну и ту же константу не влияет на их распределение: единственное, что мы меняем, — это размер одного из наборов.

training_freqs = np.array([10_322, 24_930, 30_299])
serving_freqs = np.array([1_015, 2_501, 3_187])

p_values, chi_sqs = [], []
multipliers = [0.01, 0.03, 0.05, 0.07, 0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10]
for serving_size_multiplier in multipliers:
  augmented_serving_freqs = serving_freqs * serving_size_multiplier
  cont_table = pd.DataFrame([
  training_freqs,
  augmented_serving_freqs,
  ])
  chi_sq, pvalue, _, _ = chi2_contingency(cont_table)
  p_values.append(pvalue)
  chi_sqs.append(chi_sq)

Значения при множителе, равном единице, — это те, которые мы рассчитали ранее. Обратите внимание, что при размере порции всего в 3 раза больше (отмечено вертикальной пунктирной линией) наш вывод полностью меняется: мы получаем статистику хи-2, равную 11, и значение p, близкое к нулю, что в нашем случае соответствует показателю дрейфа данных. .

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

Узнав об этом, у вас может возникнуть соблазн предложить разделить данные обслуживания на несколько фрагментов и запустить несколько тестов с меньшими наборами данных. К сожалению, это тоже не очень хорошая идея. Чтобы понять почему, нам нужно глубоко понять, что на самом деле означает p-значение.

Значение п

Мы уже определили p-значение как вероятность наблюдения тестовой статистики, по крайней мере столь же маловероятной, как та, которую мы фактически наблюдали, при условии, что нулевая гипотеза верна. Попробуем распаковать этот глоток.

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

Следовательно, наше значение p, равное примерно 0,1, означает, что при полном отсутствии дрейфа данных 10% тестов будут ошибочно сигнализировать о дрейфе данных из-за случайного случая. Это остается в соответствии с обозначением того, что представляет p-значение, которое мы ввели ранее: P (данные | H₀). Если эта вероятность равна 0,1, то, учитывая, что H₀ верно (отсутствие дрейфа), у нас есть 10%-ная вероятность наблюдения данных, по крайней мере, столь же отличных от того, что мы наблюдали (согласно тестовой статистике)

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

Байес в помощь

Мы видели, что обнаружение дрейфа данных на основе p-значения теста может быть ненадежным, что приводит к большому количеству ложных тревог. Как мы можем сделать лучше? Одно из решений — развернуться на 180 градусов и прибегнуть к байесовскому тестированию, которое позволяет нам напрямую оценить то, что нам нужно, P(H₀|данные), а не p-значение, P(данные|H₀).

Что такое Байес

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

Параметры являются случайными величинами

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

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

Байесовский подход рассматривает интересующий нас параметр как случайную величину, описываемую некоторым распределением вероятностей. Мы пытаемся оценить параметры этого распределения. Как только мы это сделаем, мы получим право делать вероятностные утверждения о параметре, такие как, например, «вероятность того, что доля пользователей нашей модели, использующих мобильные устройства, составляет от 0,2 до 0,6, составляет 55%».

Этот подход идеально подходит для обнаружения дрейфа данных: вместо того, чтобы полагаться на туманные p-значения P(данные|H₀) с помощью байесовского теста, мы можем напрямую рассчитать вероятность и величину дрейфа данных P(H₀|данные)!

Байесовский тест на дрейф данных

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

Получение нужной нам вероятности

Итак, как же получить вероятность дрейфа данных? Это можно сделать с помощью так называемого правила Байеса, изящной аксиомы вероятности, позволяющей нам вычислить вероятность того, что что-то зависит от чего-то другого, если мы знаем обратное соотношение. Например, если мы знаем, что такое P(B|A), мы можем вычислить P(A|B) как:

P(A|B) = P(B|A) * P(A) / P(B)

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

P(частота|данные) = P(данные|частота) * P(частота) / P(данные)

На байесовском жаргоне все элементы в приведенном выше уравнении имеют свои имена:

  • P(freq|data) — это то, что нам нужно — апостериорное или вероятностное распределение доли мобильных пользователей после просмотра данных;
  • P(data|freq) — вероятность или вероятность наблюдения данных с учетом конкретной частоты мобильных пользователей;
  • P(freq) — это априорное значение: что мы думаем о доле мобильных пользователей до того, как увидим какие-либо данные;
  • P (данные) можно рассматривать как коэффициент масштабирования, который гарантирует, что суммы правых частей равны единице, как и должно быть в распределении вероятностей.

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

P(H₀|данные) = P(freq_ref|данные) == P(freq_anal|данные)

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

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

Вероятность дрейфа данных

Начнем с определения наших данных. В обучающих данных у нас 65 551 наблюдение, 30 299 из которых — мобильные пользователи.

num_obs = 65_551
num_mobile_obs = 30_299

Интересующий нас параметр — частота мобильных пользователей. Теоретически это может быть любое значение от 0% до 100%. Аппроксимируем его на сетке от 0,0001 до 1:

mobile_freq = np.arange(0, 1.0001, 0.0001)

Теперь мы можем создать сетку всех комбинаций частоты мобильных пользователей и их наблюдаемого количества:

devices = pd.DataFrame([(x, y) for x in [num_mobile_obs] for y in mobile_freq])
devices.columns = ["num_mobile", "mobile_freq"]

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

devices["prior"] = 1.

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

devices["likelihood"] = binom.pmf(
  devices["num_mobile"], 
  num_obs, 
  devices["mobile_freq"]
)

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

devices["posterior"] = devices["prior"] * devices["likelihood"]
devices["posterior"] /= devices["posterior"].sum()

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

mobile_obs = devices[devices["num_mobile"] == num_mobile_obs]
mobile_obs["posterior"] /= mobile_obs["posterior"].sum()

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

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

results = {}
for dataset, num_obs, num_mobile_obs, color in zip(
  ["training", "serving"], [65_551, 6703], [30_299, 3187], ["blue", "green"]
):
  # Set up grid
  num_mobile = np.arange(0, num_obs + 1, 1)
  mobile_freq = np.arange(0, 1.0001, 0.0001)
  devices = pd.DataFrame([(x, y) for x in num_mobile for y in mobile_freq])
  devices.columns = ["num_mobile", "mobile_freq"]

  # Follow Bayes rule to compute posterior
  devices["prior"] = 1.
  devices["likelihood"] = binom.pmf(
    devices["num_mobile"], 
    num_obs,
    devices["mobile_freq"],
  )
  devices["posterior"] = devices["prior"] * devices["likelihood"]
  devices["posterior"] /= devices["posterior"].sum()

  # Ger posterior for observed number of mobile users
  mobile_obs = devices[devices["num_mobile"] == num_mobile_obs]
  mobile_obs["posterior"] /= mobile_obs["posterior"].sum()

  # Sample from posterior and store the draws
  samples[dataset] = random.choices(
    mobile_obs["mobile_freq"].tolist(),
    weights=mobile_obs["posterior"].tolist(),
    k=10_000,
  )

  # Plot the posterior
  sns.lineplot(
    mobile_obs["mobile_freq"],
    mobile_obs["posterior"], 
    color=f"dark{color}",
    label=dataset,
  )
  plt.fill_between(
    mobile_obs["mobile_freq"],
    0,
    mobile_obs["posterior"],
    color=f"light{color}",
  )
  plt.xlim(0.45, 0.50)
  plt.xlabel("Proportion of users using a mobile device")
  plt.ylabel("Probability density")

Время тестирования

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

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

np.mean([
  serving > training
  for serving, training in
  zip(samples["serving"], samples["training"])
])

0.977

Вероятность того, что переменная device сместилась, составляет 97,7 %. Дрейф почти наверняка произошел! Но насколько он велик?

np.mean([
  serving - training
  for serving, training in
  zip(samples["serving"], samples["training"])
])

0.013

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

Выводы

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

Эта статья также была опубликована в блоге NannyML.

Спасибо за прочтение!

Если вам понравился этот пост, почему бы вам не подписаться на обновления по электронной почте на мои новые статьи? А, став участником Medium, вы можете поддержать меня и получить неограниченный доступ ко всем историям других авторов и вашему покорному слуге.

Хотите всегда держать руку на пульсе стремительно развивающейся области машинного обучения и искусственного интеллекта? Ознакомьтесь с моим новым информационным бюллетенем AI Pulse. Нужна консультация? Вы можете спросить меня о чем угодно или заказать 1:1 здесь.

Вы также можете попробовать одну из других моих статей. Не можете выбрать? Выберите один из них:







Все изображения, если не указано иное, принадлежат автору.