← Powrót do Portfolio
Analiza retencji i segmentacji klientów – Online Retail II — widok główny projektu

Analiza retencji i segmentacji klientów – Online Retail II

SQLPostgreSQLpgAdminCTEFunkcje oknaRFMAnaliza kohortowa

Kompleksowe studium przypadku dotyczące zachowań klientów, ich wartości i utrzymania w czasie, zrealizowane w PostgreSQL.

Projekt prowadzi od kontroli i przygotowania danych źródłowych do analizy powtarzalności zakupów, segmentacji RFM, retencji kohortowej, cyklu życia klientów, reaktywacji, anulowań oraz sezonowości. Głównym obszarem analizy jest klient: jego aktywność, częstotliwość zakupów, wartość i zachowanie w czasie.

1Problem i cel projektu

Sama wartość sprzedaży nie pokazuje, jak zachowują się klienci ani które grupy mają największe znaczenie dla biznesu.

Celem projektu było odpowiedzenie m.in. na pytania:

  • ilu klientów dokonuje kolejnych zakupów,
  • jak szybko wracają po poprzednim zamówieniu,
  • jak koncentruje się wartość zakupów,
  • które segmenty RFM są najliczniejsze i generują najwyższą wartość dodatnich zakupów,
  • jak zmienia się retencja kolejnych kohort,
  • którzy klienci są aktywni, zagrożeni utratą lub nieaktywni,
  • jak często klienci wracają po długiej przerwie,
  • jak anulowania wpływają na ocenę wartości klienta,
  • czy w danych występują powtarzalne wzorce sezonowe.

2Dane

Zbiór Online Retail II zawiera rzeczywiste transakcje brytyjskiego sklepu internetowego sprzedającego głównie artykuły upominkowe. Wielu klientów firmy to hurtownicy.

Źródło danych: Online Retail II – UCI Machine Learning Repository

Dane obejmują:

ElementWartość
Liczba rekordów źródłowych1 067 371
Okres01.12.2009–09.12.2011
Liczba źródeł2
Rekordpojedyncza pozycja faktury
Główne polafaktura, produkt, ilość, data, cena, klient, kraj

Jeden rekord nie oznacza całego zamówienia, dlatego przed analizą klienta dane zostały zagregowane z poziomu pozycji faktury do poziomu zamówienia.

3Kontrola jakości i przygotowanie danych

Przed rozpoczęciem analizy przeprowadziłam kontrolę kompletności, duplikatów, zakresów dat i nietypowych operacji.

Najważniejsze problemy jakości danych:

ProblemSkala
Brak customer_id243 007 rekordów
Udział rekordów bez customer_id22,77%
Nakładające się rekordy między źródłami22 523
Dokładne duplikaty usunięte po połączeniu źródeł11 812
Rekordy bez opisu produktu4 382

Brak customer_id uniemożliwia wykorzystanie tych rekordów w analizie RFM, kohort, retencji i historii konkretnego klienta.

Dwa źródła nakładały się w okresie od 1 do 9 grudnia 2010 r. Do usunięcia powtórzeń wynikających z nakładania wykorzystałam EXCEPT ALL, zachowując jednocześnie dane źródłowe w warstwie raw.

Następnie przygotowałam warstwę staging, w której rekordy zostały sklasyfikowane jako:

  • sale,
  • cancellation,
  • stock_adjustment,
  • zero_price,
  • bad_debt_adjustment,
  • manual_correction.

4Warstwa analityczna

Do analiz klientów wykorzystałam wyłącznie dodatnie, płatne transakcje posiadające identyfikator klienta.

Po zagregowaniu pozycji faktur do poziomu zamówień otrzymałam:

WskaźnikWynik
Zamówienia klientów36 969
Zidentyfikowani klienci5 878
Wartość dodatnich zakupów klientów17 374 804,25
Zamówienia o wartości ≤ 00

Widok zamówień klientów stał się podstawą dalszych analiz zachowań, wartości klienta, RFM, kohort, retencji i cyklu życia.

5Zachowania klientów

Analiza pokazała, że większość klientów w dostępnej historii dokonała więcej niż jednego zakupu.

Typ klientaLiczba klientówUdział klientówLiczba zamówień
Powracający4 25572,39%35 346
Jednorazowi1 62327,61%1 623

Klienci powracający odpowiadali za około 95,61% wszystkich zamówień.

Średni czas pomiędzy pierwszym i drugim zaobserwowanym zamówieniem wyniósł 97,53 dnia, natomiast średni odstęp pomiędzy wszystkimi kolejnymi zamówieniami wyniósł 51,69 dnia.

6Wartość klientów i koncentracja

Dla każdego klienta obliczyłam liczbę zamówień, łączną wartość dodatnich zakupów oraz średnią wartość zamówienia.

Analiza koncentracji wykazała, że:

1 354 klientów, czyli 23,04% bazy, odpowiadało za 80,01% wartości dodatnich zakupów.

Oznacza to silną koncentrację wartości wśród części klientów, choć wynik nie odpowiada dokładnie klasycznej relacji 80/20.

7Segmentacja RFM

Dla każdego klienta obliczyłam:

  • Recency – liczbę dni od ostatniego zamówienia,
  • Frequency – liczbę zamówień,
  • Monetary – łączną wartość dodatnich zakupów.

Wstępnie przetestowałam NTILE(4), jednak metoda dzieliła klientów o identycznej liczbie zamówień pomiędzy różne grupy. W finalnym rozwiązaniu zastosowałam PERCENT_RANK(), dzięki czemu klienci o tych samych wartościach metryk otrzymywali ten sam percentyl.

with rfm_percentiles_CTE as
(
    select
        *
        ,percent_rank() over (order by recency_days desc) as r_percentile
        ,percent_rank() over (order by frequency) as f_percentile
        ,percent_rank() over (order by monetary) as m_percentile
    from analytics.customer_rfm
)
select
    *
    ,case
        when frequency = 1 and r_percentile >= 0.75 then 'new_customer'
        when r_percentile >= 0.75 and f_percentile >= 0.75 and m_percentile >= 0.75 then 'champion'
        when r_percentile >= 0.50 and f_percentile >= 0.50 then 'loyal_customer'
        when r_percentile >= 0.50 and f_percentile < 0.50 then 'potential_loyalist'
        when r_percentile < 0.50 and (f_percentile >= 0.50 or m_percentile >= 0.75) then 'at_risk'
        else 'hibernating'
    end as rfm_segment
from rfm_percentiles_CTE;

Wyniki segmentacji

SegmentUdział klientówŚrednia liczba zamówieńUdział w wartości dodatnich zakupów
Champion10,39%25,4852,49%
Loyal customer21,78%8,1723,12%
At risk13,63%6,9213,60%
Hibernating36,54%1,575,59%
Potential loyalist16,01%2,065,02%
New customer*1,65%1,000,18%

* new_customer oznacza klienta z jednym niedawnym zamówieniem w dostępnej historii danych, a nie potwierdzonego nowego klienta firmy.

Segment champion stanowił tylko 10,39% klientów, ale odpowiadał za ponad połowę wartości dodatnich zakupów.

8Analiza kohortowa i retencja

Klientów przypisałam do kohort na podstawie miesiąca pierwszego zamówienia zaobserwowanego w dostępnych danych.

Retencję obliczyłam jako udział klientów aktywnych w danym miesiącu względem początkowej liczebności kohorty.

Wybrane wyniki

WskaźnikWynik
Średnia retencja po 1 miesiącu21,17%
Ważona retencja po 1 miesiącu23,15%
Najwyższa retencja po 1 miesiącu35,29%
Najniższa retencja po 1 miesiącu9,21%

Retencja nie spadała liniowo – klient mógł nie kupować w jednym miesiącu i wrócić w kolejnym.

W analizie rozróżniłam również:

  • NULL – brak wystarczającego okresu obserwacji,
  • 0% – okres był obserwowany, ale żaden klient nie wrócił.

Ważona retencja została wykorzystana jako bardziej reprezentatywna dla ogólnego zachowania klientów, ponieważ uwzględnia różną wielkość kohort.

9Cykl życia klienta i reaktywacja

Progi aktywności nie zostały przyjęte arbitralnie. Wyznaczyłam je na podstawie percentyli rzeczywistych odstępów pomiędzy zakupami.

Przyjęte statusy:

StatusWarunekUdział klientów
Activerecency_days <= 7043,55%
At risk71–147 dni12,15%
Inactive>147 dni44,30%

Za reaktywację uznałam zakup wykonany po przerwie dłuższej niż 147 dni.

Co najmniej jedną reaktywację miało 2 174 klientów, czyli 36,99% całej bazy.

Szczególnie interesująca okazała się grupa at_risk – 53,08% klientów z tego segmentu było już wcześniej reaktywowanych, co wskazuje na powtarzający się wzorzec długich przerw w zakupach.

10Anulowania i ich wpływ na wartość klienta

Anulowania zostały przeanalizowane jako osobny obszar, zamiast łączyć je bezpośrednio z wcześniejszymi analizami dodatnich zachowań zakupowych.

WskaźnikWynik
Anulowane faktury8 291
Klienci z anulowaniami2 572
Wartość anulowań1 462 424,18
Anulowania / wartość sprzedaży7,14%
Udział wartości anulowań z customer_id74,18%

Analiza ujawniła przypadki, w których ranking oparty wyłącznie na dodatnich zakupach był mylący.

Przykład wpływu anulowań na ranking

KlientWartość dodatnich zakupówAnulowaniaObserwowana wartość po anulowaniachRanking bruttoRanking po anulowaniach
16446168 472,50168 478,60-6,1085 735
1234677 556,4677 608,20-51,74195 736
16029117 763,6228 058,1589 705,471215
1293192 347,3421 047,6771 299,671619

Przypadek klienta 16446 pokazuje, że bardzo wysoka wartość dodatnich zakupów może zostać praktycznie całkowicie zneutralizowana przez anulowania.

11Sezonowość

Do porównania sezonowości wykorzystałam te same miesiące 2010 i 2011 r., wykluczając niepełny grudzień 2011.

Najbardziej powtarzalny wzorzec wystąpił jesienią.

MiesiącZamówienia 2010Zamówienia 2011Wartość 2010Wartość 2011
Wrzesień1 6891 755829 013,95950 690,20
Październik2 1331 9291 033 112,011 035 642,45
Listopad2 5872 6571 166 460,021 156 205,61

W obu latach aktywność rosła od września, a listopad był miesiącem o najwyższej liczbie zamówień i najwyższej wartości zakupów.

Ze względu na dostępność tylko dwóch porównywalnych cykli rocznych wynik należy traktować jako sygnał sezonowości, a nie jej jednoznaczne potwierdzenie.

12Najważniejsze wnioski biznesowe

Analiza wskazuje, że:

  • działalność w dużym stopniu opiera się na klientach dokonujących kolejnych zakupów,
  • wartość zakupów jest silnie skoncentrowana wśród części klientów,
  • segment champion ma bardzo duży udział w wartości dodatnich zakupów mimo niewielkiego udziału w bazie,
  • istotna część klientów przechodzi w długie okresy nieaktywności,
  • grupa at_risk często zawiera klientów, którzy już wcześniej wracali po długich przerwach,
  • anulowania mogą istotnie zmienić ocenę wartości pojedynczych klientów,
  • jesienią widoczny jest powtarzalny wzrost aktywności zakupowej.

13Ograniczenia analizy

Brak customer_id

22,77% rekordów nie posiada identyfikatora klienta. Rekordy te nie mogły zostać wykorzystane w analizie RFM, kohort, retencji ani historii pojedynczego klienta.

Początek historii klienta

Dane rozpoczynają się w grudniu 2009 r., dlatego pierwszy zakup klienta widoczny w zbiorze nie musi być jego pierwszym zakupem w firmie.

W związku z tym:

  • first_purchase_date należy interpretować jako pierwszą zaobserwowaną datę zakupu,
  • kohorty są kohortami pierwszego zaobserwowanego zakupu, a nie potwierdzonymi kohortami pozyskania,
  • RFM, lifecycle i częstotliwość opisują zachowanie klienta w dostępnej historii, a nie jego pełną relację z firmą.

Anulowania

Segmentacja RFM została obliczona na podstawie dodatnich zamówień. Opisuje więc aktywność, częstotliwość i wartość dodatnich zakupów, a nie pełną wartość netto klienta po anulowaniach.

Niepełny ostatni miesiąc

Dane kończą się 9 grudnia 2011 r., dlatego miesiąc ten nie został wykorzystany do porównań sezonowych z pełnymi miesiącami.

14Dalszy rozwój projektu

W środowisku produkcyjnym analizę warto byłoby rozszerzyć o:

  • pełniejszą historię transakcji sprzed grudnia 2009,
  • rzeczywistą datę pozyskania lub rejestracji klienta,
  • uzupełnienie brakujących customer_id z systemu źródłowego,
  • jednoznaczne powiązanie anulowania z pierwotną transakcją,
  • przeliczenie komponentu Monetary i segmentacji RFM na podstawie wartości netto,
  • porównanie segmentacji brutto i netto,
  • dłuższy okres danych do dokładniejszej oceny sezonowości.

15Czego się nauczyłam

Projekt pozwolił mi przećwiczyć nie tylko składnię SQL, ale przede wszystkim prowadzenie analizy od surowych danych do interpretacji biznesowej.

Wykorzystałam m.in.:

  • strukturę raw → staging → analytics,
  • kontrolę jakości i deduplikację,
  • EXCEPT ALL,
  • wieloetapowe CTE,
  • FILTER,
  • CASE,
  • COALESCE,
  • NULLIF,
  • ROW_NUMBER(),
  • LAG(),
  • DENSE_RANK(),
  • PERCENT_RANK(),
  • FIRST_VALUE(),
  • PERCENTILE_CONT(),
  • analizę RFM,
  • kohorty i retencję,
  • analizę cyklu życia i reaktywacji.

Najważniejszym elementem projektu było dla mnie rozróżnienie pomiędzy wynikiem obliczenia a jego poprawną interpretacją. Analiza anulowań i ograniczonej historii klienta pokazała, że nawet poprawne technicznie zapytanie SQL może prowadzić do błędnego wniosku, jeśli nie uwzględni się kontekstu i ograniczeń danych.

16Repozytorium

Struktura skryptów:

01_database_setup_and_import.sql
02_data_quality.sql
03_data_preparation.sql
04_customer_behavior.sql
05_customer_value.sql
06_rfm_segmentation.sql
07_retention_and_cohort_analysis.sql
08_cancellations_and_seasonality.sql

Zobacz na GitHubie