Cohort Analysis (์ฝํธํธ ๋ถ์)
Cohort๋ '๋์ง์ง๋จ'์ด๋ผ๋ ๋ป์ด๋ค.
Cohort ๋ถ์์ ๊ณตํต๋ ํน์ฑ์ ๊ฐ์ง ์ฌ์ฉ์ ์ง๋จ(์ฝํธํธ)์ ํ๋ ๋ณํ๋ฅผ ์๊ฐ์ ๋ฐ๋ผ ๋ถ์ํ์ฌ ํธ๋ ๋์ ํจํด์ ํ์ ํ๋ ๊ธฐ๋ฒ์ด๋ค.
ํ๋ซํผ์ ์ฌ์ฉ์๋ค์ด ์๋น์ค๋ฅผ ์ด๋ค ๋น์จ๋ก ์ฌ๋ฐฉ๋ฌธ/์ฌ๊ตฌ๋งคํ๋์ง ํ์ธํ๊ณ ์ถ์ ๋,
์ฆ ์ฌ์ฉ์์ ๋ฆฌํ ์ ์ ํ์ ํ๊ณ ์ ํ ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
๋ณดํต ์(monthly) ๋๋ ์ฃผ(weekly) ๋จ์๋ก ๋ฆฌํ ์ ์ ํ์ธํ๋ค.
Data ์ค๋น
๋ฐ์ดํฐ๋ ์บ๊ธ์ ์จ๋ผ์ธ ์ธ์ผ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ค.
https://www.kaggle.com/datasets/jihyeseo/online-retail-data-set-from-uci-ml-repo
Online Retail Data Set from UCI ML repo
transactions 2010-2011 for a UK-based and registered non-store online retail
www.kaggle.com
๋ฐ์ดํฐ์์ ์ ์ ID์ ๊ตฌ๋งค๋ ์ง๋ง ์์ผ๋ฉด ๋๊ธฐ ๋๋ฌธ์ ๊ฐ๊ณตํด์ SQL์ import ํด์ค๋ค.
ํ์ฉํ ๋ฐ์ดํฐ๋ ์ด๋ ๊ฒ ์๊ฒผ๋ค.

SQL ์ฝ๋ : ๋ฐฉ๋ฒ 1
MySQL workbench์์ ์ฝ๋๋ฅผ ์คํํ๋ค.
-- ์ ์ ๋ณ ์ฒซ ๊ตฌ๋งค์ผ ๊ตฌํ๊ธฐ
WITH first_purchase AS (
SELECT
CustomerID AS user_id,
MIN(InvoiceDate) AS first_purchase_date
FROM cohort_practice.online_sale_data
GROUP BY 1
),
-- ์ฒซ ๊ตฌ๋งค์ผ์ด ๋ด๊ธด ํ
์ด๋ธ๊ณผ ์ผ๋ฐ ๊ตฌ๋งค์ผ์ ์กฐ์ธ, ๋ ๋ ์ง์ ์ ์ฐจ์ด ๊ณ์ฐ
cohort_group as (
SELECT
ch.CustomerID AS user_id,
DATE_FORMAT(fp.first_purchase_date, '%Y-%m') AS cohort_month,
(YEAR(ch.InvoiceDate) * 12 + MONTH(ch.InvoiceDate)) -
(YEAR(fp.first_purchase_date) * 12 + MONTH(fp.first_purchase_date)) AS cohort_index -- ์ฒซ ๊ตฌ๋งค์ผ๊ณผ ๊ตฌ๋งค์ผ์ ์ ์ฐจ์ด ๊ณ์ฐ
FROM cohort_practice.online_sale_data ch
LEFT JOIN first_purchase fp
ON ch.CustomerID = fp.user_id )
-- ์ฒซ ๊ตฌ๋งค์ผ, ์ฌ๊ตฌ๋งค์ผ์ ๊ธฐ์ค์ผ๋ก ์ฌ์ฉ์ ๊ท๋ชจ count
select cohort_month, cohort_index, count(distinct user_id) as quantity
from cohort_group
group by cohort_month, cohort_index
1. first_purchase CTE :
์ ์ ID๋ณ๋ก ๊ทธ๋ฃนํ๋ฅผ ํ์ฌ ์ ์ ๋ณ ์ต์ด ๊ตฌ๋งค์ผ์ ๊ตฌํด์ค๋ค.
2. cohort_group CTE :
์ฒซ ๊ตฌ๋งค์ผ์ด ๋ด๊ธด ํ ์ด๋ธ๊ณผ ์๋ณธ ๋ฐ์ดํฐ๋ฅผ ์กฐ์ธํด์ค๋ค.
๊ทธ๋ฌ๋ฉด ํ row ๋น ์ ์ ID / ๊ทธ ์ ์ ์ ์ฒซ ๊ตฌ๋งค์ผ / ์ผ๋ฐ ๊ตฌ๋งค์ผ(InvoiceDate) ์ด๋ ๊ฒ ์ฐ๋ฆฌ๊ฐ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ํ ๊ณณ์ ๋ชจ์ ์ ์๋ค.
์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ ์ผ๋ฐ ๊ตฌ๋งค์ผ(InvoieDate)๊ณผ ์ฒซ ๊ตฌ๋งค์ผ์ ์ฐจ์ด๋ฅผ ๊ตฌํด์ผ ํ๋ค.
๋ฐ๋ผ์ InvoiceDate์ first_purchase_date์ 1์ด ํ ๋ฌ ๋จ์์ธ ์ซ์๋ก ๋ณํํด์ฃผ๊ณ ์ฐจ์ด๋ฅผ ๊ตฌํด์ค๋ค.
๊ทธ ์ฐจ์ด๋ cohort_index๋ก ๋์ค์ ์ฒซ ๊ตฌ๋งค์ผ๋ก๋ถํฐ 1๋ฌ, 2๋ฌ, 3๋ฌ ๋ค์ธ ์๊ฐ์ ํ๋ฆ์ ๋ํ๋ด์ฃผ๋ ์ญํ ์ ํ๋ค.
๋ค๋ฅธ ๋ธ๋ก๊ทธ์์๋ DATEDIFF์ TIMESTAMPDIFF๋ฅผ ์ฌ์ฉํ๋๋ฐ ๊ทธ๋ ๊ฒ ํ๋ฉด ๋ ๋ ์ง ์ฌ์ด์ ๊ฐ๊ฒฉ์ ๊ธฐ์ค์ผ๋ก ์ซ์๋ฅผ ๋ฐํํ๊ฒ ๋๋ ๋ฌธ์ ๊ฐ ์๊ธด๋ค.
์๋ฅผ ๋ค์ด, 2024๋ 3์ 24์ผ์ด ์ฒซ ๊ตฌ๋งค์ผ, 2024๋ 4์ 1์ผ์ด ์ฌ๊ตฌ๋งค์ผ์ธ ๊ฒฝ์ฐ
์ํ๋ ๊ฐ : 1 ( ํ๋ฌ ์ฐจ์ด ) ์ธ๋ฐ
DATEDIFF/TIMESTAMPDIFF๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ : 0 (๋ ๋ ์ง ๊ฐ๊ฒฉ์ด 11์ผ๋ก ํ๋ฌ ๋ฏธ๋ง) ์ผ๋ก
์ํ๋ ๊ฐ์ ๊ตฌํ ์ ์๋ค.
๋ฐ๋ผ์ ์์ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์๋ค.
3. ์ต์ข select๋ฌธ:
๋ง์ง๋ง์ผ๋ก ์ฒซ ๊ตฌ๋งค์ผ (cohort_month)์ ์ ์ฐจ์ด (cohort_index)๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ทธ๋ฃนํ๋ฅผ ํ์ฌ ์ ์ ID๋ฅผ countํด์ค๋ค.
๊ทธ๋ฌ๋ฉด ์ฒซ ๊ตฌ๋งค์ผ์ ๊ธฐ์ค์ผ๋ก n์ ๋จ์ด์ง ๋ ์ง์ ๋ช๋ช ์ด ๊ตฌ๋งค๋ฅผ ํ๋์ง๋ฅผ ์ ์ ์๊ฒ ๋๋ค.
๊ฒฐ๊ณผ ํ ์ด๋ธ
์ฟผ๋ฆฌ ์คํ ๊ฒฐ๊ณผ ํ ์ด๋ธ์ ์ด๋ ๊ฒ ์๊ฒผ๋ค.
์ด๊ฒ์ ์ฐ๋ฆฌ๊ฐ ์๋ ์ผ๊ฐํ ๋ชจ์ ์ฐจํธ๋ก ๋ง๋ค์ด์ฃผ๊ธฐ ์ํด SQL์ ์ฌ์ฉํ ์๋ ์์ง๋ง
์์ ์ด ๋ ๊ฐํธํ๊ธฐ ๋๋ฌธ์ ์์ ๋ก ์ฎ๊ฒจ์ค๋ค !
Cohort ์ฐจํธ : ์์ ์ฌ์ฉ
์์ ์ ํผ๋ฒ ํ ์ด๋ธ์ ์ฌ์ฉํด์ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ์ผ๊ฐํ ๋ชจ์ ์ฐจํธ๋ก ๋ง๋ค์ด์ค๋ค.
๊ทธ ๋ค์์ ์กฐ๊ฑด๋ถ ์์์ ์ฌ์ฉํด์ ์ค์ผ์ผ๋ณ๋ก ์์น ์ ํด์ค๋ค.

๊ฒฐ๊ณผ๋ฅผ ํด์ํด๋ณด์๋ฉด,
2010๋ 12์์ ์ฒซ ๊ตฌ๋งค๋ฅผ ํ ์ ์ ๋ 948๋ช ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ๊ทธ ์ ์ ์ค 38% (362๋ช )์ด ๋ค์ ๋ฌ์ธ 2011๋ 1์์๋ ๊ตฌ๋งค ํ์๋ฅผ ํ๋ค.
33%๊ฐ ๊ทธ ๋ค์ ๋ฌ์๋ ๊ตฌ๋งค๋ฅผ ํ๊ณ 39%, 36% ์ด๋ ๊ฒ ์ ๋จ์์ ์๊ฐ์ ํ๋ฆ์ ๋ฐ๋ผ ์ ์ ๊ฐ ์ฌ๊ตฌ๋งค๋ฅผ ํ๋์ง ํ์ธํ ์ ์๋ค.
SQl ์ฝ๋ : ๋ฐฉ๋ฒ 2
-- ์ฒซ ๊ตฌ๋งค์ผ ๊ตฌํ๊ธฐ
WITH first_order AS (
SELECT
CustomerID as customer_id,
MIN(InvoiceDate) AS first_order_date
FROM cohort_practice.online_sale_data
GROUP BY customer_id
),
-- ์ต์ด ๊ตฌ๋งค์ผ๊ณผ ์ผ๋ฐ ๊ตฌ๋งค์ผ ๊ตฌํ๊ธฐ
order_month_table AS (
SELECT
a.CustomerID as customer_id,
date_format(first_order_date, '%Y-%m-01') AS first_order_month,
date_format(InvoiceDate, '%Y-%m-01') AS order_month
FROM cohort_practice.online_sale_data a
LEFT JOIN first_order b
ON a.CustomerID = b.customer_id
),
-- ์ฒซ ๊ตฌ๋งค์ผ์ ๊ธฐ์ค์ผ๋ก ๊ทธ๋ฃนํ
-- month0์ ๊ทธ๋ฅ distinct ์ ์ id count
-- month1~11์ case when ์ฌ์ฉ
-- month1์ ๊ตฌ๋งค์ผ = ์ฒซ ๊ตฌ๋งค์ผ + 1m ์ผ ๋, distinct ์ ์ id count
cohort_chart as (
SELECT
first_order_month,
COUNT(DISTINCT customer_id) AS month0,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 1 month) THEN customer_id END) AS month1,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 2 month) THEN customer_id END) AS month2,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 3 month) THEN customer_id END) AS month3,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 4 month) THEN customer_id END) AS month4,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 5 month) THEN customer_id END) AS month5,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 6 month) THEN customer_id END) AS month6,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 7 month) THEN customer_id END) AS month7,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 8 month) THEN customer_id END) AS month8,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 9 month) THEN customer_id END) AS month9,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 10 month) THEN customer_id END) AS month10,
COUNT(DISTINCT CASE WHEN order_month = DATE_ADD(first_order_month, interval 11 month) THEN customer_id END) AS month11
FROM order_month_table
GROUP BY first_order_month
ORDER BY first_order_month)
select
first_order_month,
round(month0 * 100 / month0, 2) as month0,
round(month1 * 100 / month0, 2) as month1,
round(month2 * 100 / month0, 2) as month2,
round(month3 * 100 / month0, 2) as month3,
round(month4 * 100 / month0, 2) as month4,
round(month5 * 100 / month0, 2) as month5,
round(month6 * 100 / month0, 2) as month6,
round(month7 * 100 / month0, 2) as month7,
round(month8 * 100 / month0, 2) as month8,
round(month9 * 100 / month0, 2) as month9,
round(month10 * 100 / month0, 2) as month10,
round(month11 * 100 / month0, 2) as month11
from cohort_chart
- step 1 : ์ฒซ๋ฒ์งธ ๊ตฌ๋งค์ผ ๊ตฌํ๊ธฐ
์ ์ ID๋ฅผ ๊ธฐ์ค์ผ๋ก min(๊ฒฐ์ ์ผ), ์ฆ ์ต์ ๊ฒฐ์ ์ผ์ ๊ตฌํด์ค๋ค.
- step 2 : ์ฒซ๋ฒ์งธ ๊ตฌ๋งค์ผ๊ณผ ์๋ณธ ํ ์ด๋ธ ์กฐ์ธ์ํค๊ธฐ
[์ ์ ID, ์ต์ ๊ฒฐ์ ์, ์ผ๋ฐ ๊ฒฐ์ ์] ๊ตฌ์กฐ์ ํ ์ด๋ธ์ ๋ง๋ค๊ธฐ ์ํด ์กฐ์ธ์ ํด์ค๋ค.
- step 3 : ์ฒซ๋ฒ์งธ ๊ตฌ๋งค์ผ์ ๊ธฐ์ค์ผ๋ก ๊ทธ๋ฃนํํ์ฌ ์๋ณ ๋ฆฌํ ์ ๊ตฌํ๊ธฐ
์ต์ด ๊ฒฐ์ ์์ ๊ธฐ์ค์ผ๋ก ๊ทธ๋ฃนํ๋ฅผ ํ์ฌ ์นด์ดํธํ๋ค.
์ต์ด ๊ฒฐ์ ์์ ์ ์ ์๋ฅผ count ํ๋ฉด ๊ทธ๊ฒ month0์ด ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ต์ด ๊ฒฐ์ ์๋ก๋ถํฐ + 1๋ฌ์ธ ์ผ๋ฐ ๊ฒฐ์ ์์ ์ ์ ์๋ฅผ count ํ๋ฉด month 1์ด ๋๋ค.
๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก month11๊น์ง ๊ตฌํด์ค๋ค!
๊ฒฐ๊ณผ ํ ์ด๋ธ

SQL์์ ๋ฐ๋ก ์ด๋ ๊ฒ ๋ฆฌํ ์ ์ฐจํธ๋ฅผ ๊ทธ๋ ค์ค ์ ์๋ค.
๋ฌผ๋ก ์๊ฐํ ํด์ ํ์ฉํด์ ๊ทธ๋ ค์ฃผ๋ ๊ฒ ํจ์ฌ ๊ฐ๋ ์ฑ๋ ์๊ณ ๊ด๋ฆฌํ๊ธฐ ์ฌ์ธ ๊ฒ์ด๋ค.
