1 Wprowadzenie

Analiza koszyka zakupowego (market basket analysis) jest jedną z najczęściej stosowanych technik eksploracji danych w handlu detalicznym. Jej celem jest odkrycie ukrytych wzorców współwystępowania produktów w transakcjach zakupowych. Wyniki takiej analizy pozwalają lepiej rozumieć zachowania klientów i podejmować bardziej trafne decyzje biznesowe, takie jak optymalizacja układu sklepowego, tworzenie promocji krzyżowych czy rekomendacje produktowe.

Głównym narzędziem stosowanym w analizie koszyka zakupowego są reguły asocjacyjne (association rules). Reguła asocjacyjna ma postać:

\[\{A\} \Rightarrow \{B\}\]

co oznacza: „jeśli klient kupuje produkt A, to z dużym prawdopodobieństwem kupi również produkt B”.

1.1 Miary jakości reguł

Do oceny jakości reguł asocjacyjnych stosuje się trzy podstawowe miary:

  • Support (wsparcie) – określa, jak często dany zbiór produktów pojawia się we wszystkich transakcjach. Wartość 0.05 oznacza, że produkty te współwystąpiły w 5% wszystkich paragonów: \[\text{support}(A \Rightarrow B) = \frac{|\text{transakcje zawierające A i B}|}{|\text{wszystkie transakcje}|}\]

  • Confidence (pewność) – określa, jak często reguła jest prawdziwa, czyli jaki odsetek transakcji zawierających A zawiera również B. Wartość 0.8 oznacza, że w 80% przypadków, gdy klient kupił A, kupił też B: \[\text{confidence}(A \Rightarrow B) = \frac{|\text{transakcje zawierające A i B}|}{|\text{transakcje zawierające A}|}\]

  • Lift (dźwignia) – mierzy siłę zależności między A i B w odniesieniu do losowego współwystępowania. Lift = 1 oznacza brak zależności (produkty kupowane niezależnie), lift > 1 oznacza pozytywną zależność (produkty kupowane razem częściej niż losowo), lift < 1 oznacza zależność negatywną: \[\text{lift}(A \Rightarrow B) = \frac{\text{confidence}(A \Rightarrow B)}{\text{support}(B)}\]

1.2 Algorytm Apriori

Najszerzej stosowanym algorytmem do wyznaczania reguł asocjacyjnych jest algorytm Apriori (Agrawal & Srikant, 1994). Opiera się on na właściwości antymonotoniczności: jeśli dany zbiór elementów jest rzadki (nie spełnia minimalnego progu wsparcia), to żaden jego nadzbiór również nie będzie spełniał tego progu. Dzięki temu algorytm efektywnie ogranicza przestrzeń poszukiwań i nie sprawdza wszystkich możliwych kombinacji produktów.

Działanie algorytmu przebiega dwuetapowo:

  1. Znajdowanie zbiorów częstych – algorytm wyszukuje wszystkie zestawy produktów, które pojawiają się w transakcjach co najmniej z zadaną minimalną częstością (parametr minsupp).
  2. Generowanie reguł – ze zbiorów częstych tworzone są reguły asocjacyjne, spełniające minimalny próg pewności (parametr minconf).

2 Opis zbioru danych

W analizie wykorzystano zbiór danych Groceries dostępny w pakiecie arules. Jest to klasyczny, rzeczywisty zbiór danych często wykorzystywany w dydaktyce i badaniach dotyczących reguł asocjacyjnych. Zawiera dane transakcyjne z jednego miesiąca działalności małego sklepu spożywczego.

# Wczytanie niezbędnych pakietów.
# Pakiet 'arules' dostarcza algorytm Apriori i format danych transakcyjnych.
# Pakiet 'arulesViz' umożliwia wizualizację odkrytych reguł.

library(arules)
library(arulesViz)

# Wczytanie zbioru danych Groceries.
data("Groceries")
# Funkcja summary() dla obiektu klasy 'transactions' zwraca:
# - liczbę transakcji i produktów
# - rozkład długości transakcji (ile produktów na paragon)
# - listę najczęściej kupowanych produktów wraz z ich częstością
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  level2           level1
## 1 frankfurter sausage meat and sausage
## 2     sausage sausage meat and sausage
## 3  liver loaf sausage meat and sausage

Zbiór danych Groceries zawiera 9845 transakcji oraz 169 unikalnych produktów. Każda transakcja odpowiada jednemu paragonowi zakupowemu i zawiera listę kupionych artykułów. Dane obejmują zakupy dokonane w ciągu jednego miesiąca. Najczęściej kupowanymi produktami są whole mil other vegatebles oraz rolls/buns

# Wypisanie podstawowych wymiarów zbioru danych.
# nrow() zwraca liczbę wierszy, czyli transakcji.
# ncol() zwraca liczbę kolumn, czyli unikalnych produktów (pozycji asortymentowych).
cat("Liczba transakcji:", nrow(Groceries), "\n")
## Liczba transakcji: 9835
cat("Liczba unikalnych produktów:", ncol(Groceries), "\n")
## Liczba unikalnych produktów: 169
# Wykres słupkowy przedstawiający 20 produktów o największej łącznej liczbie
# wystąpień we wszystkich transakcjach.
# type = "absolute" oznacza, że oś Y pokazuje bezwzględną liczbę transakcji
# (a nie procent) – łatwiej to zinterpretować na początku analizy.
itemFrequencyPlot(
  Groceries,
  topN = 20,
  type = "absolute",
  col = "steelblue",
  main = "20 najczęściej kupowanych produktów",
  ylab = "Liczba transakcji",
  xlab = ""
)

Powyższy wykres przedstawia 20 produktów najczęściej pojawiających się w transakcjach. Zdecydowanie najczęściej kupowanym artykułem jest pełne mleko, które pojawia się w 2500 transakcjach. Kolejne miejsca zajmują inne warzywa (other vegetables) oraz bułki i pieczywo(rolls/buns). Wyraźna różnica między pierwszym a pozostałymi produktami sugeruje wyjątkową rolę mleka w codziennych zakupach klientów tego sklepu.

# Ten wykres pokazuje tę samą informację co poprzedni, ale w wartościach względnych.
# type = "relative" – oś Y pokazuje odsetek wszystkich transakcji, w których
# dany produkt się pojawił (wartość od 0 do 1, gdzie 1 = 100%).
# Pozwala to ocenić, jak "popularny" jest produkt w stosunku do całej bazy.
itemFrequencyPlot(
  Groceries,
  topN = 20,
  type = "relative",
  col = "coral",
  main = "Względna częstotliwość 20 najczęstszych produktów",
  ylab = "Odsetek transakcji",
  xlab = ""
)

Patrząc na częstotliwości względne, pełne mleko pojawia się w blisko ok. 25–26% wszystkich transakcji, co czyni je zdecydowanie najpopularniejszym produktem w zbiorze. Inne warzywa pojawiają się w około ok. 19% transakcji. Warto zauważyć, że nawet najczęstszy produkt obecny jest tylko w co czwartym paragonie – jest to typowe dla danych zakupowych, gdzie klienci kupują zróżnicowany asortyment.


3 Przygotowanie danych

Zbiór Groceries jest już w formacie transakcyjnym (transactions), który jest natywnie obsługiwany przez pakiet arules. Nie wymaga zatem konwersji ani szerokiego przetwarzania wstępnego. Warto jednak zbadać rozkład długości transakcji, który może wpłynąć na dobór parametrów algorytmu.

# Funkcja size() zwraca wektor liczb – ile produktów zawierała każda transakcja.
# Na jego podstawie obliczamy podstawowe statystyki opisowe.
transakcje_dl <- size(Groceries)

cat("Minimalna liczba produktów w transakcji:", min(transakcje_dl), "\n")
## Minimalna liczba produktów w transakcji: 1
cat("Maksymalna liczba produktów w transakcji:", max(transakcje_dl), "\n")
## Maksymalna liczba produktów w transakcji: 32
cat("Średnia liczba produktów w transakcji:", round(mean(transakcje_dl), 2), "\n")
## Średnia liczba produktów w transakcji: 4.41
cat("Mediana liczby produktów w transakcji:", median(transakcje_dl), "\n")
## Mediana liczby produktów w transakcji: 3

.

Przeciętna transakcja zawiera średnio 4,41 produktów mediana wynosi zaś 3 produkty, choć zdarzają się paragony zawierające nawet 32 pozycji. Niska mediana wskazuje, że większość klientów robi stosunkowo małe zakupy.

# Histogram wizualizuje rozkład długości transakcji.
# breaks = 30 – liczba przedziałów histogramu (więcej = dokładniejszy wykres).
# Czerwona przerywana linia (abline) oznacza wartość średniej – 
# pomaga zobaczyć, czy rozkład jest symetryczny czy skośny.
hist(
  transakcje_dl,
  breaks = 30,
  col = "lightblue",
  border = "white",
  main = "Rozkład liczby produktów w transakcjach",
  xlab = "Liczba produktów",
  ylab = "Liczba transakcji"
)
abline(v = mean(transakcje_dl), col = "red", lwd = 2, lty = 2)
legend("topright", legend = paste("Średnia:", round(mean(transakcje_dl), 2)),
       col = "red", lty = 2, lwd = 2)

Rozkład długości transakcji jest prawostronnie skośny – słupki są skupione po lewej stronie (małe transakcje), a prawy ogon wykresu jest długi (nieliczne duże zakupy). Oznacza to, że większość klientów kupuje od 1 do 5 produktów, ale zdarzają się paragony z kilkunastoma lub kilkudziesięcioma pozycjami. Taki rozkład jest typowy dla danych zakupowych z supermarketów.


4 Reguły asocjacyjne – algorytm Apriori

4.1 Dobór parametrów

Przed uruchomieniem algorytmu należy ustalić dwa kluczowe progi:

  • supp (minimalne wsparcie) – określa, jak często para/grupa produktów musi się pojawiać w transakcjach, aby była w ogóle brana pod uwagę. Zbyt wysoki próg pomija rzadkie, ale interesujące zależności; zbyt niski tworzy miliony reguł. Przy 9835 transakcjach, supp = 0.01 oznacza, że produkty muszą się pojawić razem co najmniej w ~98 transakcjach.
  • conf (minimalna pewność) – określa minimalną „trafność” reguły. conf = 0.25 oznacza, że reguła musi być prawdziwa w co najmniej 25% przypadków.
  • minlen = 2 – wyklucza reguły jednoelementowe (sam produkt bez kontekstu), które nie mają sensu w analizie asocjacyjnej.
# Uruchomienie algorytmu Apriori.
# Wynik zapisujemy do obiektu 'reguly' klasy 'rules'.
# Algorytm wypisze w konsoli informacje o postępie obliczeń –
# pojawi się np. "writing ... rules" i liczba znalezionych reguł.
reguly <- apriori(
  Groceries,
  parameter = list(
    supp   = 0.01,
    conf   = 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.01      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: 98 
## 
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[169 item(s), 9835 transaction(s)] done [0.00s].
## sorting and recoding items ... [88 item(s)] done [0.00s].
## creating transaction tree ... done [0.00s].
## checking subsets of size 1 2 3 4 done [0.00s].
## writing ... [170 rule(s)] done [0.00s].
## creating S4 object  ... done [0.00s].
# Podsumowanie wyników – pokazuje m.in.:
# - całkowitą liczbę reguł
# - rozkład długości reguł (ile reguł 2-elementowych, 3-elementowych itd.)
# - statystyki miar jakości (min, średnia, max dla support, confidence, lift)
summary(reguly)
## set of 170 rules
## 
## rule length distribution (lhs + rhs):sizes
##  2  3 
## 96 74 
## 
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   2.000   2.000   2.000   2.435   3.000   3.000 
## 
## summary of quality measures:
##     support          confidence        coverage            lift       
##  Min.   :0.01007   Min.   :0.2517   Min.   :0.01729   Min.   :0.9932  
##  1st Qu.:0.01159   1st Qu.:0.2973   1st Qu.:0.03101   1st Qu.:1.5215  
##  Median :0.01454   Median :0.3587   Median :0.04291   Median :1.7784  
##  Mean   :0.01822   Mean   :0.3703   Mean   :0.05187   Mean   :1.8747  
##  3rd Qu.:0.02097   3rd Qu.:0.4253   3rd Qu.:0.05857   3rd Qu.:2.1453  
##  Max.   :0.07483   Max.   :0.5862   Max.   :0.25552   Max.   :3.2950  
##      count      
##  Min.   : 99.0  
##  1st Qu.:114.0  
##  Median :143.0  
##  Mean   :179.2  
##  3rd Qu.:206.2  
##  Max.   :736.0  
## 
## mining info:
##       data ntransactions support confidence
##  Groceries          9835    0.01       0.25
##                                                                               call
##  apriori(data = Groceries, parameter = list(supp = 0.01, conf = 0.25, minlen = 2))
# Funkcja length() zwraca liczbę reguł w obiekcie 'reguly'.
cat("Liczba odkrytych reguł:", length(reguly), "\n")
## Liczba odkrytych reguł: 170

Algorytm Apriori przy zadanych parametrach odkrył łącznie 170 reguł asocjacyjnych. Większość z nich to reguły około 2 elementowe. Maksymalna wartość lift wynosi 3,29, co świadczy o tym, że niektóre produkty są ze sobą silnie powiązane.

4.2 Podgląd najlepszych reguł według lift

# Funkcja sort() sortuje reguły według wybranej miary (tu: lift, malejąco).
# Funkcja inspect() wyświetla reguły w czytelnej formie tabelarycznej:
# kolumny to: lhs (lewa strona), rhs (prawa strona), support, confidence, coverage, lift, count.
# [1:15] – pokazujemy tylko 15 pierwszych (najlepszych) reguł.
inspect(sort(reguly, by = "lift")[1:15])
##      lhs                                   rhs                support   
## [1]  {citrus fruit, other vegetables}   => {root vegetables}  0.01037112
## [2]  {tropical fruit, other vegetables} => {root vegetables}  0.01230300
## [3]  {beef}                             => {root vegetables}  0.01738688
## [4]  {citrus fruit, root vegetables}    => {other vegetables} 0.01037112
## [5]  {tropical fruit, root vegetables}  => {other vegetables} 0.01230300
## [6]  {other vegetables, whole milk}     => {root vegetables}  0.02318251
## [7]  {whole milk, curd}                 => {yogurt}           0.01006609
## [8]  {other vegetables, yogurt}         => {root vegetables}  0.01291307
## [9]  {other vegetables, yogurt}         => {tropical fruit}   0.01230300
## [10] {other vegetables, rolls/buns}     => {root vegetables}  0.01220132
## [11] {tropical fruit, whole milk}       => {root vegetables}  0.01199797
## [12] {root vegetables, rolls/buns}      => {other vegetables} 0.01220132
## [13] {root vegetables, yogurt}          => {other vegetables} 0.01291307
## [14] {whole milk, yogurt}               => {tropical fruit}   0.01514997
## [15] {pip fruit}                        => {tropical fruit}   0.02043721
##      confidence coverage   lift     count
## [1]  0.3591549  0.02887646 3.295045 102  
## [2]  0.3427762  0.03589222 3.144780 121  
## [3]  0.3313953  0.05246568 3.040367 171  
## [4]  0.5862069  0.01769192 3.029608 102  
## [5]  0.5845411  0.02104728 3.020999 121  
## [6]  0.3097826  0.07483477 2.842082 228  
## [7]  0.3852140  0.02613116 2.761356  99  
## [8]  0.2974239  0.04341637 2.728698 127  
## [9]  0.2833724  0.04341637 2.700550 121  
## [10] 0.2863962  0.04260295 2.627525 120  
## [11] 0.2836538  0.04229792 2.602365 118  
## [12] 0.5020921  0.02430097 2.594890 120  
## [13] 0.5000000  0.02582613 2.584078 127  
## [14] 0.2704174  0.05602440 2.577089 149  
## [15] 0.2701613  0.07564820 2.574648 201

eguły przedstawione w tabeli zostały posortowane według wartości miary lift, która informuje o sile zależności pomiędzy produktami. Im wyższa wartość lift, tym silniejsza jest współzależność między elementami reguły – oznacza to, że produkty występują razem w transakcjach częściej, niż wynikałoby to z ich niezależnych częstości występowania.

Najwyższą wartość lift (3,29) osiąga reguła:

{citrus fruit, other vegetables} ⇒ {root vegetables}.

Oznacza to, że jeśli w koszyku zakupowym znajdują się cytrusy oraz inne warzywa, to prawdopodobieństwo zakupu warzyw korzeniowych jest ponad trzykrotnie wyższe, niż gdyby produkty te były kupowane całkowicie niezależnie. Reguła ta charakteryzuje się confidence na poziomie 0,36, co oznacza, że w około 36% transakcji zawierających cytrusy i inne warzywa pojawiają się również warzywa korzeniowe.

Podobnie wysokie wartości lift obserwujemy dla reguł:

{tropical fruit, other vegetables} ⇒ {root vegetables} (lift ≈ 3,14),

{beef} ⇒ {root vegetables} (lift ≈ 3,04).

Wskazuje to na silną współzależność pomiędzy zakupem warzyw korzeniowych a innymi produktami spożywczymi, szczególnie warzywami oraz niektórymi produktami białkowymi. Może to sugerować, że produkty te są często wykorzystywane razem w przygotowywaniu posiłków.

Interesujące zależności widoczne są również w odwrotnym kierunku. Na przykład reguła:

{citrus fruit, root vegetables} ⇒ {other vegetables}

osiąga confidence równy 0,59, co oznacza, że w niemal 60% przypadków, gdy klienci kupują cytrusy i warzywa korzeniowe, w koszyku pojawiają się również inne warzywa. Sugeruje to, że zakupy tych produktów mają często charakter komplementarny.

Warto również zwrócić uwagę na reguły związane z produktami mlecznymi, np.:

{whole milk, curd} ⇒ {yogurt} (lift ≈ 2,76),

co wskazuje, że klienci kupujący mleko i twaróg relatywnie często nabywają także jogurt. Może to odzwierciedlać wspólne preferencje konsumentów dotyczące produktów mlecznych.

Ogólnie uzyskane reguły sugerują, że wiele zidentyfikowanych zależności dotyczy produktów komplementarnych, które są wykorzystywane razem w przygotowywaniu posiłków. Tego typu informacje mogą być wykorzystywane w praktyce handlowej, np. przy projektowaniu promocji łączonych, rekomendacji produktów lub optymalizacji rozmieszczenia towarów w sklepie.

4.3 Podgląd najlepszych reguł według confidence

# To samo, ale sortowanie według pewności (confidence).
# Reguły o wysokiej confidence to takie, gdzie "jeśli A to prawie na pewno B".
# Uwaga: wysoka confidence niekoniecznie oznacza interesującą regułę –
# jeśli produkt B jest bardzo popularny (np. whole milk), 
# to wiele reguł będzie miało go po prawej stronie z wysoką pewnością.
inspect(sort(reguly, by = "confidence")[1:10])
##      lhs                                  rhs                support   
## [1]  {citrus fruit, root vegetables}   => {other vegetables} 0.01037112
## [2]  {tropical fruit, root vegetables} => {other vegetables} 0.01230300
## [3]  {curd, yogurt}                    => {whole milk}       0.01006609
## [4]  {other vegetables, butter}        => {whole milk}       0.01148958
## [5]  {tropical fruit, root vegetables} => {whole milk}       0.01199797
## [6]  {root vegetables, yogurt}         => {whole milk}       0.01453991
## [7]  {other vegetables, domestic eggs} => {whole milk}       0.01230300
## [8]  {yogurt, whipped/sour cream}      => {whole milk}       0.01087951
## [9]  {root vegetables, rolls/buns}     => {whole milk}       0.01270971
## [10] {pip fruit, other vegetables}     => {whole milk}       0.01352313
##      confidence coverage   lift     count
## [1]  0.5862069  0.01769192 3.029608 102  
## [2]  0.5845411  0.02104728 3.020999 121  
## [3]  0.5823529  0.01728521 2.279125  99  
## [4]  0.5736041  0.02003050 2.244885 113  
## [5]  0.5700483  0.02104728 2.230969 118  
## [6]  0.5629921  0.02582613 2.203354 143  
## [7]  0.5525114  0.02226741 2.162336 121  
## [8]  0.5245098  0.02074225 2.052747 107  
## [9]  0.5230126  0.02430097 2.046888 125  
## [10] 0.5175097  0.02613116 2.025351 133

Reguły o najwyższej pewności mają po prawej stronie najczęściej produkt whole milk, lub other vegatables. Wynika to z jego wysokiej popularności w zbiorze – skoro pojawia się w ~25% wszystkich transakcji, naturalnie trafia do wielu reguł jako „domyślny” następnik. Dlatego sama wysoka confidence nie wystarczy do oceny jakości reguły – konieczne jest spojrzenie łączne na wszystkie trzy miary.


5 Analiza i wizualizacja reguł

Wizualizacje pomagają zobaczyć strukturę całego zbioru reguł, a nie tylko pojedyncze wiersze tabeli. Każdy wykres poniżej pokazuje ten sam zestaw reguł z innej perspektywy.

5.1 Wykres rozrzutu (scatter plot)

# Każda reguła to jeden punkt na wykresie.
# Oś X = support (jak często produkty współwystępują)
# Oś Y = confidence (jak pewna jest reguła)
# Kolor punktu = lift (im ciemniejszy/intensywniejszy, tym wyższy lift)
# Reguły w lewym górnym rogu mają niskie wsparcie, ale wysoką pewność i lift –
# są rzadkie, ale silne. To często najbardziej interesujące reguły.
plot(
  reguly,
  method = "scatterplot",
  measure = c("support", "confidence"),
  shading = "lift",
  main = "Reguły asocjacyjne: support vs confidence (kolor = lift)"
)

Wykres rozrzutu przedstawia wszystkie 170 odkrytych reguł. Widoczna jest typowa zależność: reguły o wysokim lift (ciemniejszy kolor) skupiają się w lewej górnej części wykresu – mają niższe wsparcie (rzadziej się pojawiają), ale wyższą pewność i silniejsze zależności. Reguły o wysokim wsparciu (prawa strona wykresu) mają zazwyczaj niższy lift, co oznacza że produkty te współwystępują często, ale niekoniecznie zaskakująco.

5.2 Wykres grupowy (grouped matrix)

# Wykres grupuje reguły według lewej strony (LHS) i prawej strony (RHS).
# Bąbelki na przecięciu wierszy i kolumn oznaczają istnienie reguły.
# Rozmiar bąbelka = support (im większy, tym częściej ta kombinacja się pojawia)
# Kolor bąbelka = lift (im intensywniejszy, tym silniejsza zależność)
# Pokazujemy tylko 20 reguł z najwyższym lift, żeby wykres był czytelny.
plot(
  sort(reguly, by = "lift")[1:20],
  method = "grouped",
  main = "Grupy reguł – 20 najlepszych wg lift"
)
## Available control parameters (with default values):
## k     =  20
## aggr.fun  =  function (x, ...)  UseMethod("mean")
## rhs_max   =  10
## lhs_label_items   =  2
## col   =  c("#EE0000FF", "#EEEEEEFF")
## groups    =  NULL
## engine    =  ggplot2
## verbose   =  FALSE

Wykres grupowy pozwala szybko zobaczyć, które produkty po lewej stronie (LHS) prowadzą do których po prawej (RHS). Duże, intensywnie zabarwione bąbelki wskazują na reguły z wysokim wsparciem i wysokim lift jednocześnie – najbardziej wartościowe z praktycznego punktu widzenia.

5.3 Graf reguł (interaktywny)

# Graf sieciowy – jeden z najbardziej intuicyjnych sposobów wizualizacji reguł.
# Węzły (kółka) = produkty
# Strzałki = kierunek reguły (od LHS do RHS)
# Grubość/kolor krawędzi = wartość lift
# engine = "htmlwidget" tworzy interaktywny wykres – można przybliżać,
# oddalać i przeciągać węzły myszką w wygenerowanym raporcie HTML.
# Pokazujemy 20 reguł z najwyższym lift.
plot(
  sort(reguly, by = "lift")[1:20],
  method = "graph",
  engine = "htmlwidget"
)

Graf reguł w formie interaktywnej pozwala eksplorować powiązania między produktami. Węzły z wieloma połączeniami (tzw. hubs) to produkty centralne – pojawiają się w wielu regułach jednocześnie. W zbiorze Groceries takim centralnym węzłem jest zazwyczaj whole milk lub other vegetables.

5.4 Wykres równoległy (parallel coordinates)

# Wykres równoległy dobrze sprawdza się dla reguł wieloelementowych
# (np. {A, B} → {C}), gdzie mamy więcej niż 2 produkty w regule.
# Każda linia = jedna reguła, przebiegająca przez "kolumny" = pozycje w regule.
# Grubość linii = support (grubsza = częstsza reguła)
# Kolor = lift
plot(
  sort(reguly, by = "lift")[1:15],
  method = "paracoord",
  main = "Wykres równoległy – 15 reguł o najwyższym lift"
)

Wykres równoległy wizualizuje strukturę reguł wieloelementowych. Grubsze linie odpowiadają regułom o wyższym wsparciu. Można odczytać, że reguły z najwyższym lift często łączą mleko


6 Interpretacja wyników

6.1 Reguły dotyczące wybranego produktu – pełne mleko

Możemy zawęzić analizę do reguł dotyczących konkretnego produktu. Poniżej sprawdzamy, co prowadzi do zakupu pełnego mleka (whole milk) – czyli jakie produkty po lewej stronie reguły skutkują mlekiem po prawej.

# subset() filtruje reguły według podanego warunku.
# rhs %in% "whole milk" – wybieramy tylko reguły, gdzie prawa strona to "whole milk"
# (czyli reguły postaci: {coś} => {whole milk})
# Następnie sortujemy według lift i pokazujemy 10 najlepszych.
reguly_mleko <- subset(reguly, rhs %in% "whole milk")
inspect(sort(reguly_mleko, by = "lift")[1:10])
##      lhs                                  rhs          support    confidence
## [1]  {curd, yogurt}                    => {whole milk} 0.01006609 0.5823529 
## [2]  {other vegetables, butter}        => {whole milk} 0.01148958 0.5736041 
## [3]  {tropical fruit, root vegetables} => {whole milk} 0.01199797 0.5700483 
## [4]  {root vegetables, yogurt}         => {whole milk} 0.01453991 0.5629921 
## [5]  {other vegetables, domestic eggs} => {whole milk} 0.01230300 0.5525114 
## [6]  {yogurt, whipped/sour cream}      => {whole milk} 0.01087951 0.5245098 
## [7]  {root vegetables, rolls/buns}     => {whole milk} 0.01270971 0.5230126 
## [8]  {pip fruit, other vegetables}     => {whole milk} 0.01352313 0.5175097 
## [9]  {tropical fruit, yogurt}          => {whole milk} 0.01514997 0.5173611 
## [10] {other vegetables, yogurt}        => {whole milk} 0.02226741 0.5128806 
##      coverage   lift     count
## [1]  0.01728521 2.279125  99  
## [2]  0.02003050 2.244885 113  
## [3]  0.02104728 2.230969 118  
## [4]  0.02582613 2.203354 143  
## [5]  0.02226741 2.162336 121  
## [6]  0.02074225 2.052747 107  
## [7]  0.02430097 2.046888 125  
## [8]  0.02613116 2.025351 133  
## [9]  0.02928317 2.024770 149  
## [10] 0.04341637 2.007235 219

Reguły prowadzące do zakupu pełnego mleka (whole milk) wskazują, że produkt ten często pojawia się w koszykach zawierających inne artykuły spożywcze, szczególnie z kategorii produktów mlecznych oraz świeżej żywności.

Najwyższą wartość lift osiąga reguła:

{curd, yogurt} ⇒ {whole milk}

z confidence = 0,58 i lift = 2,28. Oznacza to, że klienci kupujący twaróg i jogurt są ponad 2,2 razy bardziej skłonni do zakupu pełnego mleka niż przeciętny klient.

Podobną zależność obserwujemy w regule:

{other vegetables, butter} ⇒ {whole milk}

gdzie confidence wynosi 0,57, a lift ≈ 2,24. Wskazuje to, że mleko często pojawia się w koszykach zawierających warzywa oraz masło, co może odzwierciedlać zakupy produktów wykorzystywanych wspólnie w przygotowywaniu posiłków.

Ogólnie analizowane reguły sugerują, że pełne mleko jest produktem komplementarnym, który często współwystępuje z innymi produktami spożywczymi kupowanymi w ramach codziennych zakupów. ## Reguły dotyczące warzyw

# Analogicznie – filtrujemy reguły, gdzie następnikiem są "other vegetables".
reguly_warzywa <- subset(reguly, rhs %in% "other vegetables")
inspect(sort(reguly_warzywa, by = "lift")[1:10])
##      lhs                                  rhs                support   
## [1]  {citrus fruit, root vegetables}   => {other vegetables} 0.01037112
## [2]  {tropical fruit, root vegetables} => {other vegetables} 0.01230300
## [3]  {root vegetables, rolls/buns}     => {other vegetables} 0.01220132
## [4]  {root vegetables, yogurt}         => {other vegetables} 0.01291307
## [5]  {yogurt, whipped/sour cream}      => {other vegetables} 0.01016777
## [6]  {root vegetables, whole milk}     => {other vegetables} 0.02318251
## [7]  {onions}                          => {other vegetables} 0.01423488
## [8]  {pork, whole milk}                => {other vegetables} 0.01016777
## [9]  {whole milk, whipped/sour cream}  => {other vegetables} 0.01464159
## [10] {pip fruit, whole milk}           => {other vegetables} 0.01352313
##      confidence coverage   lift     count
## [1]  0.5862069  0.01769192 3.029608 102  
## [2]  0.5845411  0.02104728 3.020999 121  
## [3]  0.5020921  0.02430097 2.594890 120  
## [4]  0.5000000  0.02582613 2.584078 127  
## [5]  0.4901961  0.02074225 2.533410 100  
## [6]  0.4740125  0.04890696 2.449770 228  
## [7]  0.4590164  0.03101169 2.372268 140  
## [8]  0.4587156  0.02216573 2.370714 100  
## [9]  0.4542587  0.03223183 2.347679 144  
## [10] 0.4493243  0.03009659 2.322178 133

Reguły prowadzące do zakupu innych warzyw (other vegetables) wskazują, że produkt ten często pojawia się w koszykach zawierających inne warzywa lub owoce.

Przykładowo reguła {citrus fruit, root vegetables} ⇒ {other vegetables} osiga confidence = 0,59 oraz lift ≈ 3,03, co oznacza, że klienci kupujący cytrusy i warzywa korzeniowe są ponad trzykrotnie bardziej skłonni do zakupu innych warzyw niż przeciętny klient.

Podobną zależność obserwujemy w regule {tropical fruit, root vegetables} ⇒ {other vegetables}, gdzie confidence wynosi ok. 0,58, a lift ≈ 3,02.

Wyniki te sugerują, że zakupy warzyw i owoców często mają komplementarny charakter, a klienci kupujący jedną kategorię świeżych produktów mają tendencję do wybierania również innych warzyw w tej samej transakcji.

6.2 Mocne reguły – filtrowanie według progów

# Zawężamy zestaw reguł do tych, które jednocześnie spełniają:
# lift > 2      – produkty współwystępują ponad 2x częściej niż losowo
# confidence > 0.4 – reguła jest prawdziwa w ponad 40% przypadków
# To tzw. "mocne reguły" – najbardziej wiarygodne i zaskakujące jednocześnie.
mocne_reguly <- subset(reguly, lift > 2 & confidence > 0.4)
cat("Liczba mocnych reguł (lift > 2, conf > 0.4):", length(mocne_reguly), "\n")
## Liczba mocnych reguł (lift > 2, conf > 0.4): 29
inspect(sort(mocne_reguly, by = "lift"))
##      lhs                                  rhs                support   
## [1]  {citrus fruit, root vegetables}   => {other vegetables} 0.01037112
## [2]  {tropical fruit, root vegetables} => {other vegetables} 0.01230300
## [3]  {root vegetables, rolls/buns}     => {other vegetables} 0.01220132
## [4]  {root vegetables, yogurt}         => {other vegetables} 0.01291307
## [5]  {yogurt, whipped/sour cream}      => {other vegetables} 0.01016777
## [6]  {root vegetables, whole milk}     => {other vegetables} 0.02318251
## [7]  {onions}                          => {other vegetables} 0.01423488
## [8]  {pork, whole milk}                => {other vegetables} 0.01016777
## [9]  {whole milk, whipped/sour cream}  => {other vegetables} 0.01464159
## [10] {pip fruit, whole milk}           => {other vegetables} 0.01352313
## [11] {curd, yogurt}                    => {whole milk}       0.01006609
## [12] {root vegetables}                 => {other vegetables} 0.04738180
## [13] {other vegetables, butter}        => {whole milk}       0.01148958
## [14] {tropical fruit, root vegetables} => {whole milk}       0.01199797
## [15] {citrus fruit, whole milk}        => {other vegetables} 0.01301474
## [16] {root vegetables, yogurt}         => {whole milk}       0.01453991
## [17] {tropical fruit, yogurt}          => {other vegetables} 0.01230300
## [18] {other vegetables, domestic eggs} => {whole milk}       0.01230300
## [19] {chicken}                         => {other vegetables} 0.01789527
## [20] {whole milk, butter}              => {other vegetables} 0.01148958
## [21] {hamburger meat}                  => {other vegetables} 0.01382816
## [22] {whole milk, domestic eggs}       => {other vegetables} 0.01230300
## [23] {tropical fruit, whole milk}      => {other vegetables} 0.01708185
## [24] {whipped/sour cream}              => {other vegetables} 0.02887646
## [25] {yogurt, whipped/sour cream}      => {whole milk}       0.01087951
## [26] {root vegetables, rolls/buns}     => {whole milk}       0.01270971
## [27] {pip fruit, other vegetables}     => {whole milk}       0.01352313
## [28] {tropical fruit, yogurt}          => {whole milk}       0.01514997
## [29] {other vegetables, yogurt}        => {whole milk}       0.02226741
##      confidence coverage   lift     count
## [1]  0.5862069  0.01769192 3.029608 102  
## [2]  0.5845411  0.02104728 3.020999 121  
## [3]  0.5020921  0.02430097 2.594890 120  
## [4]  0.5000000  0.02582613 2.584078 127  
## [5]  0.4901961  0.02074225 2.533410 100  
## [6]  0.4740125  0.04890696 2.449770 228  
## [7]  0.4590164  0.03101169 2.372268 140  
## [8]  0.4587156  0.02216573 2.370714 100  
## [9]  0.4542587  0.03223183 2.347679 144  
## [10] 0.4493243  0.03009659 2.322178 133  
## [11] 0.5823529  0.01728521 2.279125  99  
## [12] 0.4347015  0.10899847 2.246605 466  
## [13] 0.5736041  0.02003050 2.244885 113  
## [14] 0.5700483  0.02104728 2.230969 118  
## [15] 0.4266667  0.03050330 2.205080 128  
## [16] 0.5629921  0.02582613 2.203354 143  
## [17] 0.4201389  0.02928317 2.171343 121  
## [18] 0.5525114  0.02226741 2.162336 121  
## [19] 0.4170616  0.04290798 2.155439 176  
## [20] 0.4169742  0.02755465 2.154987 113  
## [21] 0.4159021  0.03324860 2.149447 136  
## [22] 0.4101695  0.02999492 2.119820 121  
## [23] 0.4038462  0.04229792 2.087140 168  
## [24] 0.4028369  0.07168277 2.081924 284  
## [25] 0.5245098  0.02074225 2.052747 107  
## [26] 0.5230126  0.02430097 2.046888 125  
## [27] 0.5175097  0.02613116 2.025351 133  
## [28] 0.5173611  0.02928317 2.024770 149  
## [29] 0.5128806  0.04341637 2.007235 219

Po zastosowaniu zaostrzonych progów (lift > 2 i confidence > 0.4) pozostaje 29 reguł. Wszystkie dotyczą produktów z kategorii inne warzywa mleko, co potwierdza, że to właśnie te kategorie wykazują najsilniejsze wzajemne zależności zakupowe.

6.3 Szczegółowa interpretacja wybranych reguł

# Wyświetlamy 5 reguł z najwyższym lift z pełnymi wartościami wszystkich miar.
# Kolumna 'count' to bezwzględna liczba transakcji, w których reguła wystąpiła.
inspect(sort(reguly, by = "lift")[1:5])
##     lhs                                   rhs                support   
## [1] {citrus fruit, other vegetables}   => {root vegetables}  0.01037112
## [2] {tropical fruit, other vegetables} => {root vegetables}  0.01230300
## [3] {beef}                             => {root vegetables}  0.01738688
## [4] {citrus fruit, root vegetables}    => {other vegetables} 0.01037112
## [5] {tropical fruit, root vegetables}  => {other vegetables} 0.01230300
##     confidence coverage   lift     count
## [1] 0.3591549  0.02887646 3.295045 102  
## [2] 0.3427762  0.03589222 3.144780 121  
## [3] 0.3313953  0.05246568 3.040367 171  
## [4] 0.5862069  0.01769192 3.029608 102  
## [5] 0.5845411  0.02104728 3.020999 121

Poniżej przedstawiono szczegółową interpretację najsilniejszych odkrytych reguł:

Reguła 1: {citrus fruit, other vegetables} ⇒ {root vegetables}

Support = 0.0104 – ta kombinacja produktów pojawia się w około 1,04% wszystkich transakcji.

Confidence = 0.359 – w około 35,9% przypadków, gdy klient kupuje cytrusy oraz inne warzywa, w koszyku pojawiają się również warzywa korzeniowe.

Lift = 3.295 – produkty te są kupowane razem ponad 3,3 razy częściej, niż wynikałoby to z ich niezależnego występowania.

Reguła 2: {tropical fruit, other vegetables} ⇒ {root vegetables}

Support = 0.0123 – kombinacja ta występuje w około 1,23% wszystkich transakcji.

Confidence = 0.343 – w około 34,3% przypadków, gdy klient kupuje owoce tropikalne oraz inne warzywa, kupuje także warzywa korzeniowe.

Lift = 3.145 – oznacza to, że produkty te są kupowane razem ponad 3,1 razy częściej, niż gdyby ich zakupy były całkowicie niezależne.

Obie reguły wskazują na silną współzależność między zakupem owoców i warzyw, co może sugerować, że klienci dokonujący zakupów świeżych produktów często wybierają różne rodzaje warzyw w ramach jednej transakcji, prawdopodobnie z myślą o przygotowaniu posiłków.


7 Wnioski

Przeprowadzona analiza koszyka zakupowego z wykorzystaniem algorytmu Apriori na zbiorze danych Groceries pozwoliła na wyciągnięcie następujących wniosków:

  1. Najczęstsze produkty w transakcjach to pełne mleko, inne warzywa oraz pieczywo – produkty codziennego użytku, które naturalnie pojawiają się w wielu koszykach zakupowych.

  2. Algorytm Apriori przy progach minsupp = 0.01 i minconf = 0.25 wygenerował 170 reguł asocjacyjnych, z których 29 spełnia zaostrzone kryteria jakości (lift > 2 i confidence > 0.4).

  3. Najsilniejsze zależności (najwyższy lift) dotyczą produktów z kategorii warzyw, owoców i nabiału – co sugeruje, że pewne segmenty klientów charakteryzują się spójnymi, zdrowotnymi preferencjami żywieniowymi.

  4. Zastosowania praktyczne odkrytych reguł mogą obejmować:

    • Układanie produktów powiązanych w bliskiej odległości na półkach sklepowych (np. warzywa korzeniowe obok owoców tropikalnych)
    • Tworzenie ofert promocyjnych łączących produkty o wysokim lift
    • Personalizowane rekomendacje produktowe w aplikacjach zakupowych lub przy kasie
  5. Ograniczenia analizy: Wyniki zależą od przyjętych progów – inne wartości minsupp i minconf dałyby inny zestaw reguł. Ponadto reguły asocjacyjne wykrywają korelacje, nie przyczynowość – samo współwystępowanie produktów nie oznacza, że jeden zakup powoduje drugi.


7.1 Środowisko obliczeniowe

# Wyświetlenie informacji o wersji R i załadowanych pakietach –
# standardowy element raportów naukowych, zapewniający odtwarzalność wyników.
sessionInfo()
## R version 4.4.0 (2024-04-24 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 10 x64 (build 19045)
## 
## Matrix products: default
## 
## 
## locale:
## [1] LC_COLLATE=Polish_Poland.utf8  LC_CTYPE=Polish_Poland.utf8   
## [3] LC_MONETARY=Polish_Poland.utf8 LC_NUMERIC=C                  
## [5] LC_TIME=Polish_Poland.utf8    
## 
## time zone: Europe/Warsaw
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] arulesViz_1.5.4 arules_1.7-10   Matrix_1.7-0   
## 
## loaded via a namespace (and not attached):
##  [1] viridis_0.6.5      sass_0.4.9         utf8_1.2.4         generics_0.1.3    
##  [5] tidyr_1.3.1        lattice_0.22-6     digest_0.6.35      magrittr_2.0.3    
##  [9] evaluate_0.23      grid_4.4.0         RColorBrewer_1.1-3 iterators_1.0.14  
## [13] fastmap_1.2.0      foreach_1.5.2      jsonlite_1.8.8     ggrepel_0.9.6     
## [17] seriation_1.5.8    gridExtra_2.3      purrr_1.0.2        fansi_1.0.6       
## [21] viridisLite_0.4.2  scales_1.4.0       tweenr_2.0.3       codetools_0.2-20  
## [25] jquerylib_0.1.4    registry_0.5-1     cli_3.6.2          rlang_1.1.7       
## [29] graphlayouts_1.2.3 polyclip_1.10-7    visNetwork_2.1.4   tidygraph_1.3.1   
## [33] withr_3.0.0        cachem_1.1.0       yaml_2.3.8         tools_4.4.0       
## [37] memoise_2.0.1      dplyr_1.1.4        ggplot2_4.0.2      ca_0.71.1         
## [41] TSP_1.2.6          vctrs_0.6.5        R6_2.5.1           lifecycle_1.0.4   
## [45] htmlwidgets_1.6.4  MASS_7.3-60.2      ggraph_2.2.2       pkgconfig_2.0.3   
## [49] pillar_1.9.0       bslib_0.7.0        gtable_0.3.6       glue_1.7.0        
## [53] Rcpp_1.0.12        ggforce_0.5.0      xfun_0.52          tibble_3.2.1      
## [57] tidyselect_1.2.1   rstudioapi_0.16.0  knitr_1.50         farver_2.1.2      
## [61] htmltools_0.5.8.1  igraph_2.2.2       labeling_0.4.3     rmarkdown_2.27    
## [65] compiler_4.4.0     S7_0.2.1

Raport wygenerowany w R Markdown. Dane: zbiór Groceries, pakiet arules (Hahsler et al.).