Example: Identifying Frequently-Purchased Groceries —-

Step 1: Collecting Data

Our market basket analysis will utilize the purchase data collected from one month of operation at a real-world grocery store. The data contains 9,835 transactions or about 327 transactions per day (roughly 30 transactions per hour in a 12-hour business day), suggesting that the retailer is not particularly large, nor is it particularly small. The dataset used here was adapted from the Groceries dataset in the arules R package.

Step 2: Exploring and preparing the data

load the grocery data into a sparse matrix

library(arules)
Loading required package: Matrix

Attaching package: ‘arules’

The following object is masked from ‘package:car’:

    recode

The following objects are masked from ‘package:base’:

    abbreviate, write
groceries <- read.transactions("http://www.sci.csueastbay.edu/~esuess/classes/Statistics_6620/Presentations/ml13/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           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 
2159 1643 1299 1005  855  645  545  438  350  246  182  117   78   77   55   46   29   14 
  19   20   21   22   23   24   26   27   28   29   32 
  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

look at the first five transactions

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}              

examine the frequency of items

itemFrequency(groceries[, 1:3])
abrasive cleaner artif. sweetener   baby cosmetics 
    0.0035587189     0.0032536858     0.0006100661 

plot the frequency of items

itemFrequencyPlot(groceries, support = 0.1)

itemFrequencyPlot(groceries, topN = 20)

a visualization of the sparse matrix for the first five transactions

image(groceries[1:5])

visualization of a random sample of 100 transactions

image(sample(groceries, 100))

Step 3: Training a model on the data

library(arules)

default settings result in zero rules learned

apriori(groceries)
Apriori

Parameter specification:
 confidence minval smax arem  aval originalSupport maxtime support minlen maxlen target
        0.8    0.1    1 none FALSE            TRUE       5     0.1      1     10  rules
   ext
 FALSE

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.01s].
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 

set better support and confidence levels to learn more rules

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 maxlen target
       0.25    0.1    1 none FALSE            TRUE       5   0.006      2     10  rules
   ext
 FALSE

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.01s].
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 

Step 4: Evaluating model performance

# summary of grocery association rules
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          lift       
 Min.   :0.006101   Min.   :0.2500   Min.   :0.9932  
 1st Qu.:0.007117   1st Qu.:0.2971   1st Qu.:1.6229  
 Median :0.008744   Median :0.3554   Median :1.9332  
 Mean   :0.011539   Mean   :0.3786   Mean   :2.0351  
 3rd Qu.:0.012303   3rd Qu.:0.4495   3rd Qu.:2.3565  
 Max.   :0.074835   Max.   :0.6600   Max.   :3.9565  

mining info:
      data ntransactions support confidence
 groceries          9835   0.006       0.25

In the final section of the summary() output, we receive mining information, telling us about how the rules were chosen. Here, we see that the groceries data, which contained 9,835 transactions, was used to construct rules with a minimum support of 0.0006 and minimum confidence of 0.25.

The first rule can be read in plain language as, “if a customer buys potted plants, they will also buy whole milk.” With support of 0.007 and confidence of 0.400, we can determine that this rule covers 0.7 percent of the transactions and is correct in 40 percent of purchases involving potted plants. The lift value tells us how much more likely a customer is to buy whole milk relative to the average customer, given that he or she bought a potted plant. Since we know that about 25.6 percent of the customers bought whole milk (support), while 40 percent of the customers buying a potted plant bought whole milk (confidence), we can compute the lift value as 0.40 / 0.256 = 1.56, which matches the value shown.

look at the first three rules

inspect(groceryrules[1:3])
    lhs                rhs               support     confidence lift    
[1] {potted plants} => {whole milk}      0.006914082 0.4000000  1.565460
[2] {pasta}         => {whole milk}      0.006100661 0.4054054  1.586614
[3] {herbs}         => {root vegetables} 0.007015760 0.4312500  3.956477

Step 5: Improving model performance

sorting grocery rules by lift

inspect(sort(groceryrules, by = "lift")[1:5])
    lhs                   rhs                      support confidence     lift
[1] {herbs}            => {root vegetables}    0.007015760  0.4312500 3.956477
[2] {berries}          => {whipped/sour cream} 0.009049314  0.2721713 3.796886
[3] {other vegetables,                                                        
     tropical fruit,                                                          
     whole milk}       => {root vegetables}    0.007015760  0.4107143 3.768074
[4] {beef,                                                                    
     other vegetables} => {root vegetables}    0.007930859  0.4020619 3.688692
[5] {other vegetables,                                                        
     tropical fruit}   => {pip fruit}          0.009456024  0.2634561 3.482649

These rules appear to be more interesting than the ones we looked at previously. The first rule, with a lift of about 3.96, implies that people who buy herbs are nearly four times more likely to buy root vegetables than the typical customer—perhaps for a stew of some sort? Rule two is also interesting. Whipped cream is over three times more likely to be found in a shopping cart with berries versus other carts, suggesting perhaps a dessert pairing?

finding subsets of rules containing any berry items

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

writing the rules to a CSV file

write(groceryrules, file = "groceryrules.csv",
      sep = ",", quote = TRUE, row.names = FALSE)

converting the rule set to a data frame

groceryrules_df <- as(groceryrules, "data.frame")
str(groceryrules_df)
'data.frame':   463 obs. of  4 variables:
 $ rules     : Factor w/ 463 levels "{baking powder} => {other vegetables}",..: 340 302 207 206 208 341 402 21 139 140 ...
 $ support   : num  0.00691 0.0061 0.00702 0.00773 0.00773 ...
 $ confidence: num  0.4 0.405 0.431 0.475 0.475 ...
 $ lift      : num  1.57 1.59 3.96 2.45 1.86 ...
LS0tCnRpdGxlOiAiQXNzb2NpYXRpb24gYW5hbHlzaXMgb24gdGhlIGdyb2NlcmllcyBkYXRhIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCgojIyBFeGFtcGxlOiBJZGVudGlmeWluZyBGcmVxdWVudGx5LVB1cmNoYXNlZCBHcm9jZXJpZXMgLS0tLQoKIyMgU3RlcCAxOiBDb2xsZWN0aW5nIERhdGEKT3VyIG1hcmtldCBiYXNrZXQgYW5hbHlzaXMgd2lsbCB1dGlsaXplIHRoZSBwdXJjaGFzZSBkYXRhIGNvbGxlY3RlZCBmcm9tIG9uZSBtb250aCBvZiBvcGVyYXRpb24gYXQgYSByZWFsLXdvcmxkIGdyb2Nlcnkgc3RvcmUuIFRoZSBkYXRhIGNvbnRhaW5zIDksODM1IHRyYW5zYWN0aW9ucyBvciBhYm91dCAzMjcgdHJhbnNhY3Rpb25zIHBlciBkYXkgKHJvdWdobHkgMzAgdHJhbnNhY3Rpb25zIHBlciBob3VyIGluIGEgMTItaG91ciBidXNpbmVzcyBkYXkpLCBzdWdnZXN0aW5nIHRoYXQgdGhlIHJldGFpbGVyIGlzIG5vdCBwYXJ0aWN1bGFybHkgbGFyZ2UsIG5vciBpcyBpdCBwYXJ0aWN1bGFybHkgc21hbGwuClRoZSBkYXRhc2V0IHVzZWQgaGVyZSB3YXMgYWRhcHRlZCBmcm9tIHRoZSBHcm9jZXJpZXMgZGF0YXNldCBpbiB0aGUgYXJ1bGVzIFIgcGFja2FnZS4KCiMjIFN0ZXAgMjogRXhwbG9yaW5nIGFuZCBwcmVwYXJpbmcgdGhlIGRhdGEgCiMgbG9hZCB0aGUgZ3JvY2VyeSBkYXRhIGludG8gYSBzcGFyc2UgbWF0cml4CmBgYHtyfQpsaWJyYXJ5KGFydWxlcykKZ3JvY2VyaWVzIDwtIHJlYWQudHJhbnNhY3Rpb25zKCJodHRwOi8vd3d3LnNjaS5jc3VlYXN0YmF5LmVkdS9+ZXN1ZXNzL2NsYXNzZXMvU3RhdGlzdGljc182NjIwL1ByZXNlbnRhdGlvbnMvbWwxMy9ncm9jZXJpZXMuY3N2Iiwgc2VwID0gIiwiKQpzdW1tYXJ5KGdyb2NlcmllcykKYGBgCgojIGxvb2sgYXQgdGhlIGZpcnN0IGZpdmUgdHJhbnNhY3Rpb25zCmBgYHtyfQppbnNwZWN0KGdyb2Nlcmllc1sxOjVdKQpgYGAKCiMgZXhhbWluZSB0aGUgZnJlcXVlbmN5IG9mIGl0ZW1zCmBgYHtyfQppdGVtRnJlcXVlbmN5KGdyb2Nlcmllc1ssIDE6M10pCmBgYAoKIyBwbG90IHRoZSBmcmVxdWVuY3kgb2YgaXRlbXMKYGBge3J9Cml0ZW1GcmVxdWVuY3lQbG90KGdyb2Nlcmllcywgc3VwcG9ydCA9IDAuMSkKaXRlbUZyZXF1ZW5jeVBsb3QoZ3JvY2VyaWVzLCB0b3BOID0gMjApCmBgYAoKIyBhIHZpc3VhbGl6YXRpb24gb2YgdGhlIHNwYXJzZSBtYXRyaXggZm9yIHRoZSBmaXJzdCBmaXZlIHRyYW5zYWN0aW9ucwpgYGB7cn0KaW1hZ2UoZ3JvY2VyaWVzWzE6NV0pCmBgYAoKIyB2aXN1YWxpemF0aW9uIG9mIGEgcmFuZG9tIHNhbXBsZSBvZiAxMDAgdHJhbnNhY3Rpb25zCmBgYHtyfQppbWFnZShzYW1wbGUoZ3JvY2VyaWVzLCAxMDApKQpgYGAKCiMjIFN0ZXAgMzogVHJhaW5pbmcgYSBtb2RlbCBvbiB0aGUgZGF0YQpgYGB7cn0KbGlicmFyeShhcnVsZXMpCmBgYAoKIyBkZWZhdWx0IHNldHRpbmdzIHJlc3VsdCBpbiB6ZXJvIHJ1bGVzIGxlYXJuZWQKYGBge3J9CmFwcmlvcmkoZ3JvY2VyaWVzKQpgYGAKCiMgc2V0IGJldHRlciBzdXBwb3J0IGFuZCBjb25maWRlbmNlIGxldmVscyB0byBsZWFybiBtb3JlIHJ1bGVzCmBgYHtyfQpncm9jZXJ5cnVsZXMgPC0gYXByaW9yaShncm9jZXJpZXMsIHBhcmFtZXRlciA9IGxpc3Qoc3VwcG9ydCA9CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAuMDA2LCBjb25maWRlbmNlID0gMC4yNSwgbWlubGVuID0gMikpCmdyb2NlcnlydWxlcwpgYGAKCiMjIFN0ZXAgNDogRXZhbHVhdGluZyBtb2RlbCBwZXJmb3JtYW5jZQpgYGB7cn0KIyBzdW1tYXJ5IG9mIGdyb2NlcnkgYXNzb2NpYXRpb24gcnVsZXMKc3VtbWFyeShncm9jZXJ5cnVsZXMpCgpgYGAKSW4gdGhlIGZpbmFsIHNlY3Rpb24gb2YgdGhlIHN1bW1hcnkoKSBvdXRwdXQsIHdlIHJlY2VpdmUgbWluaW5nIGluZm9ybWF0aW9uLCB0ZWxsaW5nIHVzIGFib3V0IGhvdyB0aGUgcnVsZXMgd2VyZSBjaG9zZW4uIEhlcmUsIHdlIHNlZSB0aGF0IHRoZSBncm9jZXJpZXMgZGF0YSwgd2hpY2ggY29udGFpbmVkIDksODM1IHRyYW5zYWN0aW9ucywgd2FzIHVzZWQgdG8gY29uc3RydWN0IHJ1bGVzIHdpdGggYSBtaW5pbXVtIHN1cHBvcnQgb2YgMC4wMDA2IGFuZCBtaW5pbXVtIGNvbmZpZGVuY2Ugb2YgMC4yNS4KClRoZSBmaXJzdCBydWxlIGNhbiBiZSByZWFkIGluIHBsYWluIGxhbmd1YWdlIGFzLCAiaWYgYSBjdXN0b21lciBidXlzIHBvdHRlZCBwbGFudHMsIHRoZXkgd2lsbCBhbHNvIGJ1eSB3aG9sZSBtaWxrLiIgV2l0aCBzdXBwb3J0IG9mIDAuMDA3IGFuZCBjb25maWRlbmNlIG9mIDAuNDAwLCB3ZSBjYW4gZGV0ZXJtaW5lIHRoYXQgdGhpcyBydWxlIGNvdmVycyAwLjcgcGVyY2VudCBvZiB0aGUgdHJhbnNhY3Rpb25zIGFuZCBpcyBjb3JyZWN0IGluIDQwIHBlcmNlbnQgb2YgcHVyY2hhc2VzIGludm9sdmluZyBwb3R0ZWQgcGxhbnRzLiBUaGUgbGlmdCB2YWx1ZSB0ZWxscyB1cyBob3cgbXVjaCBtb3JlIGxpa2VseSBhIGN1c3RvbWVyIGlzIHRvIGJ1eSB3aG9sZSBtaWxrIHJlbGF0aXZlIHRvIHRoZSBhdmVyYWdlIGN1c3RvbWVyLCBnaXZlbiB0aGF0IGhlIG9yIHNoZSBib3VnaHQgYSBwb3R0ZWQgcGxhbnQuIFNpbmNlIHdlIGtub3cgdGhhdCBhYm91dCAyNS42IHBlcmNlbnQgb2YgdGhlIGN1c3RvbWVycyBib3VnaHQgd2hvbGUgbWlsayAoc3VwcG9ydCksIHdoaWxlIDQwIHBlcmNlbnQgb2YgdGhlIGN1c3RvbWVycyBidXlpbmcgYSBwb3R0ZWQgcGxhbnQgYm91Z2h0IHdob2xlIG1pbGsgKGNvbmZpZGVuY2UpLCB3ZSBjYW4gY29tcHV0ZSB0aGUgbGlmdCB2YWx1ZSBhcyAwLjQwIC8gMC4yNTYgPSAxLjU2LCB3aGljaCBtYXRjaGVzIHRoZSB2YWx1ZSBzaG93bi4KCgojIGxvb2sgYXQgdGhlIGZpcnN0IHRocmVlIHJ1bGVzCmBgYHtyfQppbnNwZWN0KGdyb2NlcnlydWxlc1sxOjNdKQpgYGAKCiMjIFN0ZXAgNTogSW1wcm92aW5nIG1vZGVsIHBlcmZvcm1hbmNlCgojIHNvcnRpbmcgZ3JvY2VyeSBydWxlcyBieSBsaWZ0CmBgYHtyfQppbnNwZWN0KHNvcnQoZ3JvY2VyeXJ1bGVzLCBieSA9ICJsaWZ0IilbMTo1XSkKYGBgClRoZXNlIHJ1bGVzIGFwcGVhciB0byBiZSBtb3JlIGludGVyZXN0aW5nIHRoYW4gdGhlIG9uZXMgd2UgbG9va2VkIGF0IHByZXZpb3VzbHkuIFRoZSBmaXJzdCBydWxlLCB3aXRoIGEgbGlmdCBvZiBhYm91dCAzLjk2LCBpbXBsaWVzIHRoYXQgcGVvcGxlIHdobyBidXkgaGVyYnMgYXJlIG5lYXJseSBmb3VyIHRpbWVzIG1vcmUgbGlrZWx5IHRvIGJ1eSByb290IHZlZ2V0YWJsZXMgdGhhbiB0aGUgdHlwaWNhbCBjdXN0b21lcuKAlHBlcmhhcHMgZm9yIGEgc3RldyBvZiBzb21lIHNvcnQ/IFJ1bGUgdHdvIGlzIGFsc28gaW50ZXJlc3RpbmcuIFdoaXBwZWQgY3JlYW0gaXMgb3ZlciB0aHJlZSB0aW1lcyBtb3JlIGxpa2VseSB0byBiZSBmb3VuZCBpbiBhIHNob3BwaW5nIGNhcnQgd2l0aCBiZXJyaWVzIHZlcnN1cyBvdGhlciBjYXJ0cywgc3VnZ2VzdGluZyBwZXJoYXBzIGEgZGVzc2VydCBwYWlyaW5nPwoKIyBmaW5kaW5nIHN1YnNldHMgb2YgcnVsZXMgY29udGFpbmluZyBhbnkgYmVycnkgaXRlbXMKYGBge3J9CmJlcnJ5cnVsZXMgPC0gc3Vic2V0KGdyb2NlcnlydWxlcywgaXRlbXMgJWluJSAiYmVycmllcyIpCmluc3BlY3QoYmVycnlydWxlcykKYGBgCgoKIyB3cml0aW5nIHRoZSBydWxlcyB0byBhIENTViBmaWxlCmBgYHtyfQp3cml0ZShncm9jZXJ5cnVsZXMsIGZpbGUgPSAiZ3JvY2VyeXJ1bGVzLmNzdiIsCiAgICAgIHNlcCA9ICIsIiwgcXVvdGUgPSBUUlVFLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgoKIyBjb252ZXJ0aW5nIHRoZSBydWxlIHNldCB0byBhIGRhdGEgZnJhbWUKYGBge3J9Cmdyb2NlcnlydWxlc19kZiA8LSBhcyhncm9jZXJ5cnVsZXMsICJkYXRhLmZyYW1lIikKc3RyKGdyb2NlcnlydWxlc19kZikKYGBgCgo=