バスケット分析

準備

普通に読み込むと1行目の購買数に影響を受けてしまう

library(readr)
groceries <- read_csv("groceries.csv", col_names = F)
## 
## ─ Column specification ────────────────────────────
## cols(
##   X1 = col_character(),
##   X2 = col_character(),
##   X3 = col_character(),
##   X4 = col_character()
## )
## Warning: 8830 parsing failures.
## row col  expected    actual            file
##   2  -- 4 columns 3 columns 'groceries.csv'
##   3  -- 4 columns 1 columns 'groceries.csv'
##   6  -- 4 columns 5 columns 'groceries.csv'
##   7  -- 4 columns 1 columns 'groceries.csv'
##   8  -- 4 columns 5 columns 'groceries.csv'
## ... ... ......... ......... ...............
## See problems(...) for more details.
head(groceries)
## # A tibble: 6 x 4
##   X1               X2                  X3             X4                      
##   <chr>            <chr>               <chr>          <chr>                   
## 1 citrus fruit     semi-finished bread margarine      ready soups             
## 2 tropical fruit   yogurt              coffee         <NA>                    
## 3 whole milk       <NA>                <NA>           <NA>                    
## 4 pip fruit        yogurt              cream cheese   meat spreads            
## 5 other vegetables whole milk          condensed milk long life bakery product
## 6 whole milk       butter              yogurt         rice

スパースデータとして読み込む

# データの前処理
library(arules)
## Loading required package: Matrix
## 
## Attaching package: 'arules'
## The following objects are masked from 'package:base':
## 
##     abbreviate, write
## アイテムの区切りを指定する
groceries <- arules::read.transactions("groceries.csv", sep = ",")
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 
##             2513             1903             1809             1715 
##           yogurt          (Other) 
##             1372            34055 
## 
## element (itemset/transaction) length distribution:
## sizes
##    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
## 2159 1643 1299 1005  855  645  545  438  350  246  182  117   78   77   55   46 
##   17   18   19   20   21   22   23   24   26   27   28   29   32 
##   29   14   14    9   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
## 1 abrasive cleaner
## 2 artif. sweetener
## 3   baby cosmetics
  • 169個の商品について買ったかどうか(0, 1), 9835件の購買データが入っている
  • densityは密度であり, 約2.7%のセルにデータが入っている(\(169*9835*0.02609416=43367\))
  • whole milkが一番買われている
  • 1回あたり平均4.4商品買われている
## スパース行列の内容を確認する
arules::inspect(groceries[1:5])
##     items                     
## [1] {citrus fruit,            
##      margarine,               
##      ready soups,             
##      semi-finished bread}     
## [2] {coffee,                  
##      tropical fruit,          
##      yogurt}                  
## [3] {whole milk}              
## [4] {cream cheese,            
##      meat spreads,            
##      pip fruit,               
##      yogurt}                  
## [5] {condensed milk,          
##      long life bakery product,
##      other vegetables,        
##      whole milk}

トランザクションデータのアイテムはアルファベット順に並んでおり, それぞれが含まれている割合(指示度)は,

itemFrequency(groceries[,1:10])
## abrasive cleaner artif. sweetener   baby cosmetics        baby food 
##     0.0035587189     0.0032536858     0.0006100661     0.0001016777 
##             bags    baking powder bathroom cleaner             beef 
##     0.0004067107     0.0176919166     0.0027452974     0.0524656838 
##          berries        beverages 
##     0.0332486019     0.0260294865

可視化してみる

## 10%以上含まれているもの
itemFrequencyPlot(groceries, support = 0.1)

## 上位20品目
itemFrequencyPlot(groceries, topN = 20)

スパース行列をプロットしてみる

## 10行169列
arules::image(groceries[1:10])

ランダムサンプリングして可視化してみる

arules::image(sample(groceries, 100))

分析

# モデルを訓練する
apriori(groceries)
## Apriori
## 
## Parameter specification:
##  confidence minval smax arem  aval originalSupport maxtime support minlen
##         0.8    0.1    1 none FALSE            TRUE       5     0.1      1
##  maxlen target  ext
##      10  rules TRUE
## 
## Algorithmic control:
##  filter tree heap memopt load sort verbose
##     0.1 TRUE TRUE  FALSE TRUE    2    TRUE
## 
## Absolute minimum support count: 983 
## 
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[169 item(s), 9835 transaction(s)] done [0.00s].
## sorting and recoding items ... [8 item(s)] done [0.00s].
## creating transaction tree ... done [0.00s].
## checking subsets of size 1 2 done [0.00s].
## writing ... [0 rule(s)] done [0.00s].
## creating S4 object  ... done [0.00s].
## set of 0 rules

しかしデフォルトのsupport=0.1とconfidence=0.8では何もルールは見つからない

  • 支持度を設定する. support = 0.006にすることで9835*0.006=約60件トランザクションに出現していると重要であるとみなす
  • 確信度の最小値(閾値)を設定する. confidence = 0.25とすることで25%以の割合で正しくないといけない. (トランザクション中にアイテム X が含まれるとき、アイテム Y も同時に含まれる比率。確信度が高いルールでは、アイテム X を含むトランザクションにはアイテム Y も含まれやすい)
  • 商品を1つしか含んでいないルールを除外するためにminlen = 2とする
groceryrules <- apriori(groceries, parameter = list(
  support = 0.006, confidence = 0.25, minlen = 2)
  )
## Apriori
## 
## Parameter specification:
##  confidence minval smax arem  aval originalSupport maxtime support minlen
##        0.25    0.1    1 none FALSE            TRUE       5   0.006      2
##  maxlen target  ext
##      10  rules TRUE
## 
## Algorithmic control:
##  filter tree heap memopt load sort verbose
##     0.1 TRUE TRUE  FALSE TRUE    2    TRUE
## 
## Absolute minimum support count: 59 
## 
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[169 item(s), 9835 transaction(s)] done [0.01s].
## sorting and recoding items ... [109 item(s)] done [0.00s].
## creating transaction tree ... done [0.00s].
## checking subsets of size 1 2 3 4 done [0.00s].
## writing ... [463 rule(s)] done [0.00s].
## creating S4 object  ... done [0.00s].
groceryrules
## set of 463 rules

アイテムの数が2, 3, 4個のルールが何個あったか確認する

# モデルの性能を評価する
summary(groceryrules)
## set of 463 rules
## 
## rule length distribution (lhs + rhs):sizes
##   2   3   4 
## 150 297  16 
## 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   2.000   2.000   3.000   2.711   3.000   4.000 
## 
## summary of quality measures:
##     support           confidence        coverage             lift       
##  Min.   :0.006101   Min.   :0.2500   Min.   :0.009964   Min.   :0.9932  
##  1st Qu.:0.007117   1st Qu.:0.2971   1st Qu.:0.018709   1st Qu.:1.6229  
##  Median :0.008744   Median :0.3554   Median :0.024809   Median :1.9332  
##  Mean   :0.011539   Mean   :0.3786   Mean   :0.032608   Mean   :2.0351  
##  3rd Qu.:0.012303   3rd Qu.:0.4495   3rd Qu.:0.035892   3rd Qu.:2.3565  
##  Max.   :0.074835   Max.   :0.6600   Max.   :0.255516   Max.   :3.9565  
##      count      
##  Min.   : 60.0  
##  1st Qu.: 70.0  
##  Median : 86.0  
##  Mean   :113.5  
##  3rd Qu.:121.0  
##  Max.   :736.0  
## 
## mining info:
##       data ntransactions support confidence
##  groceries          9835   0.006       0.25
  • ルールのほとんどがsupportとconfidenceの最小値付近の場合はハードルを高く設定しすぎの可能性がある
  • リフトは、確信度をsupp(Y)で割った値で定義されている. 全100件中Yが50件なら0.5でその50件のうちX→Yが40件なら0.8になるから0.8/0.5で1.6となる.基本的には1をこえるとよい
## 最初の10件のルール
inspect(groceryrules[1:10])
##      lhs                      rhs                support     confidence
## [1]  {potted plants}       => {whole milk}       0.006914082 0.4000000 
## [2]  {pasta}               => {whole milk}       0.006100661 0.4054054 
## [3]  {herbs}               => {root vegetables}  0.007015760 0.4312500 
## [4]  {herbs}               => {other vegetables} 0.007727504 0.4750000 
## [5]  {herbs}               => {whole milk}       0.007727504 0.4750000 
## [6]  {processed cheese}    => {whole milk}       0.007015760 0.4233129 
## [7]  {semi-finished bread} => {whole milk}       0.007117438 0.4022989 
## [8]  {beverages}           => {whole milk}       0.006812405 0.2617188 
## [9]  {detergent}           => {other vegetables} 0.006405694 0.3333333 
## [10] {detergent}           => {whole milk}       0.008947636 0.4656085 
##      coverage   lift     count
## [1]  0.01728521 1.565460 68   
## [2]  0.01504830 1.586614 60   
## [3]  0.01626843 3.956477 69   
## [4]  0.01626843 2.454874 76   
## [5]  0.01626843 1.858983 76   
## [6]  0.01657346 1.656698 69   
## [7]  0.01769192 1.574457 70   
## [8]  0.02602949 1.024275 67   
## [9]  0.01921708 1.722719 63   
## [10] 0.01921708 1.822228 88

1つめはpotted plansを購入した人はwhole milkも購入する. このルールはトランザクションの0.7%をカバーしており, 確信度40%よりpotted plansを購入したときの4割にあたる. 全体の25.6%がwhole milkを購入しているのでリフト値は0.4/0.256=1.56となる

ただし, 鉢植えを買った人がミルクを買う論理的な理由を見出せるだろうか

  • Actionable : 明確かつ有益なルール

  • Trivial : 自明なルール(紙おむつと粉ミルク)

  • Inexplicable : アイテム間の結びつきが明白ではなく, どう利用したらいいかわからない

## 可視化してみる
library(arulesViz)
plot(groceryrules)
## To reduce overplotting, jitter is added! Use jitter = 0 to prevent jitter.

## バブルチャート
plot(groceryrules,method="grouped",control=list(k=10))

## アソシエーションルール
lifts <- head(sort(groceryrules, by="lift"), 10)
plot(lifts, method="graph",
     layoutParams = list(type="items"), engine = "igraph")

# モデルの性能を向上させる
## データの並べ替え(lift順)
inspect(sort(groceryrules, by = "lift")[1:5])
##     lhs                   rhs                      support confidence   coverage     lift count
## [1] {herbs}            => {root vegetables}    0.007015760  0.4312500 0.01626843 3.956477    69
## [2] {berries}          => {whipped/sour cream} 0.009049314  0.2721713 0.03324860 3.796886    89
## [3] {other vegetables,                                                                         
##      tropical fruit,                                                                           
##      whole milk}       => {root vegetables}    0.007015760  0.4107143 0.01708185 3.768074    69
## [4] {beef,                                                                                     
##      other vegetables} => {root vegetables}    0.007930859  0.4020619 0.01972547 3.688692    78
## [5] {other vegetables,                                                                         
##      tropical fruit}   => {pip fruit}          0.009456024  0.2634561 0.03589222 3.482649    93

相関ルールのサブセットを取得する

berryrules <- subset(groceryrules, items %in% "berries")
inspect(berryrules)
##     lhs          rhs                  support     confidence coverage  lift    
## [1] {berries} => {whipped/sour cream} 0.009049314 0.2721713  0.0332486 3.796886
## [2] {berries} => {yogurt}             0.010574479 0.3180428  0.0332486 2.279848
## [3] {berries} => {other vegetables}   0.010269446 0.3088685  0.0332486 1.596280
## [4] {berries} => {whole milk}         0.011794611 0.3547401  0.0332486 1.388328
##     count
## [1]  89  
## [2] 104  
## [3] 101  
## [4] 116

アウトプット

## csvファイル
write(groceryrules, file = "groceryrules.csv", sep = ",", 
      quote = TRUE, row.names = FALSE)

## データフレーム
groceryrules_df <- as(groceryrules, "data.frame")