Klienci stają się bardzo przywiązani do konkretnego krawca, gdy czują, że ten ich rozumie1 powiedział kiedyś Hubert de Givenchy – francuski projektant mody oraz założyciel znanego na całym świecie domu mody i perfum. To spostrzeżenie pozostaje aktualne również w świecie współczesnego biznesu. Hasło „poznaj i zrozum swojego klienta” znajdziemy w prawie każdym poradniku dla aspirujących biznesmenów i marketingowców.
Jednak w jaki sposób zrozumieć świat konsumenta – gdy na co dzień raczej patrzymy na niego z perspektywy wyniku finansowego firmy i bardzo daleko nam do cierpliwego przyjaciela, który może spędzić kilka godzin przy kawie, wsłuchując się w jego historię, potrzeby i oczekiwania?
Na szczęście, prowadząc sprzedaż, zyskujemy znakomite i niemal darmowe źródło informacji. Są to dane „paragonowe”, których zbieranie i tak jest naszym obowiązkiem, z uwagi na reguły podatkowe i rachunkowe. Dysponując takimi danymi, a więc datą transakcji, kwotą, wybranymi produktami oraz (przy odrobinie szczęścia) numerem karty lojalnościowej klienta – mamy praktycznie wszystko, co jest nam potrzebne do poznania zachowań konsumentów.
Trzeba jednak zauważyć, że analiza danych transakcyjnych znacząco różni się od typowej analizy statystycznej - korzystając ze zwykłych statystyk opisowych możemy tylko określić, jaka jest średnia wydana kwota, jakie jest jej odchylenie i… właściwie niewiele poza tym. Takie rozumowanie zupełnie pomija sposób podejmowania decyzji przez konsumentów. Ignoruje powiązania między wybieranymi przez nich produktami i przez to – zupełnie nie zbliża nas do ich zrozumienia.
Tu z pomocą przychodzi analiza asocjacji (association rule mining). Dzięki niej możemy skutecznie przeanalizować dane transakcyjne, szukając powtarzających się scenariuszy sprzedażowych. W ten sposób będziemy mogli odkryć reguły, które mają wpływ na zachowania konsumentów.
Dowiemy się, jakie są nasze najlepsze produkty – i z jakimi innymi często są dobierane (co otwiera nam drogę do utworzenia skutecznej strategii cross-sale). Odkryjemy jakie towary są kupowane osobno, a które zwykle występują w większych koszykach. Ponadto, w prosty sposób, z trudnego w analizie, ogromnego zbioru danych przejdziemy prostych w interpretacji informacji. Dzięki odpowiedniej kalibracji parametrów będziemy mogli zawęzić ostateczny wynik do kilkunastu najbardziej stosowalnych i użytecznych dla nas reguł.
Powyższe podejście jest typowo mikroekonomiczne – wewnętrzne decyzje przedsiębiorstwa oparte na analizie posiadanych przez nie danych. Zostało ono zaaplikowane w dotychczasowych pracach 2.
Jednak ciekawym ćwiczeniem mogłoby być bardziej ogólne spojrzenie na dane transakcyjne. Przyjrzenie się danym transakcyjnym np. z punktu widzenia dostawcy usług płatniczych mogłoby doprowadzić do ciekawych wniosków dotyczących wyboru konsumenckiego między konkretnymi sprzedawcami. Dzięki takiej analizie można odpowiedzieć na następujące pytania: Czy konsumenci częściej dokonują zakupów u jednego sprzedawcy? Czy jedne kategorie sprzedawców są bardziej popularne niż pozostałe? Jakie grupy sklepów występują razem? Ponadto, łącząc dane transakcyjne z kwotami transakcji – nawet na bardzo zagregowanym poziomie – będę w stanie określić, które asocjacje prowadzą z grup mniej dochodowych, do tych o wyższym potencjale.
Właśnie na tej problematyce skupię się w mojej pracy.
Dysponuję zanonimizowanym zbiorem danych rzeczywistych, udostępnionym w ramach platformy Kaggle przez Elo - firmę dostarczającą usługi płatnicze w Brazylii. 3 Dane zostały udostępnione w ramach otwartego konkursu analitycznego. Jego organizatorzy mają nadzieję na wykrycie wzorców zachowania klientów, w tym ich lojalności do konkretnej marki. Ma to pomóc w budowaniu skutecznych ofert promocyjnych i dopasowaniu usług do konkretnego odbiorcy.
Zbiór składa się z niemal dwóch milionów transakcji, dokonanych za pomocą kart płatniczych. Najważniejsze zmienne w zbiorze prezentują się następująco:
card_id – unikalny identyfikator karty płatniczej klienta
purchase_date – data zakupu
merchant_category_id – identyfikator kodujący kategorię sprzedawcy (zanonimizowana)
subsector_id – subsektor, do którego przydzielono kategorię sprzedawcy (zanonimizowane)
merchant_id – identyfikator sprzedawcy (zanonimizowana)
purchase_amount – znormalizowana kwota zakupu
Samych sprzedawców jest ponad 330 tysięcy (334 696). Zakwalifikowano ich w 891 kategorii (merchant_category_id). Każdy jest dodatkowo przyporządkowany do jednej z 112 586 grup kapitałowych. Można również zastosować podział sklepów na 41 zbiorczych subsektorów.
Celem analizy asocjacji (inaczej: analizy koszykowej) jest odnalezienie powiązań, występujących w zbiorze danych. W jej wyniku otrzymujemy zbiór reguł w postaci:
Jeśli A - -> to B. #Gdzie A jest poprzednikiem (ascendent), a B następnikiem (consequent).
Podstawowe parametry występujące w tym podejściu to:
wsparcie reguły (support) - miara prawdopodobieństwa wystąpienia transakcji zawierającej zarówno A, jak i B.
zaufanie (confidence) – miara prawdopodobieństwa wystąpienia w transakcji zarówno A, jak i B, podzielona przez prawdopodobieństwo wystąpienia składnika A (szansa wystąpienia koszyka w całości, w stosunku do szansy na wstąpienie poprzednika samodzielnie).
przyrost (lift) – miara prawdopodobieństwa wystąpienia w transakcji zarówno A, jak i B, podzielona przez iloczyn prawdopodobieństw wystąpienia samodzielnie składników A oraz B (szansa na wystąpienie koszyka w całości, w stosunku do iloczynu prawdopodobieństwa na wystąpienie koszyków zawierających samodzielnie A lub B). Wysokie wsparcie pokazuje, że wystąpienie kombinacji jest prawdopodobne. Zaś gdy zaufanie i przyrost są większe od jedności – koszyk ma większe szanse występowania w całości, niż jego składniki z osobna. Szukamy więc możliwie najwyższych wartości wszystkich tych miar. Tak dobrane reguły są najbardziej użyteczne w dalszym wnioskowaniu.
Do przeprowadzenia analizy asocjacji wykorzystam program RStudio ver. 1.1.456. Użyję również specjalnie dedykowanych pakietów do tego rodzaju obliczeń, a więc arules oraz arulesViz. Analizę oprę na wynikach algorytmu apriori.
Dla ułatwienia analizy przy tak dużym zbiorze danych zastosuję następujące podejście: jako transakcję przyjmę indywidualny identyfikator karty klienta, jako produkt przyjmę kategorię sprzedawcy, zamiast podziału na dane indywidualne. 4
Dzięki temu będę mogła prześledzić transakcje zawierane przez konkretnych klientów u sprzedawców z różnych kategorii. Później – wykorzystując dane dodatkowe – będę mogła określić, jakie są cechy najbardziej popularnych kategorii sprzedawców (zysk, przyporządkowanie do grup kapitałowych, itd.)
Posiadany zbiór danych poddałam również wstępnej obróbce – usunęłam kilkanaście obserwacji nieposiadających przyporządkowanej kategorii sprzedawcy. Następnie wydzieliłam identyfikator karty klienta (client) oraz kategorię sprzedawcy (shop) do odrębnego pliku. Tak przygotowany zbiór mogłam wczytać do programu jako dane transakcyjne.
Dane musza mieć odpowiednią formę, aby mogły być wczytane za pomocą pakietu arules. W wersji single, która jest odpowiednia dla mojego zbioru danych, mogą występować tylko dwie kolumny, z których pierwsza charakteryzuje identyfikator koszyka, a druga wskazuje na produkt w nim zawarty. Wczytując dane w ten sposób, program uporządkuje je według pierwszej kolumny, pobierając informacje o zbiorach elementów w każdym z koszyków.
library(arules)
## Warning: package 'arules' was built under R version 3.5.2
## Loading required package: Matrix
##
## Attaching package: 'arules'
## The following objects are masked from 'package:base':
##
## abbreviate, write
trans<-read.transactions("trans.csv", format="single", sep=";", cols=c("CLIENT","SHOP"))
Rozkład długości koszyków prezentuje się następująco:
summary(size(trans))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1.000 2.000 4.000 5.337 7.000 46.000
Klienci odwiedzali zwykle sklepy pochodzące z pięciu kategorii. Maksymalnie jeden klient zrobił zakupy w 46 kategoriach sklepów.
Na początek zastosuję algorytm apriori nie przyjmując szczegółowych założeń. Użyję domyślnych wielkości parametrów.
#domyślne: minimalne wsparcie (supp=0.1) oraz minimalne zaufanie (conf=0.8)
rules1<-apriori(trans, parameter=list(supp=0.1, conf=0.8))
## 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 FALSE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 29000
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[313 item(s), 290000 transaction(s)] done [0.31s].
## sorting and recoding items ... [11 item(s)] done [0.01s].
## creating transaction tree ... done [0.22s].
## checking subsets of size 1 2 3 done [0.00s].
## writing ... [0 rule(s)] done [0.00s].
## creating S4 object ... done [0.03s].
Jak widać takie wartości parametrów okazały się zbyt duże. Algorytm nie znalazł ani jednej reguły, która spełniała te ograniczenia. Zmniejszę więc minimalne zaufanie do 60%.
rules2<-apriori(trans, parameter=list(supp=0.1, conf=0.4))
## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen
## 0.4 0.1 1 none FALSE TRUE 5 0.1 1
## maxlen target ext
## 10 rules FALSE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 29000
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[313 item(s), 290000 transaction(s)] done [0.21s].
## sorting and recoding items ... [11 item(s)] done [0.01s].
## creating transaction tree ... done [0.30s].
## checking subsets of size 1 2 3 done [0.00s].
## writing ... [17 rule(s)] done [0.00s].
## creating S4 object ... done [0.05s].
Tym razem algorytm odnalazł już 17 reguł. Kolejną modyfikacją byłoby złagodzenie ograniczenia nałożonego na wsparcie. Dzięki temu uzyskamy 89 asocjacji.
rules3<-apriori(trans, parameter=list(supp=0.05, conf=0.4))
## Apriori
##
## Parameter specification:
## confidence minval smax arem aval originalSupport maxtime support minlen
## 0.4 0.1 1 none FALSE TRUE 5 0.05 1
## maxlen target ext
## 10 rules FALSE
##
## Algorithmic control:
## filter tree heap memopt load sort verbose
## 0.1 TRUE TRUE FALSE TRUE 2 TRUE
##
## Absolute minimum support count: 14500
##
## set item appearances ...[0 item(s)] done [0.00s].
## set transactions ...[313 item(s), 290000 transaction(s)] done [0.22s].
## sorting and recoding items ... [27 item(s)] done [0.03s].
## creating transaction tree ... done [0.32s].
## checking subsets of size 1 2 3 4 done [0.05s].
## writing ... [89 rule(s)] done [0.00s].
## creating S4 object ... done [0.05s].
Im bardziej łagodzimy ograniczenia, tym więcej reguł otrzymamy. Jednak ich jakość coraz bardziej słabnie. W tej pracy, zależy mi na uzyskaniu kompromisu pomiędzy różnorodnością i jakością wyników oraz łatwością analizy. W związku z tym, za punkt odniesienia posłużą mi reguły, zawarte w zbiorze rules2.
Zacznę od posortowania uzyskanych asocjacji ze względu na zaufanie. Dzięki temu zobaczę, które reguły są „najsilniejsze”, w porównaniu do samodzielnego występowania poprzedników.
rules.zaufanie<-sort(rules2, by="confidence", decreasing=TRUE)
inspect(rules.zaufanie) #wyświetlanie wyników
## lhs rhs support confidence lift count
## [1] {80} => {278} 0.1574862 0.5317692 1.737906 45671
## [2] {80} => {705} 0.1536345 0.5187635 1.335346 44554
## [3] {278} => {80} 0.1574862 0.5146898 1.737906 45671
## [4] {278} => {705} 0.1558586 0.5093706 1.311168 45199
## [5] {278} => {307} 0.1549069 0.5062602 1.439353 44923
## [6] {367} => {705} 0.1487897 0.5000985 1.287301 43149
## [7] {307} => {705} 0.1730931 0.4921226 1.266770 50197
## [8] {80} => {307} 0.1425724 0.4814112 1.368705 41346
## [9] {705} => {307} 0.1730931 0.4455579 1.266770 50197
## [10] {307} => {278} 0.1549069 0.4404173 1.439353 44923
## [11] {367} => {307} 0.1292414 0.4343946 1.235031 37480
## [12] {367} => {278} 0.1251345 0.4205909 1.374557 36289
## [13] {80} => {367} 0.1231897 0.4159632 1.398098 35725
## [14] {367} => {80} 0.1231897 0.4140541 1.398098 35725
## [15] {278} => {367} 0.1251345 0.4089593 1.374557 36289
## [16] {307} => {80} 0.1425724 0.4053490 1.368705 41346
## [17] {705} => {278} 0.1558586 0.4011947 1.311168 45199
Pierwsza reguła mówi nam, że jeśli klient zrobił zakupy w sklepie z kategorii „80”, to zrobi je również w sklepie z kategorii „278”. Wsparcie tej asocjacji pokazuje, że prawie 16% wszystkich klientów dokonuje zakupów zarówno w jednej, jak i w drugiej kategorii sklepów (około 45 tysięcy transakcji). Warto zauważyć, że duże zaufanie ma również reguła odwrotna. Oznacza to, że podobna liczba klientów robi zakupy w sklepach „80” lub w „278” (podobna wysokość prawdopodobieństwa występującego w mianowniku miar). Zaufanie w granicach 50% pokazuje, że co drugi klient, który zrobił zakupy w jednym z tych sklepów, kupi coś również w sklepie z drugiej grupy.
Analogicznie, widać również, że występuje wyraźne powiązanie między grupami „80” i „705” oraz „278” i „705”. Jednak w tych przypadkach kategoria „705” zdecydowanie częściej występuje jako następnik. Może to oznaczać, że klienci częściej robią zakupy w sklepach z kategorii „278” oraz „80”, ale jeśli już coś tam kupią, to jest bardzo prawdopodobne, że zrobią zakupy również w sklepie z grupy „705”.
Z analizy powyższych 17 reguł można również wywnioskować, że grupy sklepów „80”, „278”, „705”, „307” oraz „367” są najbardziej popularne wśród klientów i bardzo często występują razem (choć w różnych kombinacjach). Tę obserwację potwierdza również wartość przyrostu, która dla każdej z reguł jest wyższa od jedności. Oznacza to, że prawdopodobieństwo zakupu w obu sklepach z tych koszyków jest wyższe niż gdyby występowały osobno (były niezależne).
Ze względu na nałożone ograniczenia (jak się okazuje, dość restrykcyjne dla tego zbioru danych), uzyskane reguły mają postać dwuskładnikową: występuje tylko jeden poprzednik i jeden następnik. Jednak jako ciekawostkę pokażę pięć ostatnich reguł uzyskanych w zestawie rules3.
inspect(tail(rules3))
## lhs rhs support confidence lift count
## [1] {278,705} => {307} 0.09085517 0.5829333 1.657343 26348
## [2] {307,705} => {278} 0.09085517 0.5248919 1.715430 26348
## [3] {278,307,80} => {705} 0.05840690 0.6438101 1.657228 16938
## [4] {278,705,80} => {307} 0.05840690 0.6330306 1.799775 16938
## [5] {307,705,80} => {278} 0.05840690 0.6798860 2.221975 16938
## [6] {278,307,705} => {80} 0.05840690 0.6428571 2.170677 16938
W tych regułach widać poprzedniki składające się dwóch lub trzech elementów. Piątą regułę z tego zestawu można zinterpretować następująco: jeśli klient zrobił zakupy w sklepach „278”, „307” oraz „705”, to istnieje duża szansa, że zrobi zakupy również w sklepie z kategorii „80”. Wysokość prawdopodobieństwa można odczytać ze współczynnika zaufania – takie zachowanie zaobserwowano u 64% klientów, którzy kupili już coś w sklepach zawartych w poprzedniku. Wsparcie tej reguły mówi, że 5,8% wszystkich klientów kupiło coś w sklepach ze wszystkich tych grup. Warto również zauważyć, że przyrost dla tej zasady wynosi aż 2,17. Oznacza to, że szansa na wspólne wystąpienie całego koszyka jest dwa razy większa, niż wystąpienie tylko kombinacji zawartej w poprzedniku.
Co ciekawe, pomimo znacznego złagodzenia ograniczeń przy tworzeniu zbioru rules3, nadal obserwujemy asocjacje składające się tylko z grup sklepów, które były już widoczne w zbiorze rules2. Może to oznaczać, że pozostałe 886 kategorii sprzedawców cieszy się dużo mniejszą popularnością. Nie ma również między nimi wyraźnych połączeń, o prawdopodobieństwie wystąpienia wyższym niż 5%.
Pomimo iż analiza tabeli zawierającej 17 reguł była dość prosta, warto zastanowić się nad dostępnymi metodami wizualizacyjnymi. Mogłyby one okazać się przydatne, szczególnie w przypadku występowania wielu asocjacji. Przedstawienie ich na wykresie, mogłoby pozwolić na łatwiejszą analizę i porównanie występujących reguł między sobą.
Poniższy wykres pokazuje grupy sklepów, które są najczęściej wybierane przez konsumentów.
library(arulesViz)
## Warning: package 'arulesViz' was built under R version 3.5.2
## Loading required package: grid
itemFrequencyPlot(trans, topN=10, type="relative", main="Najczęściej występujące kategorie sklepów", ylab="Relatywna częstość występowania")
Na wykresie widać potwierdzenie wcześniejszych spostrzeżeń – pięć pierwszych grup występuje zdecydowanie częściej niż inne. Wpływa to na później odkrywane reguły – częściej występujące kategorie mają większe szanse na wysoki wskaźnik wsparcia. Warto również zwrócić uwagę na to, że kategoria „80”, która zawierała się w najsilniejszych regułach odkrytych w zbiorze, nie jest najczęściej występującą grupą sklepów.
Poniższy wykres w kształcie grafu pokazuje wykryte reguły jako zależności między kategoriami sklepów. Każda strzałka reprezentuje połączenie między kategoriami. Występująca na jej środku kulka obrazuje wartości statystyk wsparcia i przyrostu, według zasady: im większa kulka – tym wyższe wsparcie, im bardziej intensywny kolor – tym wyższy przyrost.
set.seed(240) #metoda bazuje na losowaniu punktów pierwotnych, więc dla powtarzalności wyniku wyznaczam używany zestaw liczb pseudolosowych
plot(rules2, method="graph", measure="support", shading="lift", main="Graf dla 17 reguł")
Na tym wykresie wyraźnie widać, że odkryte reguły dotyczą tylko pięciu grup sprzedawców, a najsilniejsze powiązania są pomiędzy grupami „80” i „278”.
plot(rules2, method="grouped", main="Grupowana macierz dla 17 reguł")
Powyższy wykres pokazuje liczbę i jakość asocjacji pomiędzy kategoriami. W górnej części wymienione są poprzedniki (LHS). Pionowy ślad kolorystycznie kodowanych kółek pokazuje jakość i kierunek zależności – na każdej poziomej linii znajduje się inny następnik (RHS), a wielkość i intensywność koloru wskazuje wysokość wsparcia i przyrostu. Oznaczenie „101” można odczytać jako: reguły zawierające dokładnie jeden poprzednik i jeden następnik. Taka grupowana macierz zależności jest dość przejrzysta i pozwala prześledzić, jak często dany element występuje w asocjacjach.
W pakiecie arulesViz znalazło się również kilka interesujących metod, pozwalających na interaktywną prezentację wyników grupowania. Bazują one na technologii wykorzystywanej w pakietach plotly oraz shiny. Z ich pomocą można dynamicznie dostosowywać prezentowane wyniki, a dzięki zastosowaniu rozwiązań html, css i bootstrap - obraz dynamicznie dostosuje się do okna przeglądarki. Dzięki publikacji tej pracy w formie dokumentu html mogę odpowiednio zaprezentować ich potencjał.
plotly_arules(rules2) #wykres dynamiczny
## Warning: 'plotly_arules' is deprecated.
## Use 'plot' instead.
## See help("Deprecated")
Powyższy wykres pokazuje znane nam już 17 reguł, zawartych w zbiorze rules2. Są one tu przedstawione ponownie, jako kolorystycznie kodowane kropki, ze względu na przyrost. Rozmieszczenie na polu wykresu pokazuje zależność między wsparciem i zaufaniem reguł. Dodatkowym ułatwieniem jest dynamiczne wyświetlanie podpisów. Po najechaniu myszą na dany punkt wyświetla się cała informacja na temat wskazanej reguły – poprzednik i następnik, a także miary określające jej jakość.
Podobne, interaktywne rezultaty, otrzymamy przy użyciu podstawowej komendy plot w pakiecie arulesViz. Wykres zmieni się na dynamiczny, jeśli do zwykłej składni dodamy element engine=”html”
. Poniżej znajduje się przykład znanego już grafu, tym razem z szerszym zbiorem reguł, z zastosowaniem tej modyfikacji. Teraz, za pomocą rozwijanego menu, można zaznaczyć interesującą nas kategorię sklepu, która ma występować w regule. Można również szukać asocjacji po ich identyfikatorze lub po prostu najechać na jedno z połączeń, by okryć jego własności. Jest to szczególnie ważne, gdyż zwykły graf dla 89 asocjacji w zbiorze rules3 byłby zupełnie nieczytelny.
set.seed(240)
plot(rules3, method="graph", measure="support", shading="lift", engine="html", main="Dynamiczny graf dla 17 reguł")
## Warning: Unknown control parameters: main
## Available control parameters (with default values):
## itemCol = #CBD2FC
## nodeCol = c("#EE0000", "#EE0303", "#EE0606", "#EE0909", "#EE0C0C", "#EE0F0F", "#EE1212", "#EE1515", "#EE1818", "#EE1B1B", "#EE1E1E", "#EE2222", "#EE2525", "#EE2828", "#EE2B2B", "#EE2E2E", "#EE3131", "#EE3434", "#EE3737", "#EE3A3A", "#EE3D3D", "#EE4040", "#EE4444", "#EE4747", "#EE4A4A", "#EE4D4D", "#EE5050", "#EE5353", "#EE5656", "#EE5959", "#EE5C5C", "#EE5F5F", "#EE6262", "#EE6666", "#EE6969", "#EE6C6C", "#EE6F6F", "#EE7272", "#EE7575", "#EE7878", "#EE7B7B", "#EE7E7E", "#EE8181", "#EE8484", "#EE8888", "#EE8B8B", "#EE8E8E", "#EE9191", "#EE9494", "#EE9797", "#EE9999", "#EE9B9B", "#EE9D9D", "#EE9F9F", "#EEA0A0", "#EEA2A2", "#EEA4A4", "#EEA5A5", "#EEA7A7", "#EEA9A9", "#EEABAB", "#EEACAC", "#EEAEAE", "#EEB0B0", "#EEB1B1", "#EEB3B3", "#EEB5B5", "#EEB7B7", "#EEB8B8", "#EEBABA", "#EEBCBC", "#EEBDBD", "#EEBFBF", "#EEC1C1", "#EEC3C3", "#EEC4C4", "#EEC6C6", "#EEC8C8", "#EEC9C9", "#EECBCB", "#EECDCD", "#EECFCF", "#EED0D0", "#EED2D2", "#EED4D4", "#EED5D5", "#EED7D7", "#EED9D9", "#EEDBDB", "#EEDCDC", "#EEDEDE", "#EEE0E0", "#EEE1E1", "#EEE3E3", "#EEE5E5", "#EEE7E7", "#EEE8E8", "#EEEAEA", "#EEECEC", "#EEEEEE")
## precision = 3
## igraphLayout = layout_nicely
## interactive = TRUE
## engine = visNetwork
## max = 100
## selection_menu = TRUE
## degree_highlight = 1
## verbose = FALSE
Kolejną opcją jest dynamiczny odpowiednik pokazywanej wcześniej tabeli. Dzięki przyjaznej nakładce na interface, można w łatwy sposób filtrować otrzymane wyniki i sterować wyświetlanymi rezultatami. Jest to również możliwe dla osób, które nie znają języka programowania R. Takie rozwiązanie znacznie upraszcza analizę, gdy ze zbioru wielu asocjacji, chcemy wybrać tylko niektóre. Jest też bardzo cenne w sytuacji, gdy wyniki analizy mają być zaprezentowane osobom o mniejszym zapleczu programistycznym.
inspectDT(rules3) #tabela dynamiczna
Zdecydowałam się zaprezentować powyższą tabelę dla zestawu rules3. Ze względu na mnogość zawartych w nim reguł, jego analiza w tradycyjnej tabeli była utrudniona. Po zastosowaniu komendy inspectDT mogę zawęzić rezultaty tylko do tych, które mogą być dla mnie w danym momencie interesujące (np. zawierające konkretną kategorię sprzedawcy w poprzedniku oraz mające odpowiednio wysokie wsparcie).
Ostatnią i najbardziej zaawansowaną metodą jest połączenie dwóch powyższych – dynamicznie tworzona tabela z filtrowaniem oraz dopasowany do niej moduł generujący wykresy. Wywołanie komendy ruleExplorer wywołuje nowe okno aplikacji typu Shiny. Można w nim dostosowywać otrzymywane rezultaty i elastycznie modyfikować postać wizualizacji.
Niestety, nawet dla zbioru 17 reguł aplikacja zajmuje 2,14GB pamięci. Rozmiar ten sprawia, że nie mogę załączyć jej do publikowanego pliku. Z tego powodu poniżej zaprezentowałam przykładowe okna tej aplikacji – tabelę i odpowiadający jej wykres macierzowy, po zastosowaniu kilku ograniczeń.
#ruleExplorer(rules2, parameter = NULL)
Chciałabym wrócić jeszcze na chwilę do problemu instytucji publikującej dane – firmy Elo, obsługującej większość płatności karcianych w Brazylii. W ramach konkursu, analitycy, bazując na odkrytych informacjach, mają pomóc w budowie nowych cenników i ofert dla obsługiwanych podmiotów.
Wcześniej pokazałam, że najsilniejsze asocjacje zachodzą pomiędzy pięcioma grupami sprzedawców. Warto by było znaleźć tę, której średnia wysokość sprzedaży była najwyższa (miejsce na potencjalnie najwyższe dochody z prowizji).
#wczytuje transakcyjny zbiór danych + kolumna "kwota zakupu"
priced <- read.csv(file="transprice.csv", header=TRUE, sep=";", dec=".")
library(plyr)
#kategorie sklepów z największą liczbą powiązań
wybrane= c("80", "278", "705", "307", "367")
priced_red<-priced[priced$SHOP %in% wybrane,]
aggregate(PRICE~SHOP, data = priced_red, mean)
## SHOP PRICE
## 1 80 -0.6929820
## 2 278 -0.6314548
## 3 307 -0.6162038
## 4 367 -0.6563032
## 5 705 -0.6317634
Wartości transakcji w pierwotnym zbiorze danych miały postać wystandaryzowaną. Widać więc, że we wszystkich grupach sprzedawców klienci dokonują zakupów za niewielkie kwoty. Pomimo iż najwyższą średnią wartość zakupu uzyskaliśmy dla kategorii „307”, jest ona tylko nieznacznie wyższa od pozostałych.
Oznacza to, że uzyskane asocjacje dotyczą co prawda popularnych grup sklepów, ale średnio zawarte w nich transakcje są zazwyczaj drobne. Użyteczne mogłoby się okazać odnalezienie reguł prowadzących od drobnych zakupów do sklepów ze średnio wyższymi transakcjami. Poszukam więc innych reguł, które jako poprzednik zawierają grupę „307” (wybrana ze względu na najwyższą średnią wartość transakcji spośród pięciu popularnych kategorii).
rules.307<-apriori(data=trans, parameter=list(supp=0.05,conf = 0.1), appearance=list(default="rhs", lhs="307"), control=list(verbose=F))
inspect(rules.307[11:17,]) #ukrywam pierwsze 10 reguł - zawierały puste poprzedniki
## lhs rhs support confidence lift count
## [1] {307} => {690} 0.05119655 0.1455574 1.106900 14847
## [2] {307} => {884} 0.05509655 0.1566455 1.157057 15978
## [3] {307} => {560} 0.08071379 0.2294781 1.446867 23407
## [4] {307} => {683} 0.08263448 0.2349389 1.427422 23964
## [5] {307} => {367} 0.12924138 0.3674474 1.235031 37480
## [6] {307} => {80} 0.14257241 0.4053490 1.368705 41346
## [7] {307} => {278} 0.15490690 0.4404173 1.439353 44923
Po odpowiednim rozluźnieniu ograniczeń na parametry, udało się odkryć kilka dodatkowych grup sklepów, połączonych z kategorią „307”. Ponownie sprawdzę średnią wartość zawieranych w nich transakcji, aby wykryć bardziej dochodowe połącznia.
#nowe kategorie
wybrane2= c("690", "884", "560", "683")
priced_red2<-priced[priced$SHOP %in% wybrane2,]
aggregate(PRICE~SHOP, data = priced_red2, mean)
## SHOP PRICE
## 1 560 -0.7009575
## 2 683 -0.6762185
## 3 690 -0.2996202
## 4 884 -0.5014089
Okazało się, że transakcje zawarte w sklepach z grup „690” oraz „884” mają średnio wyższe wartości (w porównaniu do pięciu popularnych kategorii). Najbardziej obiecująca jest grupa „690”. Średnia kwota zakupów jest tam nadal niska, ale nadal stanowi znaczą poprawę w stosunku do poprzednio odkrytych zależności.
Warto zauważyć, że reguła łącząca sklepy z grup „307” i „690” jest wspierana przez prawie 15 tysięcy klientów (5,1% całej grupy). Jeśli celem firmy Elo jest maksymalizacja zysków z prowizji – być może dobrym pomysłem byłoby zachęcenie większej liczby klientów do zakupów zarówno w jednej, jak i w drugiej grupie sklepów.
Możliwym rozwiązaniem byłoby wprowadzenie karty lojalnościowej połączonej z numerem karty płatniczej. Zbierane na niej punkty można by było wymieniać np. na drobne rabaty lub podarunki. Warunkiem uzyskania nagrody byłoby zrobienie zakupów w obu grupach sklepów. Takie działanie w przyszłości podniosłoby wsparcie reguły, jak również wzrost dochodów z prowizji, poprzez zachęcenie klientów do zakupów w bardziej dochodowych sklepach.
Innym sposobem na zwiększenie dochodów z prowizji poprzez wykorzystanie kart lojalnościowych mogłoby być wprowadzenie systemu punktów, który zmotywowałby klientów do wydawania wyższych kwot w najbardziej popularnych grupach sklepów. Wtedy warunkiem otrzymania nagrody mogłoby być zrobienie zakupów np. w sklepach z dwóch z pięciu popularnych kategorii za minimalną kwotę X.
Jak widać nawet analiza tak szczątkowych danych jak kategoria sklepu i wystandaryzowana wysokość transakcji, może doprowadzić do stworzenia potencjalnie skutecznych strategii biznesowych. Ich zastosowanie ma duże szanse powodzenia, gdyż ich podstawy znajdują się w realnych danych, pochodzących od klientów.
Przy wykorzystaniu odpowiednich narzędzi, analiza asocjacji może dostarczyć nam wielu interesujących informacji na temat zachowań klientów. Jest to metoda, która pozwala na wydobycie użytecznych wniosków ze zbioru trudnych w analizie surowych danych transakcyjnych.
Jej dodatkową zaletą jest wykorzystywanie statystyk opartych na klasycznym rachunku prawdopodobieństwa. Dzięki temu, ich zrozumienie jest możliwe nawet dla początkującego entuzjasty data science.
Jest to również jedna z metod dobrze radzących sobie z problemem big data shrinkage 5 bez potrzeby dodatkowej ingerencji badacza. Oznacza to w przybliżeniu tyle, że po zaimportowaniu pliku w wymagany w pakiecie sposób, algorytm skutecznie sprowadza ogrom pierwotnego zbioru danych do użytecznych i łatwych w interpretacji wyników. W większości przypadków, gdy tabela zostanie już zredukowana do postaci: id koszyka + zawartość, nie potrzeba dodatkowo jej ograniczać (np. poprzez sampling czy inny sposób wstępnej obróbki danych pierwotnych).
Odkryte asocjacje można sortować pod względem ich jakości i użyteczności. Po zakończeniu podstawowej analizy, gdy chcemy przyjrzeć się bliżej konkretnemu produktowi w koszyku (tutaj: grupie sklepów) możemy odnaleźć dodatkowe reguły. Kluczem jest odpowiednie dobranie ograniczających parametrów oraz ewentualne zawężenie po wyszukiwanych kategoriach.
Pogłębioną analizę ułatwiają interaktywne metody prezentacji wyników. Dzięki nim, bez ingerencji w kod źródłowy, możemy łatwo odnaleźć interesujące nas asocjacje. Ta cecha jest istotna, jeżeli chcemy ograniczyć czas poświęcony na badanie przez zaawansowanego analityka i przekazać pierwsze wyniki pracy do dalszej obróbki przez kogoś z mniejszym doświadczeniem.
Połączenie odkrytych powiązań z danymi finansowymi może nas zainspirować do budowy nowych strategii biznesowych, które będą oparte o rzeczywiste informacje od klientów. Mają one wtedy większe szanse na zaprocentowanie, gdyż nie tyle narzucamy coś konsumentowi, co wychodzimy naprzeciw jego potrzebom i szanujemy jego naturalne nawyki. Pokazujemy, że dobrze go znamy i oferujemy plan, niewymagający dużej modyfikacji jego zachowań, który przynosi korzyści obu stronom.
Oryginalnie: Clients become very attached to the fitter who they feel understands them. Hubert de Givenchy↩
APTE, Chidanand, et al. Business applications of data mining. Communications of the ACM, 2002, 45.8: 49-53. WU, Ruey-Chyi; CHEN, Ruey-Shun; CHEN, C.-CCJY. Data mining application in customer relationship management of credit card business. Computer Software and Applications Conference, 2005. COMPSAC 2005. 29th Annual International. IEEE, 2005. p. 39-40. WANG, Yi-Fan, et al. A personalized recommender system for the cosmetic business. Expert Systems with Applications, 2004, 26.3: 427-434.↩
https://www.kaggle.com/c/elo-merchant-category-recommendation/data↩
Szukanie reguł na poziomie identyfikatora sklepu mogłoby doprowadzić do uzyskania reguł o bardzo niskim prawdopodobieństwie wystąpienia. Każdy analizowany sklep w Brazylii ma swój indywidualny klucz. Reguły byłyby więc mocno ograniczone lokalizacyjnie. Sklep spożywczy w Porto nie mógłby być połączony z innym sklepem spożywczym, zlokalizowanym w Rio de Janeiro (ze względu dzielące ich 1570km). W związku z tym, bardziej efektywnym podejściem będzie analiza zakupów dla kategorii sklepów, np. sklepy spożywcze + sklepy przemysłowe. Takie reguły będą łatwiejsze do odnalezienia i przeanalizowania, szczególnie w celu zaprezentowania możliwości pakietu arules i wyjaśnieniu podstawowych zasad przeprowadzania analizy asocjacji. Jest to oczywiście tylko jedna z możliwych opcji: można by było również podzielić zbiór danych na mniejsze obszary lokalizacyjne i wtedy szukać powiązań między konkretnymi sklepami.↩
FAN, Jianqing; HAN, Fang; LIU, Han. Challenges of big data analysis. National science review, 2014, 1.2: 293-314.↩