#statisics
Что такое Conditional Average Treatment Effect (CATE) и зачем нам его считать?
Начнем с того, что такое Average Treatment Effect (ATE). Тут все просто. В рандомизированных исследованиях ATE используется, как мера эффекта. По сути, это просто средняя разница между группами. Когда мы проводим A/B тест, обычно это мы и хотим узнать - насколько в среднем мы сделали лучше?
Ок, но что делать, если наш treatment воздействует на разных пользователей по-разному? К примеру, у нас есть люди, которые перестанут у нас покупать, если мы проведем коммуникацию с ними. Или наоборот, есть только те, кто купит после коммуникации?
Здесь и появляется Conditional Average Treatment Effect (CATE).
Что же это такое? На самом деле, тут все лишь чуть сложнее, чем в случае ATE. Итак, у нас есть некоторые подгруппы пользователей, которые реагируют на наше воздействие по-разному. Значит, мы можем оценить наш ATE в рамках этих групп. Получим некоторый условный ATE, то есть как раз CATE (т.к. у нас conditional effect).
Обычно, CATE может использоваться при нарушении SUTVA (Stable Unit Treatment Value Assumption), то есть при нарушении предположения о независимости результатов от наличия или отсутствия treatment у других пользователей, а также от того, что у нас нет разных вариантов treatment, которые могут привести к отличию результатов. Именно в таких случаях, чтобы получить какие-то оценки нашего эффекта от treatment, мы используем CATE.
В следующих заметках рассмотрим Meta-learners, которые призваны оценивать CATE посредством ML.
Что такое Conditional Average Treatment Effect (CATE) и зачем нам его считать?
Начнем с того, что такое Average Treatment Effect (ATE). Тут все просто. В рандомизированных исследованиях ATE используется, как мера эффекта. По сути, это просто средняя разница между группами. Когда мы проводим A/B тест, обычно это мы и хотим узнать - насколько в среднем мы сделали лучше?
Ок, но что делать, если наш treatment воздействует на разных пользователей по-разному? К примеру, у нас есть люди, которые перестанут у нас покупать, если мы проведем коммуникацию с ними. Или наоборот, есть только те, кто купит после коммуникации?
Здесь и появляется Conditional Average Treatment Effect (CATE).
Что же это такое? На самом деле, тут все лишь чуть сложнее, чем в случае ATE. Итак, у нас есть некоторые подгруппы пользователей, которые реагируют на наше воздействие по-разному. Значит, мы можем оценить наш ATE в рамках этих групп. Получим некоторый условный ATE, то есть как раз CATE (т.к. у нас conditional effect).
Обычно, CATE может использоваться при нарушении SUTVA (Stable Unit Treatment Value Assumption), то есть при нарушении предположения о независимости результатов от наличия или отсутствия treatment у других пользователей, а также от того, что у нас нет разных вариантов treatment, которые могут привести к отличию результатов. Именно в таких случаях, чтобы получить какие-то оценки нашего эффекта от treatment, мы используем CATE.
В следующих заметках рассмотрим Meta-learners, которые призваны оценивать CATE посредством ML.
Meta learners. Что это такое и с чем это едят? S-learner и T-learner
Мета-алгоритм (или meta-learner) - фреймворк для оценки Conditional Average Treatment Effect (CATE) с использованием любых ML алгоритмов (называемых base learners).
При этом, у нас есть несколько разных вариантов для того, как проводить оценку CATE. Сегодня поговорим про простые методы - S-larner и T-learner.
Итак:
1. В случае S-learner мы учим модель на наших признаках и дополнительной фиче - метках был ли treatment или нет. Для теста мы используем два набора данных - где для treatment стоят все единицы и все нули. Разница предсказаний позволяет оценить CATE. Стоит отметить, что S-learner прост в реализации, но имеет важный минус - смещение эффекта от treatment относительно нуля;
2. В случае T-learner, мы используем две разных модели: одну учим на признаках с treatment = 1, другую - на признаках с treatment = 0. То есть это уже не признаки для одной модели, а способ разделить на две модели. На тесте мы получаем разность предсказаний двух моделей. Это и будет нашей оценкой CATE. Увы, и T-learner не лишен изъянов. Хотя мы и решаем проблему смещения оценки, но все же мы не защищены от т.н. regularization bias.
Например, у нас мало объектов с treatment, но много без него. Плюс, у нас есть нелинейность в результатах. Но общий treatment эффект является константой. Тогда мы обучим простую модель для объектов с treatment и модель посложнее для объектов без treatment. В итоге, мы перенесем нашу нелинейность в оценку только для сложной модели, где есть достаточно много наблюдений. Что неверно, т.к. наш общий treatment эффект константен. То есть мы внесли некоторый bias в оценку эффекта.
В этой заметке мы рассмотрели что такое meta-learners и конкретно S- и T-learner. Позже рассмотрим более сложные X- и R-learner. Думаю, что каждый из них заслуживает отдельной заметки.
Мета-алгоритм (или meta-learner) - фреймворк для оценки Conditional Average Treatment Effect (CATE) с использованием любых ML алгоритмов (называемых base learners).
При этом, у нас есть несколько разных вариантов для того, как проводить оценку CATE. Сегодня поговорим про простые методы - S-larner и T-learner.
Итак:
1. В случае S-learner мы учим модель на наших признаках и дополнительной фиче - метках был ли treatment или нет. Для теста мы используем два набора данных - где для treatment стоят все единицы и все нули. Разница предсказаний позволяет оценить CATE. Стоит отметить, что S-learner прост в реализации, но имеет важный минус - смещение эффекта от treatment относительно нуля;
2. В случае T-learner, мы используем две разных модели: одну учим на признаках с treatment = 1, другую - на признаках с treatment = 0. То есть это уже не признаки для одной модели, а способ разделить на две модели. На тесте мы получаем разность предсказаний двух моделей. Это и будет нашей оценкой CATE. Увы, и T-learner не лишен изъянов. Хотя мы и решаем проблему смещения оценки, но все же мы не защищены от т.н. regularization bias.
Например, у нас мало объектов с treatment, но много без него. Плюс, у нас есть нелинейность в результатах. Но общий treatment эффект является константой. Тогда мы обучим простую модель для объектов с treatment и модель посложнее для объектов без treatment. В итоге, мы перенесем нашу нелинейность в оценку только для сложной модели, где есть достаточно много наблюдений. Что неверно, т.к. наш общий treatment эффект константен. То есть мы внесли некоторый bias в оценку эффекта.
В этой заметке мы рассмотрели что такое meta-learners и конкретно S- и T-learner. Позже рассмотрим более сложные X- и R-learner. Думаю, что каждый из них заслуживает отдельной заметки.
Meta-learners. X-learner.
Переходим к более advanced историям. И начнем с x-learner. Объяснять этот meta-learner сложнее, чем предыдущие два (S, T-learner). Но в реализации он не так уж и сложен.
Итак, поехали.
В X-learner у нас две стадии + используется propensity score (о нем я писал ранее):
- На первом шаге делаем все точно по рецепту T-leaner. Напомню: обучаем две модели для наличия и отсутствия treatment;
- На втором шаге мы делаем небольшой "финт ушами" и вычитаем из реальных значений для наличия или отсутствия treatment предсказания для противоположной модели. Например, для отсутствия treatment получим:
- Далее обучаем еще две модели (
Но, у нас все еще проявляется все та же проблема, что и в T-learner (при нелинейном эффекте мы его видим для одной более сложной модели и не видим для менее сложной).
Что же делать? Давайте применим propensity score!
Что именно мы сделаем:
- Учим нашу модель для получения propensity score;
- Используем полученный proprensity score (обозначим его
Схему всего процесса удобнее посмотреть на приложенном к посту изображении.
Переходим к более advanced историям. И начнем с x-learner. Объяснять этот meta-learner сложнее, чем предыдущие два (S, T-learner). Но в реализации он не так уж и сложен.
Итак, поехали.
В X-learner у нас две стадии + используется propensity score (о нем я писал ранее):
- На первом шаге делаем все точно по рецепту T-leaner. Напомню: обучаем две модели для наличия и отсутствия treatment;
- На втором шаге мы делаем небольшой "финт ушами" и вычитаем из реальных значений для наличия или отсутствия treatment предсказания для противоположной модели. Например, для отсутствия treatment получим:
M_1(X, T=0) - Y_0
(где M_1
обучена на признаках с наличием treatment, предсказание сделано на признаках с отсутствием treatment, аY_0
- реальные значения отклика без treatment);- Далее обучаем еще две модели (
M'_1, M'_0
), которые предсказывают разность со второго шагаНо, у нас все еще проявляется все та же проблема, что и в T-learner (при нелинейном эффекте мы его видим для одной более сложной модели и не видим для менее сложной).
Что же делать? Давайте применим propensity score!
Что именно мы сделаем:
- Учим нашу модель для получения propensity score;
- Используем полученный proprensity score (обозначим его
e(x)
) для того, чтобы скомбинировать предсказания двух моделей (M'_0 * e(x) + M'_1 * (1 - e(x))
). Если описать логику этого шага просто - то давайте назначим больший вес той модели, которая имела больше данных при обучении. Схему всего процесса удобнее посмотреть на приложенном к посту изображении.
Meta learners. R-learner.
Завершаем серию постов про meta-learners последним типом: R-learner.
Итак, мы все еще хотим оценить CATE. Ранее мы уже рассмотрели несколько вариантов такой оценки.
Еще один вариант был предложен в 2017 году в следующей статье (за авторством Xinkun Nie и Stefan Wager).
Что же мы хотим сделать? А мы хотим построить такую функцию потерь, при оптимизации которой, мы бы получали асимптотически близкий к реальности результат. Ну и (естественно) получали ответ на вопрос: "Какой эффект будет для
Какие у нас тут предположения:
1. Пересечение распределений (что было в заметке про propensity score) вероятности. То есть у нас для каждого объекта есть ненулевой шанс попасть в группу с воздействием (ну и в контроль, соответственно);
2. Решение о попадании в Treatment и результат независимы друг от друга при условии признаков пользователя
И как мы можем записать эту функцию потерь? Расширенную версию я позаимствовал отсюда (см. прикрепленное изображение + обязательно советую прочитать и первоисточник).
Но если упрощать, то:
1. Мы строим две модели для предсказания treatment и количественного значения результата на основании фичей объекта;
2. Используем запись, которая соединяет наши модели в единую связку (формула 1 на изображении + см. Robinson Decomposition по ссылкам из поста);
3. Выражаем оттуда ошибку, берем ее квадрат (формулы 2, 3);
4. Т.к. у нас уже есть две модели предсказания, то мы можем подставить их значения в наши формулы. И минимизировать результирующую функцию, чтобы получить оценку CATE (
То есть при реальном применении это выглядит так:
1. Обучаем две модели с k-fold валидацией;
2. Используем out-of-fold предсказания, чтобы получить остатки для treatment (например, цены товара) и результирующего значения outcome (например, суммарной стоимости покупки);
3. Получаем веса в виде квадрата остатков target;
4. Трансформируем outcome в виде: остатки outcome / остатки target;
5. Учим модель предсказывать трансформированное значение с учетом весов из п.3;
6. На тесте уже предсказываем моделью из п.5.
В итоге, получим очень хорошее приближение к "предсказанию оракула" (как если бы у нас был некий "оракул", который мог бы предсказать, что бы было в реальности, если мы воздействовали на пользователя).
Итак, мы рассмотрели R-learner. Концепция весьма сложная, так что я бы рекомендовал еще почитать дополнительные материалы, особенно эту презентацию. Там все подробно изложено (но страниц там 30, а я несколько ограничен размером поста ;))
Завершаем серию постов про meta-learners последним типом: R-learner.
Итак, мы все еще хотим оценить CATE. Ранее мы уже рассмотрели несколько вариантов такой оценки.
Еще один вариант был предложен в 2017 году в следующей статье (за авторством Xinkun Nie и Stefan Wager).
Что же мы хотим сделать? А мы хотим построить такую функцию потерь, при оптимизации которой, мы бы получали асимптотически близкий к реальности результат. Ну и (естественно) получали ответ на вопрос: "Какой эффект будет для
i-го
объекта при его наборе признаковX_i
?"Какие у нас тут предположения:
1. Пересечение распределений (что было в заметке про propensity score) вероятности. То есть у нас для каждого объекта есть ненулевой шанс попасть в группу с воздействием (ну и в контроль, соответственно);
2. Решение о попадании в Treatment и результат независимы друг от друга при условии признаков пользователя
И как мы можем записать эту функцию потерь? Расширенную версию я позаимствовал отсюда (см. прикрепленное изображение + обязательно советую прочитать и первоисточник).
Но если упрощать, то:
1. Мы строим две модели для предсказания treatment и количественного значения результата на основании фичей объекта;
2. Используем запись, которая соединяет наши модели в единую связку (формула 1 на изображении + см. Robinson Decomposition по ссылкам из поста);
3. Выражаем оттуда ошибку, берем ее квадрат (формулы 2, 3);
4. Т.к. у нас уже есть две модели предсказания, то мы можем подставить их значения в наши формулы. И минимизировать результирующую функцию, чтобы получить оценку CATE (
tau(X_i)
в формулах на изображении).То есть при реальном применении это выглядит так:
1. Обучаем две модели с k-fold валидацией;
2. Используем out-of-fold предсказания, чтобы получить остатки для treatment (например, цены товара) и результирующего значения outcome (например, суммарной стоимости покупки);
3. Получаем веса в виде квадрата остатков target;
4. Трансформируем outcome в виде: остатки outcome / остатки target;
5. Учим модель предсказывать трансформированное значение с учетом весов из п.3;
6. На тесте уже предсказываем моделью из п.5.
В итоге, получим очень хорошее приближение к "предсказанию оракула" (как если бы у нас был некий "оракул", который мог бы предсказать, что бы было в реальности, если мы воздействовали на пользователя).
Итак, мы рассмотрели R-learner. Концепция весьма сложная, так что я бы рекомендовал еще почитать дополнительные материалы, особенно эту презентацию. Там все подробно изложено (но страниц там 30, а я несколько ограничен размером поста ;))
#recsys
Что такое Learning to Rank (LTR)? Pointwise, pairwise, listwise подходы к задаче обучения ранжированию.
Начнем с постановки задачи. Что мы имеем и что хотим получить?
Итак, мы имеем некоторый набор документов
В случае pointwise постановки задачи, мы переформулируем нашу задачу в обычный формат регрессии или классификации. То есть мы поступаем максимально прямолинейно - учим модель предсказывать нечто на метках.
Соответственно, нам нужно знать некие оценки релевантности, иначе у нас таргета не будет. Ну и учитывать мы будем только один элемент, а не всю информацию о множестве, что не очень хорошо.
В случае pairwise подхода, мы переформулируем задачу в виде классификации вида: больше ли релевантность одного документа, чем другого? При этом, задачу можно сформулировать в вероятностном виде:
Увы, даже при таком подходе функция скоринга все еще считает поточечно, так что мы не полностью используем доступную нам информацию.
Ну и в случае listwise подхода, мы пытаемся оптимизировать целевую метрику напрямую. И тут сталкиваемся со сложностью - наши метрики ранжирования не очень-то дифференцируемы (при желании попробуйте дифференцировать DCG).
Получается, нам нужно использовать некую аппроксимацию (ListNet), либо эвристики (например, LambdaRank), позволяющие обойти эту проблему.
Общие принципы мы рассмотрели, в следующих заметках постараюсь раскрыть подходы подробнее.
Что такое Learning to Rank (LTR)? Pointwise, pairwise, listwise подходы к задаче обучения ранжированию.
Начнем с постановки задачи. Что мы имеем и что хотим получить?
Итак, мы имеем некоторый набор документов
D
и запрос q
. И хотим выучить некоторую функцию f(q, D)
, которая бы каждому из документов D
выдавала некий показатель релевантности таким образом, чтобы наиболее релевантные документы находились выше, то есть имели более высокий score. В случае pointwise постановки задачи, мы переформулируем нашу задачу в обычный формат регрессии или классификации. То есть мы поступаем максимально прямолинейно - учим модель предсказывать нечто на метках.
Соответственно, нам нужно знать некие оценки релевантности, иначе у нас таргета не будет. Ну и учитывать мы будем только один элемент, а не всю информацию о множестве, что не очень хорошо.
В случае pairwise подхода, мы переформулируем задачу в виде классификации вида: больше ли релевантность одного документа, чем другого? При этом, задачу можно сформулировать в вероятностном виде:
Pr(i > j) = 1 / (1 + exp(-(s_i - s_j)))
. Если проще, то в следующем формате: если релевантность одного документа выше другого, то вероятность того, что наша функция f
выдаст для него больший score, должна стремиться к 1.Увы, даже при таком подходе функция скоринга все еще считает поточечно, так что мы не полностью используем доступную нам информацию.
Ну и в случае listwise подхода, мы пытаемся оптимизировать целевую метрику напрямую. И тут сталкиваемся со сложностью - наши метрики ранжирования не очень-то дифференцируемы (при желании попробуйте дифференцировать DCG).
Получается, нам нужно использовать некую аппроксимацию (ListNet), либо эвристики (например, LambdaRank), позволяющие обойти эту проблему.
Общие принципы мы рассмотрели, в следующих заметках постараюсь раскрыть подходы подробнее.
#recsys
Сегодня поговорим о ListNet. Что это такое и в чем основная идея подхода?
Как я упомянул в прошлой заметке, при реализации listwise подхода, мы можем использовать аппроксимацию или эвристику. В случае ListNet, мы аппроксимируем нашу реальную функцию потерь похожей, но хотя бы такой, чтобы ее было возможно оптимизировать.
Что же мы делаем?
Если очень просто, то учимся предсказывать некий score для наших элементов из выдачи. По нему и сортируем - получается выдача с учетом релевантности.
Но тут же возникает вопрос - а как нам учиться на всем этом?
Ответ, который дают авторы: давайте отобразим наш набор скоров в вероятностное распределение. Его и будем сравнивать с реальным вероятностным распределением. При этом, мы смотрим на top-1 permutation probability.
Но что это такое?
Если просто - то авторы предполагают, что у нас есть вероятность получить любую перестановку элементов в списке с помощью нашей ранжирующей функции. Но некоторые из этих перестановок более вероятны, чем другие. Соответственно, мы можем оптимизировать правдоподобие получаемых результатов.
Но и здесь наш ждет проблема.
Напрямую оптимизировать такое не выйдет. Оттого и переходят к top-1 permutation probability, что, по сути, является суммой вероятностей перестановок, где n-й элемент списка стоит на первом месте. При этом, авторы показывают, что эта top-1 вероятность эквивалентна экспоненте(score_n) / сумму экспонент всех скоров. Что подозрительно напоминает softmax. Wow! Получается, что нам можно просто использовать softmax и не особо заморачиваться обо всех этих permutation probabilities.
Но как же посчитать разницу между распределениями, чтобы было что оптимизировать?
На выручку к нам приходит дивергенция Кульбака-Лейблера. Весьма классический и типичный подход.
Получается следующая картина:
1. Мы создаем набор признаков query - document (например, это может быть эмбеддинг того и другого, если мы говорим о текстах);
2. Нарезаем тензоры нужного размера (например, для каждого запроса есть выдача по 20 релеватных документов, а эмбеддинги для них имеют размерность 100 -> получаем размерность
3. Учим сеть на результатах, отсортированных по оценкам реальной релеватности (которые можем получить в любом виде: начиная от 0 и 1 для кликов, заканчивая суммой покупки, все зависит от вашей фантазии);
4. В процессе обучения минимизируем KL-дивергенцию.
В итоге, получаем сеть, которая учится ставить score каждому документу в выдаче к запросу, учитывает всю нашу выдачу, а также оптимизирует функцию, близкую к реально желанному результату.
На изображении к посту я добавил обобщенную визуализацию процесса (можно заметить, что в случае RankNet используется несколько иная аппроксимация).
P.S. Дополнительно рекомендую почитать реализацию toy example по ссылке.
Сегодня поговорим о ListNet. Что это такое и в чем основная идея подхода?
Как я упомянул в прошлой заметке, при реализации listwise подхода, мы можем использовать аппроксимацию или эвристику. В случае ListNet, мы аппроксимируем нашу реальную функцию потерь похожей, но хотя бы такой, чтобы ее было возможно оптимизировать.
Что же мы делаем?
Если очень просто, то учимся предсказывать некий score для наших элементов из выдачи. По нему и сортируем - получается выдача с учетом релевантности.
Но тут же возникает вопрос - а как нам учиться на всем этом?
Ответ, который дают авторы: давайте отобразим наш набор скоров в вероятностное распределение. Его и будем сравнивать с реальным вероятностным распределением. При этом, мы смотрим на top-1 permutation probability.
Но что это такое?
Если просто - то авторы предполагают, что у нас есть вероятность получить любую перестановку элементов в списке с помощью нашей ранжирующей функции. Но некоторые из этих перестановок более вероятны, чем другие. Соответственно, мы можем оптимизировать правдоподобие получаемых результатов.
Но и здесь наш ждет проблема.
Напрямую оптимизировать такое не выйдет. Оттого и переходят к top-1 permutation probability, что, по сути, является суммой вероятностей перестановок, где n-й элемент списка стоит на первом месте. При этом, авторы показывают, что эта top-1 вероятность эквивалентна экспоненте(score_n) / сумму экспонент всех скоров. Что подозрительно напоминает softmax. Wow! Получается, что нам можно просто использовать softmax и не особо заморачиваться обо всех этих permutation probabilities.
Но как же посчитать разницу между распределениями, чтобы было что оптимизировать?
На выручку к нам приходит дивергенция Кульбака-Лейблера. Весьма классический и типичный подход.
Получается следующая картина:
1. Мы создаем набор признаков query - document (например, это может быть эмбеддинг того и другого, если мы говорим о текстах);
2. Нарезаем тензоры нужного размера (например, для каждого запроса есть выдача по 20 релеватных документов, а эмбеддинги для них имеют размерность 100 -> получаем размерность
(20, (200))
, т.к. 100*2, ибо запрос + ответ;3. Учим сеть на результатах, отсортированных по оценкам реальной релеватности (которые можем получить в любом виде: начиная от 0 и 1 для кликов, заканчивая суммой покупки, все зависит от вашей фантазии);
4. В процессе обучения минимизируем KL-дивергенцию.
В итоге, получаем сеть, которая учится ставить score каждому документу в выдаче к запросу, учитывает всю нашу выдачу, а также оптимизирует функцию, близкую к реально желанному результату.
На изображении к посту я добавил обобщенную визуализацию процесса (можно заметить, что в случае RankNet используется несколько иная аппроксимация).
P.S. Дополнительно рекомендую почитать реализацию toy example по ссылке.
👍1
#recsys
Learning to Rank: LambdaRank и LambdaMart.
Закончим разговор о learning to rank. Сегодня речь будет о LambdaRank (и вариации для бустингов под названием LambdaMart).
Корневая идея, которая лежит под LambdaRank - это идея о том, что нам вместо самой ошибки нужны только градиенты (стрелочки на изображении к посту). То есть мы можем учесть направление и силу "выталкивания" вверх или вниз по списку. При этом, градиенты можно масштабировать посредством вычисления разницы между NDCG, если элементы поменять местами.
Получаем некоторую эвристику. Если мы используем функцию потерь, которая предложена в статье, мы получаем эмпирическое улучшение NDCG. А большего нам и не надо ;)
В случае LambdaMart, мы подменяем нейронную сеть из LambdaRank градиентным бустингом (собственно, MART тут - Multiple Additive Regression Trees). Подробнее можно почитать в этой статье.
Learning to Rank: LambdaRank и LambdaMart.
Закончим разговор о learning to rank. Сегодня речь будет о LambdaRank (и вариации для бустингов под названием LambdaMart).
Корневая идея, которая лежит под LambdaRank - это идея о том, что нам вместо самой ошибки нужны только градиенты (стрелочки на изображении к посту). То есть мы можем учесть направление и силу "выталкивания" вверх или вниз по списку. При этом, градиенты можно масштабировать посредством вычисления разницы между NDCG, если элементы поменять местами.
Получаем некоторую эвристику. Если мы используем функцию потерь, которая предложена в статье, мы получаем эмпирическое улучшение NDCG. А большего нам и не надо ;)
В случае LambdaMart, мы подменяем нейронную сеть из LambdaRank градиентным бустингом (собственно, MART тут - Multiple Additive Regression Trees). Подробнее можно почитать в этой статье.
👍3
Время пролетело незаметно, а нас уже более 200 человек! 🥳🥳🥳
Спасибо всем, кто меня читает. Надеюсь, вы и дальше будете находить на канале нечто интересное для себя.
Спасибо всем, кто меня читает. Надеюсь, вы и дальше будете находить на канале нечто интересное для себя.
🎉6❤3
#books
Сегодня расскажу про книгу "System design: подготовка к сложному интервью".
В книге описывается полтора десятка кейсов построения ответа на вопросах интервью по системному дизайну. Например, одна из глав про проектирование своего собственного YouTube (иронично, судя по последним новостям).
В целом, книга интересная, но новичку будет сложновата. При этом, там много справочных материалов, полезные советы: как лучше построить вопросы интервьюеру, как вводить предположения, как оценивать ресурсы для решения и сильные/слабые стороны "на глазок".
Мне удалось почерпнуть нечто новое из нее, так что скорее склонен ее посоветовать. Особенно полезна она будет, если готовитесь к интервью по дизайну систем.
Сегодня расскажу про книгу "System design: подготовка к сложному интервью".
В книге описывается полтора десятка кейсов построения ответа на вопросах интервью по системному дизайну. Например, одна из глав про проектирование своего собственного YouTube (иронично, судя по последним новостям).
В целом, книга интересная, но новичку будет сложновата. При этом, там много справочных материалов, полезные советы: как лучше построить вопросы интервьюеру, как вводить предположения, как оценивать ресурсы для решения и сильные/слабые стороны "на глазок".
Мне удалось почерпнуть нечто новое из нее, так что скорее склонен ее посоветовать. Особенно полезна она будет, если готовитесь к интервью по дизайну систем.
👍4🔥1
Т.к. по образованию я - инженер-математик, то не могу пройти мимо и не поздравить всех причастных с днем математика!
Не знаю, почему в России его решили назначить на первое апреля, но уж как есть.
Надеюсь, что у вас все сложится, а плюсы в вашей жизни только приумножатся.
Не знаю, почему в России его решили назначить на первое апреля, но уж как есть.
Надеюсь, что у вас все сложится, а плюсы в вашей жизни только приумножатся.
🔥6❤2🎉1
#libraries
Сегодня на повестке дня библиотека с методами детекции выбросов, сдвигов в данных и adversarial историй - alibi-detect.
Очень разнообразный набор методов. При этом, реализованы методы и для широкого набора типов данных (табличные, тексты, изображения и т.д.). Методы от достаточно классических (isolation forest) до весьма современных (context-aware MMD).
Пока особо в деле ее не попробовал, т.к. случая не было. Но выглядит многообещающе. Как минимум, как baseline.
Сегодня на повестке дня библиотека с методами детекции выбросов, сдвигов в данных и adversarial историй - alibi-detect.
Очень разнообразный набор методов. При этом, реализованы методы и для широкого набора типов данных (табличные, тексты, изображения и т.д.). Методы от достаточно классических (isolation forest) до весьма современных (context-aware MMD).
Пока особо в деле ее не попробовал, т.к. случая не было. Но выглядит многообещающе. Как минимум, как baseline.
Forwarded from Reliable ML
Почему Correlation != Causation
В недавнем посте мы поговорили о том, что корреляция не подразумевает причинно-следственную связь.
Давайте теперь обсудим, почему это может быть так.
Общепринято выделять 4 причины.
1. Пропущенная переменная (Omitted variable). В случае, если Х и Y скоррелированы, причиной их изменения может быть другой, третий фактор F, воздействие которого и заставляет X и Y двигаться вместе (сонаправленно). Поэтому, если цель нашего исследования – изменить Y, изменение Х нам с этим не поможет. К изменению Y приведет только изменение F.
В нашем недавнем посте можно найти ряд примеров, когда корреляция не означает причинно-следственной связи, именно по причине пропущенного фактора. Так, в корреляции наличия астмы и низкой вероятности смерти от пневмонии третьим фактором оказалось регулярное врачебное наблюдение, необходимое при астме и оказывающее значительное влияние на снижение смерти от пневмонии. А для корреляции ЗП и сексуальной активности третьим фактором, по мнению автора исследования, является состояние здоровья.
2. Обратная причинность (Reverse Causality). Корреляция X и Y не подразумевает, что Х влияет на Y, поскольку влияние может быть обратным – Y влияет на Х. Самым известным примером reverse causality считается взаимосвязь курения и депрессии. Здесь возможна как прямая взаимосвязь (курение способствует депрессии), так и обратная (подавленное состояние способствует курению). Другие примеры из экономической теории: уровень дохода и счастье, бедность и безработица, сексуальная активность и уровень ЗП.
3. Смещение выборки (Selection bias). Третья возможная причина, почему корреляция не подразумевает причинно-следственной связи – нерепрезентативность выборки, на основе которой мы делаем выводы, для генеральной совокупности. Пример – исследование факторов роста заработной платы. При проведении подобного исследования мы неизбежно рассматриваем только работающих и, следовательно, получающих ЗП на текущий момент людей и делаем выводы о факторах, влияющих на их доход. При этом в выборку не попадают неработающие люди (потерявшие работу, матери в декрете, официально безработные, и др.), данные о которых могут значимо повлиять на результат.
4. Ошибка измерения (Measurement error). Способ получения данных и его уязвимости также могут влиять на результат. Самый распространенный пример – систематическое искажение данных в опросах. Так, пациенты могут систематически приукрашивать данные о регулярности приема лекарств и занижать – о приеме алкоголя. В опросах про доходы также часто встречается завышение низкого дохода и занижение высокого. При этом не каждая ошибка измерения приводит к неверным выводам о причинно-следственной связи. В некоторых случаях она может быть вполне безобидной.
В недавнем посте мы поговорили о том, что корреляция не подразумевает причинно-следственную связь.
Давайте теперь обсудим, почему это может быть так.
Общепринято выделять 4 причины.
1. Пропущенная переменная (Omitted variable). В случае, если Х и Y скоррелированы, причиной их изменения может быть другой, третий фактор F, воздействие которого и заставляет X и Y двигаться вместе (сонаправленно). Поэтому, если цель нашего исследования – изменить Y, изменение Х нам с этим не поможет. К изменению Y приведет только изменение F.
В нашем недавнем посте можно найти ряд примеров, когда корреляция не означает причинно-следственной связи, именно по причине пропущенного фактора. Так, в корреляции наличия астмы и низкой вероятности смерти от пневмонии третьим фактором оказалось регулярное врачебное наблюдение, необходимое при астме и оказывающее значительное влияние на снижение смерти от пневмонии. А для корреляции ЗП и сексуальной активности третьим фактором, по мнению автора исследования, является состояние здоровья.
2. Обратная причинность (Reverse Causality). Корреляция X и Y не подразумевает, что Х влияет на Y, поскольку влияние может быть обратным – Y влияет на Х. Самым известным примером reverse causality считается взаимосвязь курения и депрессии. Здесь возможна как прямая взаимосвязь (курение способствует депрессии), так и обратная (подавленное состояние способствует курению). Другие примеры из экономической теории: уровень дохода и счастье, бедность и безработица, сексуальная активность и уровень ЗП.
3. Смещение выборки (Selection bias). Третья возможная причина, почему корреляция не подразумевает причинно-следственной связи – нерепрезентативность выборки, на основе которой мы делаем выводы, для генеральной совокупности. Пример – исследование факторов роста заработной платы. При проведении подобного исследования мы неизбежно рассматриваем только работающих и, следовательно, получающих ЗП на текущий момент людей и делаем выводы о факторах, влияющих на их доход. При этом в выборку не попадают неработающие люди (потерявшие работу, матери в декрете, официально безработные, и др.), данные о которых могут значимо повлиять на результат.
4. Ошибка измерения (Measurement error). Способ получения данных и его уязвимости также могут влиять на результат. Самый распространенный пример – систематическое искажение данных в опросах. Так, пациенты могут систематически приукрашивать данные о регулярности приема лекарств и занижать – о приеме алкоголя. В опросах про доходы также часто встречается завышение низкого дохода и занижение высокого. При этом не каждая ошибка измерения приводит к неверным выводам о причинно-следственной связи. В некоторых случаях она может быть вполне безобидной.
👍3
#interview
Что такое MapReduce и как он работает?
MapReduce - это модель распределенных вычислений. Потребность в использовании такого рода модели возникает, когда у нас нет возможности физически обработать данные на одной машине. Разработана в недрах Google еще в 2000-х.
При обработке записей, данные проходят через три стадии:
1. Map - на этой стадии мы применяем некоторую функцию к нашему набору значений (что похоже на обычный map из python). В итоге, мы должны получить некоторое множество пар ключ-значение (при этом, для одной записи множество может быть и пустым). На этой стадии происходит предварительная обработка и фильтрация данных. При этом, уже на этом шаге мы можем разбить наши значения на обработку несколькими машинами;
2. Shuffle - на этой стадии пары ключ-значение разбиваются на отдельные множества по значению ключа. Эти множества послужат входными данными для стадии reduce. Это может быть сильно затратной стадией, т.к. нам придется "гонять" наши данные между машинами;
3. Reduce - на этой стадии мы применяем некоторую функцию, которая производит финальные вычисления над данными, полученными с map шага. Полученные на каждой отдельной машине результаты потом склеиваются на т.н. master-ноде.
К посту прилагаю пример того, как выглядит сам процесс для задачи подсчета слов в тексте.
Что такое MapReduce и как он работает?
MapReduce - это модель распределенных вычислений. Потребность в использовании такого рода модели возникает, когда у нас нет возможности физически обработать данные на одной машине. Разработана в недрах Google еще в 2000-х.
При обработке записей, данные проходят через три стадии:
1. Map - на этой стадии мы применяем некоторую функцию к нашему набору значений (что похоже на обычный map из python). В итоге, мы должны получить некоторое множество пар ключ-значение (при этом, для одной записи множество может быть и пустым). На этой стадии происходит предварительная обработка и фильтрация данных. При этом, уже на этом шаге мы можем разбить наши значения на обработку несколькими машинами;
2. Shuffle - на этой стадии пары ключ-значение разбиваются на отдельные множества по значению ключа. Эти множества послужат входными данными для стадии reduce. Это может быть сильно затратной стадией, т.к. нам придется "гонять" наши данные между машинами;
3. Reduce - на этой стадии мы применяем некоторую функцию, которая производит финальные вычисления над данными, полученными с map шага. Полученные на каждой отдельной машине результаты потом склеиваются на т.н. master-ноде.
К посту прилагаю пример того, как выглядит сам процесс для задачи подсчета слов в тексте.
👍4👎1
#statistics
Сегодня давайте рассмотрим такую вещь, как блочный бутстреп (block bootstrapping).
Блочный бутстреп используется для данных, в которых присутствует корреляция между значениями или ошибками предсказания модели. Обычно, такое возникает при работе с временными рядами (автокорреляция значений в них играет с нами злую шутку), но может быть и при пространственной связи (например, в задачах работы с геоданными, либо с иными данными, имеющими кластерную структуру).
Кратко опишем идею методов блочного бутстрепа. Давайте будем тем или иным образом выбирать готовые блоки из данных, которые сохраняют некоторую структурную целостность исходного набора. С множеством этих блоков мы и будем работать дальше.
Основные методы блочного бутстрапирования:
1. Non-overlapping block bootstrap (NBB) - в данном случае, мы выделяем некоторое множество непересекющихся блоков, которые в дальнейшем используем для бутстрапирования;
2. Moving block bootstrap (MBB) - выделяем множество пересекающихся блоков данных некоторой фиксированной длины, после чего с возвращением выбираем подмножество этих блоков и составляем требуемое множество;
3. Circular block bootstrap (CBB) - здесь мы закольцовываем нашу генерацию, чтобы справляться с ситуациями на концах генерируемых множеств. Например, у нас может быть окно с n=5 и ряд в 100 элементов. Должны ли мы тогда останавливаться на последнем блоке с 96 значения по 100? В случае CBB мы можем просто подставить значения из начала нашей серии, то есть будет, например, блок с 99 значения по 3 (99, 100, 1, 2, 3);
4. Stationary bootstrap (SB) - можно рассматривать, как некоторое улучшение MBB. В данном случае, мы используем еще и случайную длину блоков (и еще случайные точки старта этих блоков). Это позволяет исправить проблему нестационарности получаемых наблюдений.
Подробнее про указанные методы можно почитать в этом посте. Описано весьма неплохо и понятно.
А реализацию части приведенных выше методов можно найти здесь.
Сегодня давайте рассмотрим такую вещь, как блочный бутстреп (block bootstrapping).
Блочный бутстреп используется для данных, в которых присутствует корреляция между значениями или ошибками предсказания модели. Обычно, такое возникает при работе с временными рядами (автокорреляция значений в них играет с нами злую шутку), но может быть и при пространственной связи (например, в задачах работы с геоданными, либо с иными данными, имеющими кластерную структуру).
Кратко опишем идею методов блочного бутстрепа. Давайте будем тем или иным образом выбирать готовые блоки из данных, которые сохраняют некоторую структурную целостность исходного набора. С множеством этих блоков мы и будем работать дальше.
Основные методы блочного бутстрапирования:
1. Non-overlapping block bootstrap (NBB) - в данном случае, мы выделяем некоторое множество непересекющихся блоков, которые в дальнейшем используем для бутстрапирования;
2. Moving block bootstrap (MBB) - выделяем множество пересекающихся блоков данных некоторой фиксированной длины, после чего с возвращением выбираем подмножество этих блоков и составляем требуемое множество;
3. Circular block bootstrap (CBB) - здесь мы закольцовываем нашу генерацию, чтобы справляться с ситуациями на концах генерируемых множеств. Например, у нас может быть окно с n=5 и ряд в 100 элементов. Должны ли мы тогда останавливаться на последнем блоке с 96 значения по 100? В случае CBB мы можем просто подставить значения из начала нашей серии, то есть будет, например, блок с 99 значения по 3 (99, 100, 1, 2, 3);
4. Stationary bootstrap (SB) - можно рассматривать, как некоторое улучшение MBB. В данном случае, мы используем еще и случайную длину блоков (и еще случайные точки старта этих блоков). Это позволяет исправить проблему нестационарности получаемых наблюдений.
Подробнее про указанные методы можно почитать в этом посте. Описано весьма неплохо и понятно.
А реализацию части приведенных выше методов можно найти здесь.
👍2
Forwarded from Love. Death. Transformers.
This media is not supported in your browser
VIEW IN TELEGRAM
Ладно, минутка киберпанка их Шанхая, где в связи с новыми ковидными ограничениями происходит рыбалка на дронах.
👍2
#books
Совсем недавно прочитал книгу "Мама, я тимлид! Практические советы по руководству IT-командой".
По итогу - весьма сильно резонирует с моим опытом. Интересная подача и достаточно обширный набор тем, которые автор успел покрыть в книге. При этом, скорее выжимка идей и опыта, но с примерами и иллюстрациями.
Мне книга показалась весьма четкой и емкой + прочитал весьма быстро (ушло два выходных по несколько часов в каждый из них). Ну и подача с юморком. Что я как раз уважаю (ну и там классные картинки с котиками 🐈).
Единственное, что могу отметить из минусов - сильно устарел пункт про распределенные команды. Мысли и подходы там "доковидные", так что стоит на это сделать скидку, я думаю.
В общем, точно могу порекомендовать тем, кто начинает свою работу в качестве тимлида, либо претендует на эту роль в будущем.
Совсем недавно прочитал книгу "Мама, я тимлид! Практические советы по руководству IT-командой".
По итогу - весьма сильно резонирует с моим опытом. Интересная подача и достаточно обширный набор тем, которые автор успел покрыть в книге. При этом, скорее выжимка идей и опыта, но с примерами и иллюстрациями.
Мне книга показалась весьма четкой и емкой + прочитал весьма быстро (ушло два выходных по несколько часов в каждый из них). Ну и подача с юморком. Что я как раз уважаю (ну и там классные картинки с котиками 🐈).
Единственное, что могу отметить из минусов - сильно устарел пункт про распределенные команды. Мысли и подходы там "доковидные", так что стоит на это сделать скидку, я думаю.
В общем, точно могу порекомендовать тем, кто начинает свою работу в качестве тимлида, либо претендует на эту роль в будущем.
👍6
#statistics
Uplift деревья. Что это и зачем нужно?
Итак, что такое uplift деревья?
У нас есть много разных методов оценки uplift-а (про это понятие я ранее писал, как про CATE: Conditional Average Treatment Effect, но вообще это еще может быть и не индивидуальном уровне, то есть ITE: Individual Treatment Effect) для разных ситуаций (ранее я писал про S,T,X,R learners, то есть подходы с использованием meta-learners). Но они имеют свои минусы (к примеру, при использовании двух разных моделей мы получаем двойную ошибку, при разных типах моделей одна может переобучиться, а другая - недообучиться и т.п.). Хочется взять что-то достаточно привычное, что можно было бы использовать напрямую к данной задаче. На выручку к нам приходят решающие деревья (decision tree).
Итак, мы хотим использовать некоторое дерево, которое в узлах будет по некоему критерию разделять наши группы пользователей. Желательно, чтобы этот критерий был как можно ближе к реальности, то есть позволял отделить наш эффект от воздействия на целевую группу.
Какие для этого есть предложения? Предложение следующее - давайте для критерия разделения использовать разницу между нашими распределениями. Чем больше мы разделим распределение в целевой и контрольной группах - тем ближе подберемся к оценке uplift'а.
Здесь у нас есть несколько вариантов:
1. Дивергенция Кульбака-Лейблера (Kullback–Leibler divergence);
2. Евклидово расстояние (Euclidean distance);
3. Дивергенция хи-квадрат (Сhi-squared divergence, отличается от евклидова расстояния тем, что мы вместо
Получается, что при разбиении мы хотим максимизировать дивергенцию (или разницу) между нашими распределениями.
Казалось бы, все ок, с задачей справились. Но! Возникает новая проблема: у нас начинают появляться неравномерные разбиения с большим количеством контрольных объектов или объектов с воздействием. Приходится модифицировать наш критерий таким образом, чтобы учитывалось и количество объектов в разных группах при разделении на ветви дерева (подробнее можно посмотреть здесь).
Обновленная метрика позволяет получить лучшие результаты. Правда, тут стоит заметить, что это все еще не прямая оптимизация uplift'а, а лишь некоторое приближение. Ну и, конечно же, указанную проблему постарались решить в более поздних работах. Про то, что же предложили в этих работах, я расскажу позже.
А пока предлагаю посмотреть реализацию uplift tree в библиотеке causalml от Uber.
Uplift деревья. Что это и зачем нужно?
Итак, что такое uplift деревья?
У нас есть много разных методов оценки uplift-а (про это понятие я ранее писал, как про CATE: Conditional Average Treatment Effect, но вообще это еще может быть и не индивидуальном уровне, то есть ITE: Individual Treatment Effect) для разных ситуаций (ранее я писал про S,T,X,R learners, то есть подходы с использованием meta-learners). Но они имеют свои минусы (к примеру, при использовании двух разных моделей мы получаем двойную ошибку, при разных типах моделей одна может переобучиться, а другая - недообучиться и т.п.). Хочется взять что-то достаточно привычное, что можно было бы использовать напрямую к данной задаче. На выручку к нам приходят решающие деревья (decision tree).
Итак, мы хотим использовать некоторое дерево, которое в узлах будет по некоему критерию разделять наши группы пользователей. Желательно, чтобы этот критерий был как можно ближе к реальности, то есть позволял отделить наш эффект от воздействия на целевую группу.
Какие для этого есть предложения? Предложение следующее - давайте для критерия разделения использовать разницу между нашими распределениями. Чем больше мы разделим распределение в целевой и контрольной группах - тем ближе подберемся к оценке uplift'а.
Здесь у нас есть несколько вариантов:
1. Дивергенция Кульбака-Лейблера (Kullback–Leibler divergence);
2. Евклидово расстояние (Euclidean distance);
3. Дивергенция хи-квадрат (Сhi-squared divergence, отличается от евклидова расстояния тем, что мы вместо
(p - q)**2
используем ((p - q)**2 / q)
).Получается, что при разбиении мы хотим максимизировать дивергенцию (или разницу) между нашими распределениями.
Казалось бы, все ок, с задачей справились. Но! Возникает новая проблема: у нас начинают появляться неравномерные разбиения с большим количеством контрольных объектов или объектов с воздействием. Приходится модифицировать наш критерий таким образом, чтобы учитывалось и количество объектов в разных группах при разделении на ветви дерева (подробнее можно посмотреть здесь).
Обновленная метрика позволяет получить лучшие результаты. Правда, тут стоит заметить, что это все еще не прямая оптимизация uplift'а, а лишь некоторое приближение. Ну и, конечно же, указанную проблему постарались решить в более поздних работах. Про то, что же предложили в этих работах, я расскажу позже.
А пока предлагаю посмотреть реализацию uplift tree в библиотеке causalml от Uber.
👍3
Какие из тем наиболее интересны?
Anonymous Poll
67%
statistics
33%
books
42%
interview
12%
video
33%
libraries
26%
recsys
26%
management
40%
AB
21%
competition
37%
advice