Отправка кодов скидок избранным клиентам для увеличения прибыли

TL; DR В этой части вы создадите модель логистической регрессии с использованием Python с нуля. В процессе вы узнаете об алгоритме градиентного спуска и воспользуетесь им для обучения своей модели.

Серия "Машинное обучение с нуля":

  1. Умные скидки с логистической регрессией
  2. Прогнозирование цен на жилье с помощью линейной регрессии
  3. Построение дерева решений с нуля в Python
  4. Извлечение цветовой палитры с кластеризацией K-средних
  5. Анализ настроений в обзоре фильма с помощью Наивного Байеса
  6. Система рекомендаций музыкальных исполнителей с использованием стохастического градиентного спуска
  7. Классификация имиджа модного товара с помощью нейронных сетей
  8. Создайте агента по вождению такси в постапокалиптическом мире с помощью обучения с подкреплением

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

Полная записная книжка с исходным кодом (Google Colaboratory):



Данные

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

Давайте загрузим данные во фрейм данных Pandas:

И посмотрите на это:

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

Принятие решений с помощью логистической регрессии

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

Некоторые проблемы, которые можно решить с помощью логистической регрессии, включают:

- Электронная почта - определение того, является ли это спам или нет
- Онлайн-транзакции - мошеннические или нет
- Классификация опухолей - злокачественный или доброкачественный
- Обновление клиента - купит ли клиент премиум-обновление или нет

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

и установите 0: отрицательный класс (например, электронная почта не является спамом) или 1: положительный класс (например, электронная почта является спамом).

Разве мы не можем просто использовать линейную регрессию?

Линейная регрессия - еще одна очень популярная модель. Он работает в предположении, что наблюдаемые явления (ваши данные) можно объяснить прямой линией.

Переменная ответа y линейной регрессии не ограничена в пределах интервала [0, 1]. Из-за этого довольно сложно принимать двоичные решения на основе его вывода. Таким образом, не подходит для наших нужд.

Модель логистической регрессии

Учитывая нашу проблему, нам нужна модель, которая использует 1 переменную (предиктор) (x_1 -amount_spent), чтобы предсказать, следует ли нам отправлять скидку покупателю.

где коэффициенты w_i - параметры модели. Пусть вектор коэффициентов W будет:

Тогда мы можем представить h_w(x) в более компактной форме:

Это модель линейной регрессии.

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

Для логистической регрессии мы хотим изменить это и ввести другую функцию g:

Мы собираемся определить g как:

куда

g также известен как сигмовидная функция или логистическая функция. После замены получаем:

для нашей гипотезы.

Более пристальный взгляд на сигмовидную функцию

Интуитивно мы собираемся использовать сигмовидную функцию «поверх» модели линейной регрессии, чтобы ограничить ее в пределах [0; +1].

Напомним, что сигмовидная функция определяется как:

Давайте переведем это в функцию Python:

Графическое представление сигмовидной функции:

Выглядит знакомо, правда? Обратите внимание, как быстро он сходится к -1 или +1.

Как мы можем найти параметры для нашей модели?

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

Функция потерь

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

Которая также известна как функция Логарифмическая потеря или кросс-энтропийная потеря.

Мы можем сжать вышеуказанную функцию в одну:

куда

Давайте реализуем это на Python:

Подход # 1 - опробовать число

Давайте представим 3 числа, которые представляют коэффициенты w0, w1, w2.

loss: 25.0 predicted: 0.999999999986112 actual: 0.0

К сожалению, я довольно ленив, и такой подход кажется мне слишком трудоемким. Перейдем к следующему:

Подход # 2 - попробуйте много чисел

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

0.0 
0.0 
0.0 
6.661338147750941e-16 
9.359180097590508e-14
1.3887890837434982e-11 
2.0611535832696244e-09 
3.059022736706331e-07 
4.539889921682063e-05 
0.006715348489118056 
0.6931471805599397 
5.006715348489103 
10.000045398900186 
15.000000305680194 
19.999999966169824 
24.99999582410784 
30.001020555434774 
34.945041100449046 
inf 
inf

Удивительно, но первое значение параметра, которое мы попробовали, принесло нам убыток равный 0. Это ваш счастливый день или так будет всегда? Ответ оставляем читателю в качестве упражнения :)

Подход № 3 - Градиентный спуск

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

В машинном обучении мы используем алгоритмы градиентного спуска, чтобы найти «хорошие» параметры для наших моделей (логистическая регрессия, линейная регрессия, нейронные сети и т. Д.).

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

Хорошо, но как мы можем найти этот градиент? Нам нужно найти производную нашей функции стоимости, поскольку наш пример довольно прост.

Первая производная сигмовидной функции

Первая производная сигмовидной функции определяется следующим уравнением:

Полный текст можно найти здесь.

Первая производная функции стоимости

Напомним, что функция стоимости была задана следующим уравнением:

Данный

Получаем первую производную функции стоимости:

Обновление наших параметров W

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

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

Алгоритм градиентного спуска

Алгоритм, который мы собираемся использовать, работает следующим образом:

Repeat until convergence {
  1. Calculate gradient average
  2. Multiply by learning rate
  3. Subtract from weights
}

Давайте сделаем это на Python:

Об этом until convergence part. Вы могли заметить, что мы пытаемся обойти это методом грубой силы. То есть мы будем запускать алгоритм для заданного количества итераций. Еще один интересный момент - инициализация наших весов W - изначально установленных на ноль.

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

Теперь для нашего простого теста:

Обратите внимание, что мы используем reshape, чтобы добавить фиктивное измерение к X. Далее, после нашего вызова predict, мы округляем результаты. Напомним, что сигмовидная функция выплевывает (как у дракона с расстройством желудка) числа в [0; 1] диапазон. Мы просто округлим результат, чтобы получить ответы 0 или 1 (да или нет).

run_tests()

Вот результат выполнения нашего тестового примера:

F

Что ж, это нехорошо, после всей этой суеты мы еще далеки от достижения нашей цели - нахождения хороших параметров для нашей модели. Но что пошло не так?

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

run_tests()

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

loss: 0.6931471805599453 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056
loss: 0.41899283818630056
F........

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

Во-первых, меньшая скорость обучения a:

run_tests()

С a=0.001 мы получаем это:

loss: 0.42351356323845546 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056 	
loss: 0.41899283818630056
F.......

Не так уж и хорошо, правда? Как насчет добавления еще одного параметра для поиска / изучения нашей модели?

run_tests()

А по результатам:

........
---------------------------------------------------------
Ran 8 tests in 0.686s  
OK

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

Бонус - создание собственного LogisticRegressor

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

Но сначала давайте напишем несколько тестов:

run_tests()

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

Использование нашего Regressor, чтобы решить, кто должен получать коды скидок

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

Напомним наши исходные данные:

Теперь давайте опробуем нашу модель на данных, полученных от двух новых клиентов:

Customer 1 - $10
Customer 2 - $250
y_test

Напомним, что 1 означает отправку кода, а 0 означает не отправку:

array([1., 0.])

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

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



Заключение

Отличная работа! У вас есть полная (хотя и простая) реализация LogisticRegressor, с которой можно поиграться. Давай, повеселись!

Далее вы реализуете модель линейной регрессии с нуля :)

Серия "Машинное обучение с нуля":

  1. Умные скидки с логистической регрессией
  2. Прогнозирование цен на жилье с помощью линейной регрессии
  3. Построение дерева решений с нуля в Python
  4. Извлечение цветовой палитры с кластеризацией K-средних
  5. Анализ настроений в обзоре фильма с помощью Наивного Байеса
  6. Система рекомендаций музыкальных исполнителей с использованием стохастического градиентного спуска
  7. Классификация имиджа модного товара с помощью нейронных сетей
  8. Создайте агента по вождению такси в постапокалиптическом мире с помощью обучения с подкреплением

Нравится то, что вы читаете? Хотите узнать еще больше о машинном обучении?



Практическое машинное обучение с нуля
« То, что я не могу создать, я не понимаю
- Ричард Фейнман. Эта книга проведет вас на пути к более глубокому… Leanpub.com »