TL; DR; В этой статье дается методика создания алгоритма машинного обучения для прогнозирования в качестве компании, занимающейся рекламным видео в Интернете, следует ли нам показывать рекламный видеоролик пользователю или нет, например, приносит ли оно достаточный доход.

Ссылка на полный код записной книжки Jupyter: http://nbviewer.jupyter.org/github/BenseddikM/teads_challenge/blob/fd585e96ceb2983b8f75260a7cf1c80974134fe7/teads_challenge.ipynb

В рамках собеседования я недавно участвовал в опросе данных для компании, занимающейся онлайн-рекламой, которая предлагает «решения для видеорекламы out-stream, которые входят в состав премиального редакционного контента и работают на всех устройствах». Я подумал, что задача была очень интересной, поскольку проблема типичной онлайн-рекламы, и проведенный мной анализ мог бы стать введением в использование анализа данных и машинного обучения в полевых условиях.

Контекст

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

  • Мы не показываем видео: Стоимость = 0, Доход = 0,
  • Прибыль = 0 Показываем видео, которое не смотрят достаточно долго: Стоимость ›0,
  • Доход = 0, Прибыль = -Стоимость.

Мы показываем видео, которое смотрят достаточно долго: Стоимость ›0, Доход› 0, Прибыль = Доход-Стоимость.

Описание данных

Данные представляют собой файл csv, содержащий 100000 примеров показа видеообъявлений. Этот журнал содержит следующие столбцы:

  • creative_id: уникальный идентификатор видео, которое было показано пользователю.
  • user_operating_system: операционная система (ОС) пользователя.
  • user_device: тип пользовательского устройства.
  • average_seconds_played: среднее количество секунд, в течение которых пользователь обычно просматривает видео (только если мы уже знаем пользователя, на основе его истории).
  • Стоимость: стоимость, которую нам пришлось заплатить за показ видео.
  • доход: доход от просмотра этого видео.

Исследование данных

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

Мы уже можем сделать некоторые предположения, посмотрев на первые 10 строк нашего набора данных:

  • creative_id содержит идентификаторы, которые повторяются в различных наблюдениях. Это означает, что связанное видео присутствует в наборе данных несколько раз и отображается различным пользователям в журнале. Позже мы сможем получить некоторую информацию, относящуюся к самому видео, сгруппировав наблюдения с одинаковым creative_id и просмотрев общие характеристики.
  • В нашем наборе данных есть 2 столбца категориальных данных: user_operating_system и user_device. Из их описания мы можем подумать, что они сильно коррелированы, потому что пользовательские устройства являются платформами для разных пользовательских ОС. Необходимо иметь представление о распределении каждой категории в этих двух столбцах по нашему набору наблюдений.
  • Мы заметили, что average_seconds_played содержит значения NaN. Эти значения «NaN» не описывают отсутствующие данные, а описывают пользователей, о которых мы раньше не имели представления. Мы должны обращаться с этими значениями осторожно, потому что замена этих значений «NaN» неверной информацией приведет к сильному смещению в нашем наборе данных.
  • Стоимость и Доход - это два непрерывных значения, которые хранятся в DataFrame. Мы хотели бы взглянуть на их распределение и получить некоторое представление о тенденциях прибыли для каждого отображаемого видео.

››› Мы рассмотрим каждый вопрос следующим образом:

1) Статистика отображаемых видео:

Количество уникальных видео в журнале: 936
Распределение количества отображений каждого видео в журнале:

Распределение общего дохода от уникального видео:

Распределение среднего дохода по сравнению со средним значением стоимости уникального видео:

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

Выручка зависит от количества просмотров видео, что является нормальным явлением. Диапазон общих доходов от видео составляет от 0 до ~ 50.

Третий график распределения ясно показывает нам, что есть видео, которые не приносят прибыли: среднее [стоимость] ›среднее [доход], и часть видео, которые имеют тенденцию быть прибыльными: среднее [стоимость] ‹означает [доход], как видно по перекрывающимся линиям распределения.

2) Анализ категориальных данных:

  • Различные операционные системы:
['Android' 'Windows' 'iOS' 'macOS' 'OS X' 'Fire OS' 'Linux' 'Chrome OS' 'BlackBerry OS' 'unknown' 'BSD' 'RIM OS']
  • Различные пользовательские устройства:
[‘Phone’ ‘PersonalComputer’ ‘Tablet’ nan ‘ConnectedTv’]

  • Видео, отображаемые на персональном компьютере и в ОС Windows, являются наиболее часто встречающимся типом видео в файле журнала.
  • Категория Телефон также занимает большую часть отображаемых видео, при этом IOS является доминирующей категорией ОС.
  • IOS присутствует на платформах Телефон и Планшет.

3) Информация о значениях NaN в наборе данных и столбце average_seconds_played:

  • Доля роликов с неизвестными пользователями: 61,828%, а их количество в файле журнала: 61828.
  • Доля роликов с известными пользователями: 38,172%, а их количество в лог-файле: 38172.
  • Общее количество видео в журнале: 100000.

  • Существует большое количество наблюдений с неизвестными пользователями, и, следовательно, большое количество наблюдений со значениями "NaN" в столбце average_seconds_played.
  • Даже известный пользователь, у которого нет "NaN" в average_seconds_played, обычно смотрел рекламные ролики в течение 0 секунд.
  • Есть часть пользователей, которые обычно смотрели рекламные ролики более 10 секунд.
  • Небольшое количество наблюдений с пропущенными значениями в столбцах user_device (8 строк). Мы сбросим их позже. Однако мы не будем отбрасывать значения NaN из столбца average_seconds_played, мы обработаем его по-другому в следующих разделах.

Общие вопросы

1) Маржа, определяемая как (доход - затраты) / доход, какова наша глобальная маржа на основе этого журнала?

Глобальная маржинальная прибыль файла журнала составляет: 27,1907%.

2) Можете ли вы придумать другие интересные показатели для оптимизации?

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

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

  • Аналогично валовой прибыли мы можем представить себе маржу ROAS: Рентабельность затрат на рекламу, рассчитываемую следующим образом:

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

  • Мы также должны учитывать объем: долю рынка для каждого типа пользователей ОС, выраженную в процентах видео, представленных для каждого типа пользователей.

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

  • Еще одним важным показателем, который мы хотели бы оптимизировать, является показатель Общая ценность клиента или CLTV. Это позволяет нам анализировать стратегию приобретения и оценивать маркетинговые затраты. Грубо говоря, CLTV - это прогнозируемый доход, который клиент будет генерировать в течение своей жизни, или, как выражено в его упрощенной версии уравнения (существует множество вариантов):

В то время как:

m = валовая прибыль или вклад в расчете на одного клиента.

r = коэффициент удержания клиента (годовой) или, в нашем случае, среднее время воспроизведения видео в секундах на одного клиента.

i = годовая ставка дисконтирования или процентная ставка, используемая для расчета приведенной стоимости будущего денежного потока.

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

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

3) Какие операционные системы являются наиболее прибыльными?

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

››› Само по себе это мнение является необъективным, поскольку мы не принимаем во внимание «объем» или долю рынка, а также другие показатели, которые могут показать нам больше о доле прибыли.

В первую очередь мы сосредоточимся на доле рынка, мы заметили, что IOS, Windows, Android и OSX явно впереди. с более чем 96,75% от общего объема рынка, как показано ранее. Другие типы пользовательских ОС, такие как BSD, BlackBerry OS… значительно отстают

3 лидера, взятые только из общего количества отображаемых видео. Это подтверждает, что даже если у нас высокий уровень валовой маржи, как было показано ранее, например, с BSD, мы не можем сказать, что это самая прибыльная ОС.

››› Но в чем разница между прибылью и выручкой в ​​целом для каждой ОС?

Опять же, как и в случае с рыночной долей, IOS, Windows, Android и OSX занимают лидирующие позиции по показателям чистой прибыли и чистой выручки.

››› Как насчет того, чтобы посмотреть на устройства пользователей и сегментировать представление доходов / расходов с учетом этого параметра?

IOS и Android вытесняют платформы Телефон и Планшет. Хотя IOS явно впереди, особенно в индустрии планшетов. С другой стороны, Windows явно лидирует на платформе PersonalComputer, далеко впереди OSX и macOS.

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

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

››› Мы можем однозначно заключить, что: IOS, Windows, Android, OSX - самые прибыльные категории операционных систем для пользователей.

Машинное обучение - прогнозная модель

1) Как мы могли бы использовать эти исторические данные, чтобы предсказать событие, которое мы выиграем от дохода (т. е. доход ›0) в наборе данных, где доход еще не известен?

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

2) Вычислите точность прогнозов по хорошо подобранному алгоритму и прокомментируйте результаты.

  • Затем важно очистить данные: мы должны обрабатывать значения 'NaN' в average_seconds_played таким образом, чтобы не искажать набор данных. , и мы не можем отбросить эти наблюдения, потому что на самом деле это не «недостающие данные».
  • Следующим шагом будет создание релевантных функций для проблемных. Цель состоит в том, чтобы получить максимум информации, которая объяснит данные и их отношение к этикеткам.
  • Мы также должны обрабатывать категориальные данные, чтобы передать их алгоритму машинного обучения. Мы должны преобразовать каждый категориальный столбец в числовые значения с помощью OneHotEncoder или фиктивных переменных.
  • Мы должны выбрать релевантную метрику оптимизации, чтобы классифицировать хорошие результаты классификации модели.
  • Мы должны выбрать алгоритм обучения классификации, который хорошо подходит для категоризированных данных. Также важно стандартизировать и масштабировать данные и обрабатывать несбалансированные данные.
  • Затем мы разделим наши данные на обучающую и тестовую части и обучим модель на train_dataперекрестной проверкой и некоторая регуляризация, чтобы избежать переобучения) и подтвердите его выбранной метрикой для оптимизации на тестовых данных.
  • Наконец, мы оптимизируем модель, настроив гиперпараметры модели с помощью поиска по сетке по диапазону возможных значений.

Мы создаем новые функции на основе указанных столбцов и очищаем "average_seconds_played" от значений "NaN":

  • Мы добавляем столбец ‘viewer_type’, который содержит 0, если ‘average_seconds_played’ == ‘NaN’, 1, если 0 ‹=’ average_seconds_played ’‹ 10 и 2, если ‘average_seconds_played’ ›10
  • Мы добавляем столбец «known_viewer», который содержит 0, если «average_seconds_played» == «NaN», иначе: 1
  • Мы заполняем столбец «average_seconds_played» нулями вместо значений «N / A».
  • Мы добавляем среднее значение доходов от видео и среднее значение «средних_секунд, воспроизведенных» на видео.

DataFrame с новыми функциями:

Index([‘creative_id’, ‘user_operating_system’, ‘user_device’, ‘average_seconds_played’, ‘cost’, ‘revenue’, ‘watched’, ‘viewer_type’,’known_viewer’, ‘avg_revenue_vid’, ‘mean_avg_sec_vid’], dtype=’object’)

Сбалансированы ли наши данные?

Мы видели, что распределение доходов имеет тенденцию к высокой концентрации выше 0, что создает дисбаланс в наборе данных (большое количество y = 0). Это создает дисбаланс в сигнале, и нашей модели будет сложно уловить разницу между двумя классами.

››› Наши данные действительно несбалансированы.

Мы перейдем к созданию новых выборок из класса меньшинства (здесь y = 1 или доход ›0) из существующего набора данных с помощью метода начальной загрузки. Это усилит сигнал класса меньшинства в модели, не слишком сильно изменяя характеристики данных (распределения).

New Upsampled data classes count: 1    72951
0    72951
Name: watched, dtype: int64.
New size of dataset: 145902

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

Features with dummy variables: Index(['average_seconds_played', 'cost',
'watched', 'viewer_type',
'known_viewer', 'avg_revenue_vid', 'mean_avg_sec_vid',
'user_operating_system_Android', 'user_operating_system_BlackBerry O
'user_operating_system_Chrome OS', 'user_operating_system_Fire OS',
'user_operating_system_Linux', 'user_operating_system_OS X',
'user_operating_system_RIM OS', 'user_operating_system_Windows',
'user_operating_system_iOS', 'user_operating_system_macOS',
'user_operating_system_unknown', 'user_device_ConnectedTv',
'user_device_PersonalComputer', 'user_device_Phone',
'user_device_Tablet']

Мы разделяем данные по обучению и тестированию с соотношением 80% -20%. Мы также применяем стандартный скейлер на поездах и тестовых наборах.

››› Мы будем использовать RandomForestClassifier для выполнения учебной задачи.

Причины выбора Р.Ф. среди других алгоритмов машинного обучения:

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

Параметры нашей первой модели Радомского леса:

RandomForestClassifier(bootstrap=True, class_weight=None,       criterion='gini',max_depth=15, max_features='auto', max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=20, n_jobs=-1, oob_score=False, random_state=None, verbose=0, warm_start=False):

RF AUC score on train : 0.8001581196725515
RF AUC score on test : 0.73146329717649

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

А как насчет важности функции, определенной на основе модели?

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

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

Наконец, мы проверяем матрицу путаницы на тестовом наборе для нашей модели:

Похоже, что наша модель не борется с classify y = 0. Это означает, что модель хорошо обучена обнаруживать неприбыльное видео. Хотя эту модель путают с классом y = 1, и она дает сильно присутствующую ошибку типа 2 с большим количеством ложноотрицательных прогнозов.

››› Теперь мы настроим наш алгоритм. Мы выполним поиск по сетке с перекрестной проверкой.

Поиск по сетке не содержит большого количества параметров, чтобы избежать тяжелых вычислений. Мы проведем перекрестную проверку данных в трех случаях (cv = 3), чтобы избежать переобучения и уменьшить расхождение между моделями. Мы убеждаемся, что метрикой скоринга является AUC при выполнении поиска по сетке.

Результаты поиска по сетке cv:

[mean: 0.72772, std: 0.00257, params: {'n_estimators': 20, 'n_jobs': 2,'max_depth': 15}, 
mean: 0.73316, std: 0.00298, params: {'n_estimators': 500, 'n_jobs': 2, 'max_depth': 15},
mean: 0.73346, std: 0.00276, params: {'n_estimators': 1000, 'n_jobs': 2,
'max_depth': 15},
mean: 0.74785, std: 0.00249, params: {'n_estimators': 20, 'n_jobs': 2,
'max_depth': 20},
mean: 0.75246, std: 0.00200, params: {'n_estimators': 500, 'n_jobs': 2,
'max_depth': 20},
mean: 0.75249, std: 0.00204, params: {'n_estimators': 1000, 'n_jobs': 2,
'max_depth': 20},
mean: 0.75167, std: 0.00131, params: {'n_estimators': 20, 'n_jobs': 2,
'max_depth': 25},
mean: 0.75571, std: 0.00144, params: {'n_estimators': 500, 'n_jobs': 2,
'max_depth': 25},
mean: 0.75580, std: 0.00150, params: {'n_estimators': 1000, 'n_jobs': 2, 'max_depth': 25}]

››› Характеристики нашей модели немного улучшились. Однако оценка не слишком высока, и мы можем улучшить качество наших прогнозов.

Некоторые идеи по улучшению модели:

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

Спасибо, что прочитали мою первую статью. Пожалуйста, не стесняйтесь обращаться ко мне, если у вас есть какие-либо вопросы.