В нашем распоряжении есть информация о 9’835 покупках 169 продуктов в виде csv файла:

head -n5 groceries.csv
## citrus fruit,semi-finished bread,margarine,ready soups
## tropical fruit,yogurt,coffee
## whole milk
## pip fruit,yogurt,cream cheese ,meat spreads
## other vegetables,whole milk,condensed milk,long life bakery product

где строки представляют список покупок одним потребителем.

Загрузим данные из пакета arules, где они находятся в специальном формате transactions и вкратце проанализируем их:

library(arules)
## Loading required package: Matrix
## 
## Attaching package: 'arules'
## The following objects are masked from 'package:base':
## 
##     abbreviate, write
data(Groceries)
dim(Groceries)
## [1] 9835  169

Для доступа к транзакциям в пакете arules существует функция inspect:

inspect(Groceries[1:5])
##   items                     
## 1 {citrus fruit,            
##    semi-finished bread,     
##    margarine,               
##    ready soups}             
## 2 {tropical fruit,          
##    yogurt,                  
##    coffee}                  
## 3 {whole milk}              
## 4 {pip fruit,               
##    yogurt,                  
##    cream cheese ,           
##    meat spreads}            
## 5 {other vegetables,        
##    whole milk,              
##    condensed milk,          
##    long life bakery product}

Краткое резюме всех транзакций

summary(Groceries)
## transactions as itemMatrix in sparse format with
##  9835 rows (elements/itemsets/transactions) and
##  169 columns (items) and a density of 0.02609146 
## 
## most frequent items:
##       whole milk other vegetables       rolls/buns             soda           yogurt 
##             2513             1903             1809             1715             1372 
##          (Other) 
##            34055 
## 
## element (itemset/transaction) length distribution:
## sizes
##    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19   20 
## 2159 1643 1299 1005  855  645  545  438  350  246  182  117   78   77   55   46   29   14   14    9 
##   21   22   23   24   26   27   28   29   32 
##   11    4    6    1    1    1    1    3    1 
## 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.000   2.000   3.000   4.409   6.000  32.000 
## 
## includes extended item information - examples:
##        labels  level2           level1
## 1 frankfurter sausage meat and sausage
## 2     sausage sausage meat and sausage
## 3  liver loaf sausage meat and sausage
  1. Наиболее часто покупаемые продукты – молоко (2513) и овощи (1903).
  2. Единичных покупок – 2159, покупок из 2ух продуктов – 1643, макимальное количество продуктов в корзине – 32, средняя корзина состоит из 4.409 покупок.

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

library(ggplot2)
lst <- LIST(Groceries)
num <- sapply(lst, 'length')
ggplot(data=NULL, aes(x=num)) +
    geom_histogram(binwidth=.5, fill='grey60', color='white') +
    scale_x_continuous(breaks = 0:20, limits=c(-1,20))
## Warning: Removed 29 rows containing non-finite values (stat_bin).

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

x <- sort(table(do.call('c',lst[num==1])),decreasing = T)[1:10]

ggplot(data=NULL) +
    geom_bar(aes(x=reorder(names(x),-x), y=x),stat='identity', fill='grey50',width=.4) +
    theme(axis.text.x=element_text(angle=90))+
    coord_flip()+
    xlab('')

Или наиболее часто покупаемые пары продуктов:

x <- sort(table(unlist(lapply(lst[num==2],function(x) (paste0(x,collapse = ','))))),decreasing=T)[1:10]

ggplot(data=NULL) +
    geom_bar(aes(x=reorder(names(x),-x), y=x),stat='identity', fill='grey50',width=.4) +
    theme(axis.text.x=element_text(angle=90))+
    coord_flip() +
    xlab('')

Или наиболее часто покупаемые продукты вообще:

x <- sort(table(do.call('c',lst)),decreasing = T)[1:10]
ggplot(data=NULL) +
    geom_bar(aes(x=reorder(names(x),-x), y=x),stat='identity',fill='grey50', width=.4) +
    theme(axis.text.x=element_text(angle=90))+
    xlab('')+
    coord_flip()

Анализ потребительской корзины позволяет ответить на вопросы:

Анализ потребительской корзины происходит при помощи алгоритма apriori, предложенного Rakesh Agrawal и Ramakrishnan Srikant в 1994. Данный алгоритм реализован в пакете R под названием arules (“association rules”). Логика действия алгоритма такова:

1.алгоритм “отсекает” редкие комбинации покупок, которые “априори” не могут сформировать повторяемый паттерн покупок “IF” –> “THEN” (если бы этого не было, общее количество различных комбинаций покупок из 100 продуктов было бы \(2^{100}\))

  1. для комбинаций, прошедших фильтр, вычисляется “support”, или частота покупки такой комбинации

  2. сеты покупок разбиваются на 2 части:
    • lhs – “левая часть корзины” (“IF”, если мы купили “ЭТО”)
    • rhs – “правая часть корзины” (“THEN”, то мы купим “ТО”)
  3. Для rhs вычисляются:
    • confidence - условная вероятность P(rhs|lhs)
    • lift - увеличение вероятности покупки rhs (при условии покупки lhs) по сравнению с отсутствием корреляции между двумя покупками (lift=1 говорит об отсутствии корреляции между rhs и lhs).

Если мы считаем, что любые транзакции с частотой менее 3 покупок в день – это шум, то мы можем составить правила покупок таким образом:

rules <- apriori(Groceries,
                 parameter=list(support=0.01,
                                confidence=.1,
                                minlen=2))
## Apriori
## 
## Parameter specification:
##  confidence minval smax arem  aval originalSupport support minlen maxlen target   ext
##         0.1    0.1    1 none FALSE            TRUE    0.01      2     10  rules FALSE
## 
## Algorithmic control:
##  filter tree heap memopt load sort verbose
##     0.1 TRUE TRUE  FALSE TRUE    2    TRUE
## 
## Absolute minimum support count: 98 
## 
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[169 item(s), 9835 transaction(s)] done [0.01s].
## sorting and recoding items ... [88 item(s)] done [0.00s].
## creating transaction tree ... done [0.01s].
## checking subsets of size 1 2 3 4 done [0.01s].
## writing ... [427 rule(s)] done [0.00s].
## creating S4 object  ... done [0.00s].
inspect(sort(rules, by='confidence')[1:10])
##     lhs                                 rhs                support    confidence lift    
## 362 {citrus fruit,root vegetables}   => {other vegetables} 0.01037112 0.5862069  3.029608
## 377 {tropical fruit,root vegetables} => {other vegetables} 0.01230300 0.5845411  3.020999
## 332 {curd,yogurt}                    => {whole milk}       0.01006609 0.5823529  2.279125
## 338 {other vegetables,butter}        => {whole milk}       0.01148958 0.5736041  2.244885
## 380 {tropical fruit,root vegetables} => {whole milk}       0.01199797 0.5700483  2.230969
## 398 {root vegetables,yogurt}         => {whole milk}       0.01453991 0.5629921  2.203354
## 341 {other vegetables,domestic eggs} => {whole milk}       0.01230300 0.5525114  2.162336
## 350 {yogurt,whipped/sour cream}      => {whole milk}       0.01087951 0.5245098  2.052747
## 404 {root vegetables,rolls/buns}     => {whole milk}       0.01270971 0.5230126  2.046888
## 356 {pip fruit,other vegetables}     => {whole milk}       0.01352313 0.5175097  2.025351

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

  1. {citrus fruit,root vegetables,other vegetables} встречаются в различных комбинациях в корзинах покупок (возможно и с другими продуктами), 102 раза (“0.01037112*9835“)
  2. как только потребитель приобрел {citrus fruit,root vegetables}, [условная] вероятность, или confidence, приобретения {other vegetables} составляет 0.59
  3. lift, или увеличение вероятности покупки по сравнению со случайной корзиной, составляет 3.02

Пакет arules позволяет фильтровать как по rhs (т.е. найдет триггеры, которые приведут к покупке пива):

beer_rhs <- subset(rules, rhs %pin% 'beer')
inspect(beer_rhs)
##    lhs                rhs            support    confidence lift    
## 26 {shopping bags} => {canned beer}  0.01138790 0.1155831  1.487905
## 91 {bottled water} => {bottled beer} 0.01576004 0.1425943  1.770726

так и по lhs (т.е. определить, к чему приведет покупка пива)

beer_lhs <- subset(rules, lhs %pin% 'beer')
inspect(sort(beer_lhs, by="lift"))
##    lhs               rhs                support    confidence lift     
## 90 {bottled beer} => {bottled water}    0.01576004 0.1957071  1.7707259
## 25 {canned beer}  => {shopping bags}    0.01138790 0.1465969  1.4879052
## 92 {bottled beer} => {soda}             0.01698017 0.2108586  1.2092094
## 94 {bottled beer} => {other vegetables} 0.01616675 0.2007576  1.0375464
## 27 {canned beer}  => {soda}             0.01382816 0.1780105  1.0208356
## 95 {bottled beer} => {whole milk}       0.02043721 0.2537879  0.9932367
## 93 {bottled beer} => {rolls/buns}       0.01362481 0.1691919  0.9198466
## 28 {canned beer}  => {rolls/buns}       0.01128622 0.1452880  0.7898878

Резюме:

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