Обычно, когда возникает необходимость оценить эффект от продуктовой фичи, аналитики проверяют гипотезы через A/B эксперименты. Но иногда запустить эксперимент нет возможности, а оценить эффект все еще хочется. Столкнувшись в очередной раз с такой ситуацией, я решил погрузиться в нашумевший в последнее время мир причинно-следственного анализа или Causal Inference и поделиться опытом применения различных подходов на практике.

Случалось ли с вами что-нибудь из этого?

  • Какая-то фича в продукте существует давно, на нее тратятся ресурсы, но вы не знаете какой эффект она оказывает на ключевые метрики?

  • Фичу раскатили без A/B эксперимента, но хочется оценить эффект от нее

  • Провести A/B технически сложно или невозможно

  • Ухудшающий A/B может потенциально испортить опыт пользователя

С нами случилось почти все сразу. И один из способов засетапить эксперимент без A/B – Causal Inference методы.

Меня зовут Артем Пономарев, я занимаюсь анализом данных и нередко сталкиваюсь с ситуациями, подобные тем, что выше в списке. Сейчас на тему причинно-следственных выводов несложно найти много статей, описывающих различные методы и подходы. Но в этой статье я хочу сделать упор на неочевидные проблемы и сложности, с которыми можно столкнуться на практике, и заодно поделиться опытом и впечатлением от применения таких методов. Но самое главное — постараться заинтересовать возможным применением подобных методов в подходящих ситуациях в ваших задачах (а что за подходящие ситуации — разберемся ниже!)

Постановка задачи

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

  • взаимодействовали с фичей (условная treatment группа)

  • не взаимодействовали (условная control группа)

Задача — оценить, как влияет взаимодействие с фичей на целевую метрику продукта (например, деньги или конверсию в покупку). В нашем случае это будет конверсия в покупку.

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

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

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

Генерация данных
import numpy as np
import pandas as pd

np.random.seed(42)

n = 50000

is_login = np.random.binomial(1, 0.3, size=n)
clicks = np.random.poisson(2, size=n)
is_open_profile = np.random.binomial(1, 0.3, size=n)
is_search = np.random.binomial(1, 0.4, size=n)
platform = np.random.choice([0, 1, 2], size=n)
lang = np.random.choice(["en", "es", "fr"], size=n)
clicks_notifications = np.random.exponential(scale=4, size=n)

# Adding linear relationships to treatment

treatment = is_open_profile * 0.3 + is_search * 0.6 + platform * 0.3 + is_login * 1.0 +\
    clicks * 1.2 + clicks_notifications * 0.1

treatment = (treatment > 4.5).astype(int)

added_ate = 0.12 # effect

# Adding linear relationships to a target metric

is_order = (treatment * 1.0 + is_login * 3.7 + clicks * 0.05 + clicks_notifications * 0.2 +\
    1.2 * platform + np.random.normal(0, 0.001, n) + (treatment * added_ate)) > 4.9

df = pd.DataFrame({
    "is_order": is_order.astype(int), # Y (целевая метрика) 
    "treatment": treatment, # T (флаг воздействия / использования фичи)
    "is_login": is_login, # Потенциальный конфаундер
    "clicks": clicks, # Потенциальный конфаундер
    "clicks_notifications": clicks_notifications, # Потенциальный конфаундер
    "is_open_profile": is_open_profile, # Потенциальный конфаундер
    "is_search": is_search, # Потенциальный конфаундер
    "platform": platform, # Потенциальный конфаундер
    "lang": lang # Потенциальный конфаундер
})

df["user_id"] = np.arange(1, len(df) + 1)

df.head()

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

Конверсия в покупку по группам

Конверсия в покупку

Пользователей

Не использовали фичу

17.5%

34 356

Использовали фичу

51.7%

15 644

Получаем впечатляющий эффект: в группе пользователей, которые фичу использовали значение конверсии в покупку выше на 34%!

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

Causal Inference методы как раз помогают удалить смещение между группами пользователей и в конце концов получить «чистый» эффект воздействия фичи на целевые метрики, как в привычном A/B эксперименте, если бы группа для каждого пользователя назначалась случайно.

Далее рассмотрим методы, которые мне удалось применить и которые часто используют для причинно-следственных выводов. Я не буду детально разбирать каждый из методов (за исключением метода PSM, на это есть причина, о ней ниже), потому что про них много всего написано на просторах интернета и Хабра. Вместо этого я хочу сосредоточиться на практическом использовании и демонстрации результата на сгенерированных данных.

Propensity Scores

Сначала поговорим о том, что такое оценка склонности (propensity score), потому что такие оценки используются сразу в нескольких методах, которые мы будем рассматривать ниже.

Как было упомянуто ранее, из-за неслучайности факта использования фичи, пользователи в контроле и тесте скорей всего отличаются между собой по исходной мотивации и активности. Хочется иметь какую-то единую меру, которой мы можем измерять «исходную мотивацию и активность» пользователя. В качестве такой меры мы можем использовать propensity score.

Propensity score — вероятность, что пользователь получит воздействие (использует фичу, например), учитывая его характеристики: например, страна пользователя, количество сессий, количество кликов и так далее.

e(X) = P(T = 1 \mid X)

Если научиться получать такой score для каждого пользователя, то мы сможем «выровнять» пользователей по этому показателю между группами, таким образом минимизируя смещение и предвзятость. Это позволит сравнивать две группы между собой и получать более корректную оценку реального эффекта от использования фичи.
Ведь если у двух объектов одинаковая вероятность получения воздействия, то единственная причина, почему один получил воздействие, а второй нет — случайность (тут математическое обоснование).

Чтобы получить propensity score, нам необходимо правильно выбрать набор признаков / характеристик пользователей, а затем обучить ML модель на факт воздействия (в нашем случае факт использования фичи), используя в качестве признаков модели выбранные характеристики.

Но для получения propensity scores подойдут не все признаки.

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

  • влияют на вероятность использования фичи (инструменты)

  • влияют на целевую метрику (ковариаты)

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

Как выбирать конфаундеры?

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

Для наглядности рассмотрим пример признака, который не является конфаундером.

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

Но чтобы выбрать конфаундеры, нам нужен какой-то исходный набор данных, из которого мы будем выбирать эти самые конфаундеры.

Как выбрать исходный набор характеристик?

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

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

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

Возможные трудности со сбором данных

Проблема с периодом сбора метрик
Проблема с периодом сбора метрик

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

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

  • считать метрики накопительно по сессиям для каждого пользователя

  • ...

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

Получение Propensity Scores

После выбора конфаундеров для получения propensity scores необходимо обучить ML модель на основе этих признаков на факт использования фичи.

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

Отбор конфаундеров и модель логистической регрессии

Напоминаю, что пример с симуляциями можно посмотреть здесь: GitHub

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

Корреляции каждого признака с целевой метрикой и с фактом воздействия:

Признак

Коэф корреляции с целевой метрикой

Коэф корреляции с тритментом

is_login

0.94

0.29

clicks_notifications

0.29

0.20

is_search

0.02

0.19

is_open_profile

0.01

0.08

platform

0.12

0.05

clicks

0.17

0.94

lang

0.00

0.00

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

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

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

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

Корректность полученных Propensity Scores

После обучения модели и получения оценок propensity scores хочется как-то проверить адекватность полученных оценок. И первое, на что стоит обращать внимание на этом этапе — это распределение полученных propensity scores между группами пользователей.

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

  • мы не очень хорошо подобрали конфаундеры

  • ML модель плохо описывает данные (не учитывает сложные взаимосвязи или, наоборот, переобучилась)

Можно получить, например, такое распределение.

Не самое удачное распределение propensity scores
Распределение PS между группами
Распределение PS между группами

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

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

Более приятное распределение propensity scores
Распределение PS
Распределение PS

В то же время важно смотреть не только на плотность распределения скоров между группами, но и на гистограмму с распределением абсолютного количества объектов по propensity scores. Особенно, если есть дисбаланс по количеству наблюдений между группами.

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

Далее кратко рассмотрим некоторые из методов, которые будут помогать получать эквивалентные группы и оценивать эффект от тритмента.

Propensity Score Matching

PSM (Propensity Score Matching) — один из самых популярных методов причинно-следственного вывода.

Примерная суть PSM
Примерная суть PSM

Суть метода в том, что для каждого объекта (например, пользователя) мы получаем вероятность получения воздействия (propensity score) на основе поведения пользователя и его параметров. Далее, используя полученные оценки, находим для пользователей из treatment группы очень похожих пользователей из control группы, то есть по сути находим «пользователей-близнецов», тем самым снижая исходное смещение между группами. Похожих пользователей можно искать каким-нибудь из методов матчинга, например, KNN.

После этого оцениваем эффект от фичи между полученными группами на целевую метрику.

Результат применения метода PSM на сгенерированных данных

Ранее мы выбрали конфаундеры и получили propensity scores. Так как мы получали неидеальное перекрытие распределение propensity scores между группами, пришлось ограничить выборку по значению propensity score < 0.7.

Далее используем метод KNN для поиска пользователей «близнецов» с похожими скорами между группами, оценим эффект и проверим баланс конфаундеров между группами.

treated = data_ps[data_ps["treatment"] == 1]
control = data_ps[data_ps["treatment"] == 0]

nn = NearestNeighbors(n_neighbors=1, metric="euclidean")

nn.fit(control[["propensity_score"]])

distances, indices = nn.kneighbors(treated[["propensity_score"]])

matched_indices = indices.reshape(-1)
matched_control_df = control.iloc[matched_indices].reset_index(drop=True)
matched_treated_df = treated.reset_index(drop=True)

effect = matched_treated_df["is_order"].mean() - matched_control_df["is_order"].mean()

print(f"ATE obtained by the PSM method for a logistic regression model: {round(effect, 2)}")

ATE obtained by the PSM method for a logistic regression model: 0.18

Получаем средний эффект на популяцию 0.18 (+18% конверсии в покупку), что гораздо более корректно, чем базовый эффект без удаления смещений в 34%, но далековато от истинного добавленного эффекта в 12%. Это может быть связано именно с тем, что в этом методе мы делаем прямой матчинг и теряем часть информации (тем более выше ограничили выборку по значению propensity score).

Проверим баланс конфаундеров на примере признака is_login.

# before psm
stat, p_value = ttest_ind(
    df_[df_["treatment"] == 0]["is_login"],
    df_[df_["treatment"] == 1]["is_login"]
)
print(f"Before PSM, p-value: {p_value}")

# after psm
stat, p_value = ttest_ind(
    df_matched[df_matched["treatment"] == 0]["is_login"],
    df_matched[df_matched["treatment"] == 1]["is_login"])
print(f"After PSM, p-value: {p_value}")

Before PSM, p-value: 0.0 After PSM, p-value: 0.217

Проверка баланса конфаундеров между скорректированными группами показывает, что нам удалось сбалансировать группы по выбранным конфаундерам. До применения метода значение признака is_login было различным между группами, а после применения — разницы между группами по этому признаку нет.

Применение метода позволило получить оценку эффекта гораздо ближе к истинному.

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

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

Формулы для оценки эффекта

Средний эффект на всю популяцию:

\text{ATE} = \mathbb{E}[Y(1) - Y(0)]

Эффект на тех, кто получил воздействие:

\text{ATT} = \mathbb{E}[Y(1) - Y(0) \mid T = 1]

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

\text{ATC} = \mathbb{E}[Y(1) - Y(0) \mid T = 0]

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

Почему PSM нужно использовать осторожно?

Несмотря на то, что Propensity Score Matching один из самых популярных методов в контексте Causal Inference, он не лишен существенных недостатков.

Про это можно подробней прочитать в статье Gary King и Richard Nielsen Why Propensity Scores Should Not Be Used for Matching, а я остановлюсь на основных тезисах:

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

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

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

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

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

Другие методы

PSW (Propensity Score Weighting) — еще один метод причинно-следственного вывода, который похож на PSM, потому что тоже использует оценки склонности (propensity scores), но отличается тем, как формируются эквивалентные группы.

Примерная суть PSW
Примерная суть PSW

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

Для каждого пользователя необходимо вычилить веса:

  • для группы тритмента: w_i = \frac{1}{e_i}

  • для контрольной группы w_i = \frac{1}{1 - e_i}

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

ATE = \frac{\sum_{i} w_i Y_i(T=1) - \sum_{i} w_i Y_i(T=0)}{\sum_{i} w_i}

Интуиция метода в том, что пользователи из тестовой группы, которые имеют высокую вероятность использования фичи (высокий propensity score), будут получать меньшие веса. И, напротив, пользователи из контрольной группы, которые имеют низкую вероятность использования фичи (низкий propensity score), получают большие веса. Это перевзвешивание позволяет лучше «представлять» менее вероятные события, чтобы они стали более сопоставимы с более вероятными.

Интуитивный пример

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

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

  • PSW «перепредставляет» менее тяжелых пациентов в группе лечения и более тяжелых пациентов в контрольной группе, чтобы обе группы стали сопоставимыми по тяжести симптомов

Применение метода PSW на сгенерированных данных

Для применения метода PSW я использовал два варианта полученных propensity scores, чтобы сравнить результаты:

  • PS, полученные из модели логистической регрессии

  • PS, полученные из более сложной модели CatBoost

Случай более простой модели

print(f"ATE obtained by the PSW method for a linear model: {round(weighted_effect, 2)}")

ATE obtained by the PSW method for a linear model: 0.14

Случай более сложной модели

print(f"ATE obtained by the PSW method for a catboost model: {round(weighted_effect, 2)}")

ATE obtained by the PSW method for a catboost model: 0.34

Мы видим, что использование propensity scores из простой модели логистической регрессии дает оценку 14%, очень близкую к заданной (12%). В то же время использование скоров, полученных из более сложной модели, дает плохую оценку. Скорее всего это связано с переобучением более сложной модели, но нам не нужно пытаться это выяснить на этапе обучения модели. Мы можем просто посмотреть на баланс конфаундеров после применения метода и увидеть, что только использование скоров из более простой модели удалось сбалансировать конфаундеры хорошо.

В качестве примера можем посмотреть на баланс между группами по платформе пользователя, которая является конфаундером:

 Случай использования PS из простой модели
Случай использования PS из простой модели
Случай использования PS из более сложной модели
Случай использования PS из более сложной модели

Именно поэтому очень важно всегда проверять баланс конфаундеров.

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

Doubly Robust

Метод Doubly Robust — еще один метод для оценки причинно-следственных эффектов, обладающий свойством двойной надежности.

Применение этого метода заключается в построении двух моделей:

  • модель для получения propensity scores

  • модель для целевой метрики (outcome)

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

  • Если модель для получения propensity scores верна, но модель результата неверна, оценка будет все еще точной

  • Если модель результата верна, но модель для получения propensity scores неверна, оценка также будет точной

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

Формула для оценки эффекта Doubly Robust
\begin{align} \hat{ATE} = & \frac{1}{N} \sum \left( \frac{T_i (Y_i - \hat{\mu}_1(X_i))}{\hat{P}(X_i)} + \hat{\mu}_1(X_i) \right) \\ & - \frac{1}{N} \sum \left( \frac{(1-T_i)(Y_i-\hat{\mu}_0(X_i))}{1-\hat{P}(X_i)} + \hat{\mu}_0(X_i) \right) \end{align}

Здесь P(x)– оценка показателя склонности, \hat{\mu}_0(X)– оценка [Y|X, T=0], \hat{\mu}_1(X)– оценка [Y|X, T=1].

Применение метода Doubly Robust на сгенерированных данных
print(f"Doubly robust estimation of the effect of an treatment: {round(dr_estimate, 2)}")

Doubly robust estimation of the effect of an treatment: 0.13

Оценка эффекта размером 0.13 (13%) после применения метода стала очень близка к истинной (12%)

Доверительный интервал для эффекта
Доверительный интервал для эффекта

Double Machine Learning

Метод тоже направлен на минизацию смещений и, как правило, наиболее сложный в применении из всех рассмотренных методов.

Основная идея метода в разделении задач на части:

  • обучение модели на outcome (целевая метрика)

  • обучение модели на treatment (воздействие)

  • извлечение остатков для каждого наблюдения для модели outcome

  • извлечение остатков для каждого наблюдения для модели treatment

  • через регрессию на основе остатков оценивается эффект

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

DML также обладает свойством двойной робастности. В отличие от Doubly Robust метод больше ориентирован на ML и использует остатки. Подходит для высокоразмерных сложных данных. Более устойчив к сложным зависимостям. Делает дополнительную корректировку за счет использования остатков, минимизируя смщение.

Применение метода DML на сгенерированных данных
print(f"ATE Double Machine Learning: {round(ate_dml, 2)}")

ATE Double Machine Learning: 0.15

Метод DML дал оценку ATE 0.15 (15%). Это менее точная оценка по сравнению с методом Doubly Robust, но все еще близкая к истинной оценке 12%.

Доверие к результату

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

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

Тем не менее, есть три ключевых момента, на которые необходимо обращать внимание:

  • Выбор конфаундеров

  • Баланс ковариат после получения групп

  • Осторожная интерпретация полученного результата

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

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

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

Общее впечатление и выводы

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

  • Норм, когда нет возможности провести полноценный A/B, но очень хочется внести больше определенности

  • Скорее не подходит, когда нужны точные цифры

Применение таких методов также может быть очень удобным для обоснования проведения сложного и дорогого полноценного A/B эксперимента. Субъективно я бы выделил такую цель применения подобных методов как одну из основных и полезных.

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

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

А еще я пишу про данные в Telegram-канал, заходите почитать!

Использованные источники

Комментарии (0)