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.
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…