Wstęp

Dane dotyczą transakcji, a każda transakcja dotyczy zbioru produktów. Chcemy wyznaczyć produkty często kupowane razem.

Oznaczmy przez P zbiór produktów P = {P1, P2, ..., Pn}. Regułą asocjacyjną nazwiemy parę L→R, przy czym L,R to podzbiory zbioru P. Ktoś kto kupił kiełbasę kupił także musztardę i ketchup (kiełbasa → {musztarda,ketchup}.) Prościej się nie da:-)

Reguł postaci L→R można wygenerować dowolnie wiele, ale nie każde są użyteczne. Potrzebne są kryteria użyteczności.

Support (wsparcie) określa jak często zdarza się reguła LR. To iloraz liczby transakcji zawierających regułę LR do liczby wszystkich transakcji. Jeżeli transakcji kiełbasa → {mleko sojowe} jest bardzo mało, to nie mają one większego praktycznego znaczenia (przypadek)

Confidence (wiarygodność), czyli procent LR/L czyli ile transakcji kupna kiełbasy skończyło się kupnem musztardy i ketchupu. Oczywiście interesują nas reguły o dużej wiarygodności. Jeżeli w analizowanym zbiorze transakcji było 2000 zawierających kiełbasę oraz 1500 kiełbasę, musztardę i ketchup to wiarygodność reguły (kiełbasa → {musztarda,ketchup} wynosi 75%.

Lift (podniesienie), wsparcie LR do iloczynu wsparcia L oraz R (iloczyn wspracia L oraz R odpowiada sytuacji gdy L/R są niezależne); Jeżeli lift =1 to nie ma związku między L i R; jeżeli lift > 1 to L zwiększa szanse na R; jeżeli lift < 1 to L zmniejsza szanse na R.

Przykład

Baza danych mbo.db zawiera toy example hurtowni danych składającej się dokładnie z 4 tabel. Tabela TRANS to tabela faktów (pozycje z paragonów); tabele SHOP, PROD, DATE to wymiary:

Baza dla utrudnienia jest w formacie SQLite. Należy dane wydobyć i złączyć. Konkretnie do danych z tablicy TRANS (iid oraz tid – identyfikator paragonu) dodać nazwy produktów (name) żeby całość była bardziej czytelna. Tutaj od razu do akcji wkracza język programowania R. Korzystamy z dwóch bibliotek arules do wyznaczania reguł asocjacyjnych oraz RSQLite do komunikowania się z SQLite:

library("arules")
library(RSQLite)

## Łączenie się z bazą z pliku mbo.db
myDB <- "mbo.db"
conn <- dbConnect(drv = SQLite(), dbname= myDB)

## lista sklepów na rozgrzewkę
## shops <- dbGetQuery(conn, "SELECT *  FROM shop")

## lista pozycji (złączenie tablei TRANS z PROD)
items <- dbGetQuery(conn, "SELECT iid, tid, name  FROM tran 
                    inner join prod on tran.pid=prod.pid")

## zamykamy bazę
dbDisconnect(conn)

W tym momencie ramka items zawiera dane niezbędne do analizy:

translist <- split (items$name, items$tid, "transactions")
rul <- apriori(translist, parameter = list(support=0.005, 
                                           confidence=0.5, maxlen=10, minlen=2))
## Warning in asMethod(object): removing duplicated items in transactions
## Apriori
## 
## Parameter specification:
##  confidence minval smax arem  aval originalSupport maxtime support minlen
##         0.5    0.1    1 none FALSE            TRUE       5   0.005      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: 37 
## 
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[120 item(s), 7501 transaction(s)] done [0.00s].
## sorting and recoding items ... [101 item(s)] done [0.00s].
## creating transaction tree ... done [0.00s].
## checking subsets of size 1 2 3 4 done [0.00s].
## writing ... [20 rule(s)] done [0.00s].
## creating S4 object  ... done [0.00s].
inspect(rul)
##      lhs                                 rhs             support     confidence
## [1]  {salmon, spaghetti}              => {mineral water} 0.006799093 0.5049505 
## [2]  {olive oil, soup}                => {mineral water} 0.005199307 0.5820896 
## [3]  {frozen vegetables, soup}        => {mineral water} 0.005065991 0.6333333 
## [4]  {ground beef, soup}              => {mineral water} 0.005065991 0.5205479 
## [5]  {milk, soup}                     => {mineral water} 0.008532196 0.5614035 
## [6]  {chocolate, soup}                => {mineral water} 0.005599253 0.5526316 
## [7]  {soup, spaghetti}                => {mineral water} 0.007465671 0.5233645 
## [8]  {cooking oil, eggs}              => {mineral water} 0.006399147 0.5454545 
## [9]  {milk, turkey}                   => {mineral water} 0.006132516 0.5411765 
## [10] {chicken, chocolate}             => {mineral water} 0.007598987 0.5181818 
## [11] {frozen vegetables, olive oil}   => {spaghetti}     0.005732569 0.5058824 
## [12] {frozen vegetables, olive oil}   => {mineral water} 0.006532462 0.5764706 
## [13] {milk, olive oil}                => {mineral water} 0.008532196 0.5000000 
## [14] {chocolate, olive oil}           => {mineral water} 0.008265565 0.5040650 
## [15] {ground beef, shrimp}            => {spaghetti}     0.005999200 0.5232558 
## [16] {ground beef, pancakes}          => {mineral water} 0.007465671 0.5137615 
## [17] {frozen vegetables, ground beef} => {spaghetti}     0.008665511 0.5118110 
## [18] {frozen vegetables, ground beef} => {mineral water} 0.009198773 0.5433071 
## [19] {ground beef, milk}              => {mineral water} 0.011065191 0.5030303 
## [20] {eggs, ground beef}              => {mineral water} 0.010131982 0.5066667 
##      coverage    lift     count
## [1]  0.013464871 2.118363 51   
## [2]  0.008932142 2.441976 39   
## [3]  0.007998933 2.656954 38   
## [4]  0.009732036 2.183798 38   
## [5]  0.015197974 2.355194 64   
## [6]  0.010131982 2.318395 42   
## [7]  0.014264765 2.195614 56   
## [8]  0.011731769 2.288286 48   
## [9]  0.011331822 2.270338 46   
## [10] 0.014664711 2.173871 57   
## [11] 0.011331822 2.905531 43   
## [12] 0.011331822 2.418404 49   
## [13] 0.017064391 2.097595 64   
## [14] 0.016397814 2.114649 62   
## [15] 0.011465138 3.005315 45   
## [16] 0.014531396 2.155327 56   
## [17] 0.016931076 2.939582 65   
## [18] 0.016931076 2.279277 69   
## [19] 0.021997067 2.110308 83   
## [20] 0.019997334 2.125563 76

albo ładniej:

bjuty_rules <- DATAFRAME(rul)
library("knitr")
kable(bjuty_rules, col.names = c('L', 'R', 'wsparcie', 'wiarygodność', 'coverage',
                                 'lift', 'n'))
L R wsparcie wiarygodność coverage lift n
{salmon,spaghetti} {mineral water} 0.0067991 0.5049505 0.0134649 2.118363 51
{olive oil,soup} {mineral water} 0.0051993 0.5820896 0.0089321 2.441976 39
{frozen vegetables,soup} {mineral water} 0.0050660 0.6333333 0.0079989 2.656954 38
{ground beef,soup} {mineral water} 0.0050660 0.5205479 0.0097320 2.183798 38
{milk,soup} {mineral water} 0.0085322 0.5614035 0.0151980 2.355195 64
{chocolate,soup} {mineral water} 0.0055993 0.5526316 0.0101320 2.318395 42
{soup,spaghetti} {mineral water} 0.0074657 0.5233645 0.0142648 2.195613 56
{cooking oil,eggs} {mineral water} 0.0063991 0.5454545 0.0117318 2.288286 48
{milk,turkey} {mineral water} 0.0061325 0.5411765 0.0113318 2.270338 46
{chicken,chocolate} {mineral water} 0.0075990 0.5181818 0.0146647 2.173871 57
{frozen vegetables,olive oil} {spaghetti} 0.0057326 0.5058824 0.0113318 2.905531 43
{frozen vegetables,olive oil} {mineral water} 0.0065325 0.5764706 0.0113318 2.418404 49
{milk,olive oil} {mineral water} 0.0085322 0.5000000 0.0170644 2.097595 64
{chocolate,olive oil} {mineral water} 0.0082656 0.5040650 0.0163978 2.114649 62
{ground beef,shrimp} {spaghetti} 0.0059992 0.5232558 0.0114651 3.005315 45
{ground beef,pancakes} {mineral water} 0.0074657 0.5137615 0.0145314 2.155327 56
{frozen vegetables,ground beef} {spaghetti} 0.0086655 0.5118110 0.0169311 2.939582 65
{frozen vegetables,ground beef} {mineral water} 0.0091988 0.5433071 0.0169311 2.279276 69
{ground beef,milk} {mineral water} 0.0110652 0.5030303 0.0219971 2.110308 83
{eggs,ground beef} {mineral water} 0.0101320 0.5066667 0.0199973 2.125563 76

koniec analizy…