Использование кластеризации K-средних для понимания реакции маркетинга

Обзор

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

В этом мини-проекте я использую популярный алгоритм Кластеризация K-средних для сегментации клиентов на основе их реакции на серию маркетинговых кампаний. Этот метод относительно легко реализовать, и тем не менее он позволил мне собрать тонны информации из моих данных и выявить интересные модели поведения в моей клиентской базе.

Что такое сегментация рынка?

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

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

Что такое кластеризация K-средних?

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

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

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

K-Means могут сгруппировать их вокруг середины или centre каждого кластера, представленного здесь «X», таким образом, чтобы минимизировать расстояние между каждым элементом до это centre

Итак, как это поможет вам лучше понять своих клиентов? Что ж, в этом случае вы можете использовать их поведение (в частности, какое предложение они сделали или не использовали) как способ сгруппировать их с единомышленниками. Теперь вы можете изучить каждую из этих групп, чтобы выявить тенденции и закономерности и использовать их для формирования будущих предложений.

В более техническом отношении, важно отметить, что существует множество доступных алгоритмов K-средних (Хартиган-Вонг, Ллойд, MacQueen, и это лишь некоторые из них), но все они разделяют одну и ту же базовую концепцию: каждый элемент назначается кластеру, так что он сводит к минимуму сумму евклидова расстояния в квадратах до centre - a процесс также называется минимизацией общей суммы квадратов внутри кластера (tot.withinss).

Загрузка пакетов

library(tidyverse)
library(lubridate)
library(knitr)
library(readxl)
library(broom)
library(umap)
library(ggrepel)

Данные

Набор данных взят из книги Джона Формана Data Smart. Он содержит данные рекламных акций для вымышленного розничного продавца вин и включает подробную информацию о 32 рекламных акциях (включая ассортимент вин, минимальное количество покупок, процентную скидку и страна происхождения), а также список из 100 клиентов и рекламных акций, на которые они откликнулись.

offers_tbl <- read_excel('../00_data/WineKMC.xlsx', 
                           sheet = 'OfferInformation')
offers_tbl <- offers_tbl %>% 
                 set_names(c('offer', 'campaign', 
                             'varietal', 'min_qty_kg',
                             'disc_pct','origin','past_peak')
                             )
head(offers_tbl)
## # A tibble: 6 x 7
##  offer campaign varietal min_qty_kg disc_pct origin  past_peak
##  <dbl> <chr>    <chr>       <dbl>   <dbl>    <chr>     <chr>    
## 1 1 January     Malbec        72     56      France     FALSE    
## 2 2 January     Pinot Noir    72     17      France     FALSE    
## 3 3 February    Espumante    144     32      Oregon     TRUE     
## 4 4 February    Champagne     72     48      France     TRUE     
## 5 5 February    Cabernet~    144     44      New Zeala~ TRUE     
## 6 6 March       Prosecco     144     86      Chile      FALSE
transac_tbl <- read_excel('../00_data/WineKMC.xlsx', 
                            sheet = 'Transactions')
transac_tbl <- transac_tbl %>% 
                   set_names(c('customer', 'offer')
                               )
head(transac_tbl)
## # A tibble: 6 x 2
##   customer offer
##   <chr>    <dbl>
## 1 Smith        2
## 2 Smith       24
## 3 Johnson     17
## 4 Johnson     24
## 5 Johnson     26
## 6 Williams    18

Данные необходимо преобразовать в User-Item format (также известную как матрица "клиент-продукт"), в которой клиенты вверху, а предложения внизу. Ячейки заполнены значениями 0 и 1, где 1 указывает, ответил ли клиент на конкретное предложение.

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

wine_tbl <- transac_tbl %>% 
    left_join(offers_tbl) %>% 
    mutate(value = 1) %>%
    spread(customer,value, fill = 0) 
head(wine_tbl)
## # A tibble: 6 x 107
##  offer campaign varietal min_qty_kg disc_pct origin past_peak 
##  <dbl>  <chr>   <chr>      <dbl>      <dbl>    <chr>  <chr>     
## 1 1    January  Malbec       72       56      France   FALSE         
## 2 2    January  Pinot Noir   72       17      France   FALSE         
## 3 3    February Espumante   144       32      Oregon   TRUE          
## 4 4    February Champagne    72       48      France   TRUE          
## 5 5    February Cabernern~  144       44      New Zea~ TRUE          
## 6 6    March    Prosecco    144       86      Chile    FALSE         
## # ... with 100 more variables: Adams <dbl>, Allen <dbl>, Anderson <dbl>, Bailey <dbl>, Baker <dbl>, Barnes <dbl>, ...

Кластеризация клиентов

Алгоритм K-средних поставляется с пакетом stats, одной из основных системных библиотек в R, и довольно прост в использовании. Мне просто нужно передать несколько параметров функции kmeans ().

user_item_tbl <- wine_tbl[,8:107]
set.seed(196) 
            
kmeans_obj <- user_item_tbl %>%  
    kmeans(centers = 5,     # number of clusters 
           nstart = 100,    # number of random sets to be chosen
           iter.max = 50)   # max number of iterations allowed

Я могу быстро проверить модель с помощьюglance() из broomпакета, который предоставляет сводную статистику на уровне модели.

glance(kmeans_obj) %>% glimpse()
## Observations: 1
## Variables: 4
## $ totss        <dbl> 283.1875
## $ tot.withinss <dbl> 189.7255
## $ betweenss    <dbl> 93.46201
## $ iter         <int> 3

Единственная метрика, за которой действительно следует следить, - это общая сумма квадратов внутри кластера (или tot.withinss), поскольку оптимальное количество кластеров - это то, которое минимизирует tot.withinss.

Итак, я хочу подогнать модель k-средних для разного количества кластеров и посмотреть, где tot.withinss достигает своего минимума.

Сначала я создаю функцию для заданного числа centers (в данном случае 4) и проверяю, что она работает на glance().

kmeans_map <- function(centers = 4) {
    user_item_tbl %>%  
        kmeans(centers = centers, 
        nstart = 100, 
        iter.max = 50)
}
4 %>% kmeans_map() %>%  glance()
## # A tibble: 1 x 4
##   totss tot.withinss betweenss  iter
##   <dbl>        <dbl>     <dbl> <int>
## 1  283.         203.      80.0     2

Затем я создаю вложенный тиббл, который представляет собой способ «вложения» столбцов во фрейм данных.

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

kmeans_map_tbl <- tibble(centers = 1:15) %>%  
                         # create column with centres 
          mutate(k_means = centers %>% 
                  map(kmeans_map)) %>%   
                         # iterate `kmeans_map` row-wise to 
                         # gather kmeans models for each centre
          mutate(glance = k_means %>%  
                  map(glance))            
                         # apply `glance()` row-wise to gather 
                         # each model’s summary metrics

kmeans_map_tbl %>% glimpse()
## Observations: 15
## Variables: 3
## $ centers <int>  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, ...
## $ k_means <list> [<1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
## $ glance  <list> [<tbl_df[1 x 4]>, <tbl_df[1 x 4]>, ...

Наконец, я могу построить scree plot и искать «изгиб» на графике, точку, где количество дополнительных кластеров, кажется, выравнивается. В этом случае 5 представляется оптимальным числом, так как падение tot.withinss для 6 не так ярко выражено, как предыдущее.

kmeans_map_tbl %>% 
    unnest(glance) %>%           # unnest the glance column
    select(centers, 
             tot.withinss) %>%   # select centers and tot.withinss
    
    ggplot(aes(x = centers, y = tot.withinss)) + 
    geom_line(colour = 'grey30', size = .8) +
    geom_point(colour = 'green4', size = 3) +
    geom_label_repel(aes(label = centers), 
                     colour = 'grey30') +
    theme_light() +
    labs(title = 'Scree Plot')

Визуализация сегментов

Теперь, когда я определил оптимальное количество кластеров, я хочу их визуализировать. Для этого я использую UMAP (Uniform Manifold Approximation and Projection), метод уменьшения размерности, который можно использовать для визуализации кластеров аналогично Анализ главных компонентов и t-SNE .

Сначала я создаю объект umap и извлекаю аргумент layout (содержащий координаты, которые можно использовать для визуализации набора данных), меняю его формат на тиббл и присоединяю столбец offer из wine_tbl.

umap_obj <- user_item_tbl %>%  umap() 

umap_tbl <- umap_obj$layout %>% 
    as_tibble() %>%                       # change to a tibble
    set_names(c('x', 'y')) %>%            # remane columns
    bind_cols(wine_tbl %>% select(offer)) # attach offer reference

Затем я pluck 5-ю модель kmeans из вложенного тибла, присоединяю аргумент cluster из функции kmeans к выходным данным и присоединяю предложение и кластер к umap_tbl.

umap_kmeans_5_tbl <- kmeans_map_tbl %>% 
    pull(k_means) %>%
    pluck(5) %>%                   # pluck element 5 
    broom::augment(wine_tbl) %>%   # attach .cluster to the tibble 
    select(offer, .cluster) %>% 
    left_join(umap_tbl, 
                 by = 'offer')     # join umap_tbl by offer

Наконец-то я могу визуализировать проекции кластеров по UMAP. plotly добавляет приятную интерактивность, которая оживляет график!

umap_kmeans_5_tbl %>% 
    mutate(label_text = str_glue('Offer: {offer}
                                  Cluster: {.cluster}')) %>%
    ggplot(aes(x,y, colour = .cluster)) +
    geom_point() +
    geom_label_repel(aes(label = label_text), size = 3) +
    theme_light() +
    labs(title    = 'UMAP 2D Projections of K-Means Clusters',
         caption  = "") +
    theme(legend.position = 'none')

Оценка кластеров

Теперь мы можем, наконец, более внимательно посмотреть на отдельные кластеры, чтобы увидеть, что идентифицировал K-Means.

Но давайте сначала соберем всю информацию в одном фрейме данных.

cluster_trends_tbl <- wine_tbl %>%
    left_join(umap_kmeans_5_tbl) %>%
    arrange(.cluster) %>%
    select(.cluster, offer:past_peak)

Кластер 1 и 2

Клиенты в кластере 1 покупают большие объемы игристых вин (шампанское и просекко), тогда как клиенты из второго сегмента предпочитают небольшие объемы закупок разных сортов.

cluster_trends_tbl %>% 
    filter(.cluster ==1 | .cluster ==2) %>% 
    count(.cluster, varietal, origin, min_qty_kg, disc_pct) %>%
    select(-n)
## # A tibble: 9 x 5
##   .cluster varietal     origin       min_qty_kg disc_pct
##   <fct>    <chr>        <chr>             <dbl>    <dbl>
## 1 1        Champagne    France               72       48
## 2 1        Champagne    New Zealand          72       88
## 3 1        Prosecco     Chile               144       86
## 4 2        Espumante    Oregon                6       50
## 5 2        Espumante    South Africa          6       45
## 6 2        Malbec       France                6       54
## 7 2        Merlot       Chile                 6       43
## 8 2        Pinot Grigio France                6       87
## 9 2        Prosecco     Australia             6       40

Кластер 3 и 4

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

cluster_trends_tbl %>% 
    filter(.cluster ==3 | .cluster ==4 ) %>% 
    group_by() %>%
    count(.cluster, varietal, origin, min_qty_kg, disc_pct) %>%
    select(-n)
## # A tibble: 6 x 5
##   .cluster varietal   origin    min_qty_kg disc_pct
##   <fct>    <chr>      <chr>          <dbl>    <dbl>
## 1 3        Pinot Noir Australia        144       83
## 2 3        Pinot Noir France            72       17
## 3 3        Pinot Noir Germany           12       47
## 4 3        Pinot Noir Italy              6       34
## 5 4        Champagne  France            72       63
## 6 4        Champagne  France            72       89

Кластер 5

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

cluster_trends_tbl %>% 
    filter(.cluster ==5 ) %>% 
    count(.cluster, varietal, origin, min_qty_kg, disc_pct) %>%
    select(-n)
## # A tibble: 17 x 5
##    .cluster varietal           origin       min_qty_kg disc_pct
##    <fct>    <chr>              <chr>             <dbl>    <dbl>
##  1 5        Cabernet Sauvignon France               12       56
##  2 5        Cabernet Sauvignon Germany              72       45
##  3 5        Cabernet Sauvignon Italy                72       82
##  4 5        Cabernet Sauvignon Italy               144       19
##  5 5        Cabernet Sauvignon New Zealand         144       44
##  6 5        Cabernet Sauvignon Oregon               72       59
##  7 5        Champagne          California           12       50
##  8 5        Champagne          France               72       85
##  9 5        Champagne          Germany              12       66
## 10 5        Chardonnay         Chile               144       57
## 11 5        Chardonnay         South Africa        144       39
## 12 5        Espumante          Oregon              144       32
## 13 5        Malbec             France               72       56
## 14 5        Merlot             California           72       88
## 15 5        Merlot             Chile                72       64
## 16 5        Prosecco           Australia            72       83
## 17 5        Prosecco           California           72       52

Последние мысли

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

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

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

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

Репозиторий кода

Полный код R можно найти в моем профиле GitHub

использованная литература

Первоначально опубликовано на https://diegousai.io 25 мая 2019 г.