ML Advertising
1.21K subscribers
137 photos
13 videos
2 files
193 links
Пишу про AdTech, AI и разработку

Для связи: @evgenii_munin
Download Telegram
Хочу рассказать вам о партнёре - сервисе Upgraide.me (GPT x Claude x Mistral x Command R x Dall-e)

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

Почему команда? Одна модель сгенерирует идею, вторая напишет текст, третья найдет ссылочки в интернете, а четвертая сгенерирует иллюстрацию. И все в одном чате, запоминают контекст и становятся помощником #1️⃣в любой профессии.

В бесплатной версии - GPT-4 Omni, Claude 3 Haiku

А по ссылке - новости сервиса, статьи и спрятанные промокоды на скидку ⚡️

И комьюнити с техподдержкой, которая всегда на связи ❗️
🔥4❤‍🔥3🦄2👍1👾1
Проверяем качество данных с Evidently

Evidently - это платформа, которая помогает делать EDA или первичный анализ данных, строить отчеты и оценивать качество модели, если данные изменяются

Сформировать отчет можно следующим образом

report = Report(metrics=[DataQualityPreset(), DataDriftPreset(), RegressionQualityMetric()])
report.run(current_data=current_data, reference_data=reference_data)
report.save_html("dash.html")


Основная логика строится на пресетах (или по-другому метриках). К примеру:

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

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

- RegressionQualityMetric: метрики для оценки качества модели. Например для модели регрессии доступны ME, MAE, MAPE. Также доступны пресеты для классификации и ранжирования и рекомендаций

Также в Evidently есть тесты. Например, мы может задать тест на то, удовлетворяет ли определенная колонка условию, допустим ее значения < 20. Также можно писать тесты не только на пороговые значения, но и на статы для медианы, среднего и т.д.


data_stability = TestSuite(tests=[
TestColumnValueMax(column_name='bathrooms', lt=20),
])
data_stability.run(reference_data=reference_data, current_data=current_data)
data_stability.save_html('tests.html')
🔥71👍1
Weighting Time Series

Как работать с устаревшими данными, особенно на временных рядах?

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

Другой вариант - это sample_weight. В CatBoost он отвечает за то, с какой силой сэмплы будут влиять на обучение. Делается это прямо в методе fit


model = CatBoostClassifier()
model.fit(
X_train,
y_train,
sample_weight=train_weight)


Либо можно сделать через объект Pool, тогда зададим еще и веса для валидационной выборки


model = CatBoostClassifier()
model.fit(
X = Pool(X_train, y_train, weight=train_weight),
eval_set = Pool(X_test, y_test, weight=test_weight)
)


Объект с весом 0.1 будет вносить вклад в обучение примерно в 10 раз меньше чем с весом 1.0.

#mltips
🔥6👍32
Как работает SSP?

# Part 1

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

Все начинается, когда пользователь заходит на сайт с рекламным слотом. В этот момент паблишер трекает пришедшего пользователя и отправляет на Prebid Bid Request о том, что нужно проводить аукцион. В составе Bid Request паблишер также передает список партнерских SSP, которые могут биддить на слотах (или по-другому adUnits) на его сайте. Также в паблишер прикрепляет в запросе характерные для каждого SSP параметры.


bids: [{
bidder: 'appnexus',
params: {
placementId: 13144370
}
},
{
bidder: "adyoulike",
params: {
placement: "e622af275681965d3095808561a1e510"
}
}]


Далее также на браузере запрос обрабатывается кодом Prebid.js, который рассылает его по разным SSP через их соответствующие Bid Adapter'ы.

1️⃣ Placement Call
В момент, когда запрос приходит на SSP, тригерится первый внутренный ивент placementCall. SSP сервер принимает POST запрос на ставку.

Далее внутри SSP происходят различные проверки этого запроса, например
- SSP отправляет запрос на Double Verify для проверки сайта на MFA (Made For Advertising) и Brand Safety
- Запрос проверяется на наличие ошибок: adUnit not found, SDK deprecated, publisher blacklisted etc.


2️⃣ Bid Request Hydration
После то, как все проверки корректности запроса проведены, он обогащается данными о пользователе (геолокация, статы User Agent). Эти данные добываются разными способами: с помощью 1st/ 3rd party-cookie (как работают куки мы рассматривали в предыдущих постах раз, два), Google Privacy Sandbox, при запросе на третье-сторонние Data Management платформы вроде Exelate.

Также на этом этапе запускаются первые ML модели, которые предсказывают
- P(bid | request) вероятность хотя бы одно бида в DSP аукционе при условии реквеста
- P(impression | ssp_hb_win) вероятность показа при условии победы SSP в Prebid аукционе


3️⃣ DSP Bid Request
После того, как проверки и фильтры на стороне SSP пройдены запрос рассылается на DSP для ставки во внутреннем SSP аукционе. Предарительно SSP кастует запрос в стандартный формат Open RTB 2.5. Также SSP выставляет floor price, минимальную цены, ниже которой ставки не принимаются.

Здесь также запрашивается ML модель, которая предсказывает P(bid_dsp_i != null & is_not_timeout) вероятность ставки от конкретного DSP. Это нужно, поскольку 95% RTB бид реквестов, отправляются в пустоту и не получают ответов от DSP. Таким образом экономятся ресурсы на HTTP запросы.


#adtech
🔥9👍54
Optuna для препроцессинга данных

Как правило оптуну воспринимают исключительно, как инструмент оптимизации гипер-параметров модели. Но ее возможности несколько шире. Например, можно повесить на нее и препроцессинг

Предположим, у нас есть датасет, а внем колонки с пропусками. От колонок с большой долей пропусков нам нужно избавляться.
- Чтобы понять, колонки с какой долей пропусков (70%, 80%, 90% etc) удалять, мы сначала подсчитываем это значение в каждой колонке.
- Затем в цикле генерируем количество пропусков, которое хотим оставить
- Отбираем колонки по этому количеству
- Формируем датасеты для обучения и валидации


nulls_perc = (X.isna().sum() / X.shape[0] * 100).astype(int).sort_values(ascending=False)

def objective(trial):
params = {
'objective': 'regression',
'metric': 'mse',
'learning_rate': trial.suggest_float('learning_rate', 1e-5, 0.7, log=True),
'num_leaves': trial.suggest_int('num_leaves', 20, 150),
'verbose': -1
}

nulls_max = trial.suggest_int('nulls_max', 10, 100)
f_cols = list(nulls_perc[nulls_perc < nulls_max].index)

X_train = train[f_cols]
X_test = test[f_cols]

model = lgbm.train(
params = params,
train_set = lgbm.Dataset(X_train, y_train),
valid_sets = lgbm.Dataset(X_test, y_test),
verbose_eval = None
)

score = model.best_score['valid_0']['l2']
print(score, len(f_cols))

return score

study = optuna.create_study(direction='minimize')
study.optimize(objective, n_trials=3000, timeout=300)


Кроме фильтрации колонок с пропусками можно удалять константные колонки, перебирать значения по заполнению пропусков и делать много других задач
👍9🔥5
👍1
Floor Price Optimization in RTB Auctions

Хочу сделать разбор статьи по оптимизации floor прайса в RTB аукционах в Yahoo Ad Exchange.

1️⃣ Какая мотивация?
Floor price (или еще Reserved price) - минимальная цена, ниже которой ставки не принимаются. Это также минимальная цена, которую выплачивает биддер в случае победы. Выставляется паблишером и характеризует в какой-то степени ценность продаваемого инвентаря.

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

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

2️⃣ Что по статье?
Задача оптимизации ставится следующим образом:

Целевая функция 

eRev(floor | X) = rev(floor | X) + ADXRev * proba (bids < floor | X)


- т.е. берется выручка как функция от флора при условии фичей (девайс, user-agent, dsp)
- если на бид реквест все биды ниже флора, то Yahoo отправляют реквесты на Google Ad Exchange и через него продают инвентарь

постановка задачи: найти такой флор, чтобы максимзировать суммарную выручку floor * = argmax eRev(floor | X)
- rev(floor | X) представляется в виде интеграла
- rev(floor | X) = sum(k_i * sum(bid_i * mult(F(bid_i | floor, X))). Здесь суммарную выручку считают как интеграл от бида ДСП  умноженного на функциую распределения бида ДСП при условии флора. k_i = {0, 1} и нужен для того, если ДСП бидить или не бидит. Аналогичный интеграл приводится и для Google ADX

далее оценивают распределение F(bid_i | floor, X)  из исторических данных как распределение Weibull’а с параметрами scale, shape .
- чтобы нащупать кривую F рандомизируют флоры и логируют значения бидов. При этом отсекают 95% квантиль, чтобы убрать выбросы. Данные берут за 7 дней
- далее оценивают параметры  scale, shape для F. Здесь просто фитят это распределение на гистограмму, полученную с прошлого шага
- далее решают задачу максимизации rev(floor | X) , после того как узнали параметры распределения F. При этом считают флор отдельно для связки (placement, site, publisher, DSP)
- после этого пушат флор в SSP
🔥32👍2
Yahoo Ad Exchange- Optimizing Floors in First Price Auctions.pdf
1.3 MB
Также сама статья по оптимизации флора
👍2🔥1
Привет! Если вы интересуетесь внутренней кухней и инсайтами Avito.Tech, то рекомендую вам канал big_ledovsky.

Его ведет Александр Ледовский, Team Lead команды монетизации Avito.

У себя в постах я уже рассказывал о его выступлении на DataFest'е, например по дискуссии на тему рекламных аукционов с ребятами из Яндекс Директ и Ozon. Несмотря на то, что бизнесы маркетплейса и display-рекламы отличаются друг от друга, многие технические задачи и модели очень схожи, например,

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

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

Кроме технической части здесь вы сможете узнать о буднях DS команд в Avito.Tech, актуальные вакансии, а также полезные советы о том, как сохранять work-life баланс, будучи менеджером команды.

Го подписываться! 🔥
👍3🔥2
Ранее я рассказывал про метод Adversarial Validation. Он помогает проверять, приходятся ли фичи из train/ test из одного распределение. Эта задача также называется ковариационный сдвиг между фичами в выборках

Несмотря на то, что это очевидный недостаток в данных, мы можем попробовать использовать его в свою пользу
- С помощью классификатора Adversarial Validation на train/ test для каждого объекта трен. выборки возьмем его вероятность принадлежности к тесту P(y=1)
- Далее будем использовать полученную вероятность как вес сэмпла при обучении модели
- Модель при обучении будет обращать больше внимания на примеры, схожие с тестовой выборкой

Такой метод заходит на Каггле, где наша цель - это заточиться под приватный лидерборд с долей тестовой выборки. В индустриальных проектах с такими финтами нужно быть осторожней, поскольку появляется риск переобучения, но в целом метод докидывает в модель
🔥5👍2
Как работает SSP?

# Part2

Итак, в прошлом посте о работе SSP мы остановились на отправке RTB запросов на DSP после их предварительной фильтрации.

▶️ Auction Resolution
Допустим, мы получили ответ от некоторых DSP, и теперь можем разрешить аукцион и выбрать победителя. Внутренний аукцион, как правило, первой цены, значит победитель платит свою ставку.

На этом же этапе происходят следующие вещи
- SSP создает xml файл VAST, в котором прописываются ставка, ссылка на креатив, его формат, и tracking ивенты (это более актуально для видео, где трекаются inview, start, midpoint, complete)
- Если SSP закупает инвентарь у паблишера напрямую, и цель рекламной кампании забидевшего рекламодателя CPM, т.е. branding показа, то мы минуем Prebid аукцион. И в этот же момент триггериться биллинг ивент, и SSP платит паблишеру.
- Также проверяем креатив на наличие ошибок error-vast перед тем, как его отправить паблишеру (например, формат креатива не соответствует заявленному на слоте, или ломаная ссылка в VAST)

Ниже приведен пример, как может выглядеть VAST файл

<VAST version="3.0">
<Ad id="20001" sequence="1">
<InLine>
<AdSystem version="1.0">Criteo</AdSystem>
<AdTitle>Adidas Video Ad</AdTitle>
<Description>VAST 3.0 compliant video ad</Description>
<Advertiser>Adidas</Advertiser>
<Pricing model="CPM" currency="USD">25.00</Pricing>
<Impression><![CDATA[https://criteo.com/impression]]></Impression>
<Creatives>
<Creative sequence="1" AdID="20001">
<Linear>
<Duration>00:00:30</Duration>
<TrackingEvents>
<Tracking event="complete"><![CDATA[https://sample-ssp.com/tracking/complete]]></Tracking>
</TrackingEvents>
<MediaFiles>
<MediaFile delivery="progressive" type="video/mp4" bitrate="500" width="640" height="360" scalable="true" maintainAspectRatio="true">
<![CDATA[https://sample-ssp.com/mediafile.mp4]]>
</MediaFile>
</MediaFiles>
</Linear>
</Creative>
</Creatives>
</InLine>
</Ad>
</VAST>



▶️ Header Bidding SSP Bid Response
В случае, если SSP бидит на Prebid, то она прокидывает полученную ранее ставку DSP с модификаторами и вычтенной маржой. Формулу ставки SSP можно представить в следующем виде


ssp_price = clearing_price * (1 - margin) * P(impression|auction_resolved) * bid_modifier


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


▶️ SSP Header Bidding Win
Если SSP победила в HB аукционе, то триггерится ивент ssp_hb_win. Prebid отсылает уведомление о победе, а SSP отправляет ему tag VAST с креативом. В этот момент SSP оплачивает инвентарь паблишера в размере своей ставки.


▶️ Impression
Собственно, сам ивент показа. Он триггерится в момент, когда пользователь доскролил до Ad слота и ему виден пиксель, заранее размещенный на слот. На показе DSP платит SSP clearing_price. Из этой цены аккумулируется средний CPM, который можно видеть в Yandex Direct или Google DV360 при отслеживании кампании

Также на моменте показа тригеррятся ML модели предсказывающие полноту показа (для видео) и клики для performance кампаний. В зависимости от цели кампании ее биллинг ивенты смещаются соответсвенно на complete или click
- Viewability: P(inview | impression)
- Compeltion: P(complete | impression)
- CTR: P(click | impression)

#adtech
🔥4👍2
▶️ Разбираем форматы рекламы на YouTube

In-Stream рекламные слоты YouTub'а, это отдельная эко-система форматов, которая почти всегда закупается через DV360 DSP Гугла. Сегодня разберем эти форматы, их назначение и эффективность.

Среди нашей аудитории есть ребята, работающие в AdOps, поэтому этот материал будет интересен для вас.

Заодно поэкспериментирую с новыми постами

Форматы In-Stream рекламы
- Trueview Skippable
- Trueview Unskippable
- Bumper
- Short
- In-Feed

Каждый адаптирован под разные KPI цели кампании CPM (показы + охват) или CPCV (полнота досмотров). Также можно закупать пакеты форматов


Video Reach Campaign = bumper + skippable + shorts + in-feed
Video Views Campaign = skippable + shorts + in-feed


На skippable формате удобно применять модификаторы ставки, которая выставляется в DV360, чтобы рулить скоростью расхода суточного бюджета кампании. На других форматах, заточенных больше на показы модификаторы также работают, но не так эффективно.
👍2🔥2
Немного инфографики. Подкапотное описание команд Docker для образов и контейнеров вдобавок к шпаргалке.

Сохраняем к себе!
👍5