What is Cohort Analysis? 코호트 분석이란?
코호트(Cohort)는 가입 날짜, 첫 구매 월, 생년월일, 유입 채널 등 공통점을 공유하는 사용자 그룹을 말하는 것으로 비즈니스에서 많이 사용되는 용어입니다. 코호트 분석은 이러한 그룹을 시간에 따라 추적하여 파악하는 데 도움이 되는 방법으로 반복 적인 고객 행동 (구매, 참여, 지출 금액 등)을 이해하고 고객 및 수익 유지를 모니터링하는데 많이 이용을 합니다.
코호트 분석이 가치가 있는 이유?
코호트 분석은 고객의 충성도로 비즈니스의 건전성과 "고착성(Stickiness)"을 이해하는 데 도움을 줍니다. 신규 고객을 확보하는 것보다 현재 고객을 유지하는 것이 비용적으로 효율적이기 때문에 "고착성(Stickness)"은 매우 중요합니다. StartUp에서 특히 중요한 지표로 인식하고 있으며 사용자의 유지/이탈 현황을 시각화하고 LTV(Life Time Value)를 측정하고 이해하는데 좋은 방법입니다.
데이터 세트를 다운로드 후 프로그램 시작합시다.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
pd.set_option('max_columns', 30000)
#mpl.rcParams['lines.linewidth'] = 2
df = pd.read_excel('C:\\Users\\HANA\\\Downloads\\cohort_test.xlsx')
print(df.head())
#Result
OrderId OrderDate UserId TotalCharges CommonId PupId PickupDate
0 262 2009-01-11 47 50.67 TRQKD 2 2009-01-12
1 278 2009-01-20 47 26.60 4HH2S 3 2009-01-20
2 294 2009-02-03 47 38.71 3TRDC 2 2009-02-04
3 301 2009-02-06 47 53.38 NGAZJ 2 2009-02-09
4 302 2009-02-06 47 14.28 FFYHD 2 2009-02-09
잘 정돈된 사용자 ID와 주문정보가 들어있는 데이터 세트입니다.
df['OrderPeriod'] = df.OrderDate.apply(lambda x: x.strftime('%Y-%m'))
월별 Cohort를 수행하기 위해 데이터 세트에 OrderPeriod에 YYYY-MM형식의 데이터 세트를 입력해주게 됩니다. 이 때 사용 편의성을 위해 lambda를 사용하여 코딩의 용이성을 높이게 됩니다. 날짜 형식을 변경하는 함수로 strftime을 사용하는것도 기억하면 이후 코딩에 도움을 주게 됩니다.
df.set_index('UserId', inplace=True)
df['CohortGroup'] = df.groupby(level=0)['OrderDate'].min().apply(lambda x: x.strftime('%Y-%m'))
df.reset_index(inplace=True)
print(df.head())
#set_index : UserId에 인덱스를 설정합니다. inplace=True 셋팅은 원본 객체를 변경할지 여부 설정
#groupby(level=0): Index를 설정한 첫번째 열을 기준으로 group by를 실행함을 의미
#reset_index: 새로운 컬럼이 추가되어 index를 새로 reset합니다.
#Result
UserId OrderId OrderDate ... PickupDate OrderPeriod CohortGroup
0 47 262 2009-01-11 ... 2009-01-12 2009-01 2009-01
1 47 278 2009-01-20 ... 2009-01-20 2009-01 2009-01
2 47 294 2009-02-03 ... 2009-02-04 2009-02 2009-01
3 47 301 2009-02-06 ... 2009-02-09 2009-02 2009-01
4 47 302 2009-02-06 ... 2009-02-09 2009-02 2009-01
CohortGroup의 새로운 열을 만들고, 사용자의 첫 구매가 발생한 연도-월을 구합니다. 즉 Cohort의 기준을 고객별로 산정하기 위해 실행합니다.
grouped = df.groupby(['CohortGroup', 'OrderPeriod'])
cohorts = grouped.agg({'UserId': pd.Series.nunique, 'OrderId': pd.Series.nunique, 'TotalCharges': np.sum})
cohorts.rename(columns={'UserId': 'TotalUsers', 'OrderId': 'TotalOrders'}, inplace=True)
cohorts.head()
#Result
TotalUsers TotalOrders TotalCharges
CohortGroup OrderPeriod
2009-01 2009-01 22 30 1850.255
2009-02 8 25 1351.065
2009-03 10 26 1357.360
2009-04 9 28 1604.500
2009-05 10 26 1575.625
상기에서 새롭게 생성한 OrderPeriod와 CohortGroup을 Group화 하고, UserId와 OrderId, TotalCharses의 값을 agg함수로 Count 하고 Sum을 진행합니다. 마지막으로 각 칼럼의 이름을 변경을 하기 위해 rename을 수행합니다.
def cohort_period(df):
df['CohortPeriod'] = np.arange(len(df)) + 1
return df
cohorts = cohorts.groupby(level=0).apply(cohort_period)
cohorts.head()
print(cohorts.head())
#Result
TotalUsers TotalOrders TotalCharges CohortPeriod
CohortGroup OrderPeriod
2009-01 2009-01 22 30 1850.2550 1
2009-02 8 25 1351.0650 2
2009-03 10 26 1357.3600 3
2009-04 9 28 1604.5000 4
2009-05 10 26 1575.6250 5
... ... ... ... ...
2010-01 2010-02 50 101 8453.1039 2
2010-03 26 31 2238.6461 3
2010-02 2010-02 100 139 7374.7108 1
2010-03 19 19 945.9633 2
2010-03 2010-03 24 26 1099.5471 1
CohortGroup를 기준으로 Group화를 한 후 CohortPeriod 컬럼을 생성한 후 OrderPeriod와의 순서를 정합니다. 하기 그림의 위치를 정하기 위함입니다. np.arrange()의 사용법을 알면 도움이 됩니다.
예) np.arrange()는 일정한 값들을 array형태로 반황해 주는 함수입니다.
import numpy as np
np.arange(3)
>>> array([0, 1, 2])
x = df[(df.CohortGroup == '2009-01') & (df.OrderPeriod == '2009-01')]
y = cohorts.loc[('2009-01', '2009-01')]
assert(x['UserId'].nunique() == y['TotalUsers'])
assert(x['TotalCharges'].sum().round(2) == y['TotalCharges'].round(2))
assert(x['OrderId'].nunique() == y['TotalOrders'])
x = df[(df.CohortGroup == '2009-01') & (df.OrderPeriod == '2009-09')]
y = cohorts.loc[('2009-01', '2009-09')]
assert(x['UserId'].nunique() == y['TotalUsers'])
assert(x['TotalCharges'].sum().round(2) == y['TotalCharges'].round(2))
assert(x['OrderId'].nunique() == y['TotalOrders'])
x = df[(df.CohortGroup == '2009-05') & (df.OrderPeriod == '2009-09')]
y = cohorts.loc[('2009-05', '2009-09')]
assert(x['UserId'].nunique() == y['TotalUsers'])
assert(x['TotalCharges'].sum().round(2) == y['TotalCharges'].round(2))
assert(x['OrderId'].nunique() == y['TotalOrders'])
변환된 데이터가 잘 되었는지 확인하기 위한 검증 합니다. 처음 설정한 df dataframe와 새롭게 생성한 cohort의 dataframe 간 차이가 있는지 확인하기 위해 assert를 사용합니다.
#assert?
assert는 뒤의 조건이 True가 아니면 AssertError를 발생합니다.
예를들어 어떤 함수는 성능을 높이기 위해 반드시 정수만을 입력받아 처리하도록 만들 수 있습니다. 이런 함수를 만들기 위해서는 반드시 함수에 정수만 들어오는지 확인할 필요가 있습니다. 이를 위해 if문을 사용할 수도 있고 '예외 처리'를 사용할 수도 있지만 '가정 설정문'을 사용하는 방법도 있습니다.
def test(t):
assert type(t) is int, 'Oh! No. there is no Int Type in this list'
lists = [1, 3, 6, 3, 8, 7, 13, 23, 13, 2, 3.14, 2, 3]
for i in lists:
test(i)
- Result
Traceback (most recent call last):
File "C:/Users/HANA/PycharmProjects/HANATOUR/Pandas/TEST_PD#2.py", line 89, in <module>
test(i)
File "C:/Users/HANA/PycharmProjects/HANATOUR/Pandas/TEST_PD#2.py", line 85, in test
assert type(t) is int, 'Oh! No. there is no Int Type in this list'
AssertionError: Oh! No. there is no Int Type in this list
cohorts.reset_index(inplace=True)
cohorts.set_index(['CohortGroup', 'CohortPeriod'], inplace=True)
cohort_group_size = cohorts['TotalUsers'].groupby(level=0).first()
cohort_group_size.head()
#CohortGroup
2009-01 22
2009-02 15
2009-03 13
2009-04 39
2009-05 50
2009-06 32
2009-07 50
2009-08 31
2009-09 37
2009-10 54
2009-11 130
2009-12 65
2010-01 95
2010-02 100
2010-03 24
Name: TotalUsers, dtype: int64
각 Cohort그룹별 Base를 가져오기 위해 CohortGroup별로 전체 고객 수의 첫 번째 값을 가져오기 위해 first()를 지정한다.
print('-----Head()----------')
print(cohorts.head())
print('-----unstack()-------')
print(cohorts['TotalUsers'].unstack(0).head())
print('------divide()---------')
print(cohorts['TotalUsers'].unstack(0).divide(cohort_group_size, axis=1).head())
#Result
-----Head()----------
OrderPeriod TotalUsers TotalOrders TotalCharges
CohortGroup CohortPeriod
2009-01 1 2009-01 22 30 1850.255
2 2009-02 8 25 1351.065
3 2009-03 10 26 1357.360
4 2009-04 9 28 1604.500
5 2009-05 10 26 1575.625
-----unstack()-------
CohortGroup 2009-01 2009-02 2009-03 ... 2010-01 2010-02 2010-03
CohortPeriod ...
1 22.0 15.0 13.0 ... 95.0 100.0 24.0
2 8.0 3.0 4.0 ... 50.0 19.0 NaN
3 10.0 5.0 5.0 ... 26.0 NaN NaN
4 9.0 1.0 4.0 ... NaN NaN NaN
5 10.0 4.0 1.0 ... NaN NaN NaN
[5 rows x 15 columns]
------divide()---------
CohortGroup 2009-01 2009-02 2009-03 ... 2010-01 2010-02 2010-03
CohortPeriod ...
1 1.000000 1.000000 1.000000 ... 1.000000 1.00 1.0
2 0.363636 0.200000 0.307692 ... 0.526316 0.19 NaN
3 0.454545 0.333333 0.384615 ... 0.273684 NaN NaN
4 0.409091 0.066667 0.307692 ... NaN NaN NaN
5 0.454545 0.266667 0.076923 ... NaN NaN NaN
[5 rows x 15 columns]
Map구조로 만들기 위한 데이터 구조화 unstack()를 이용하여 CohortGroup기준으로 데이터를 정리합니다. 이후 divide를 이용하여 X축을 기준으로 나누어 주게 됩니다. 상기 결과를 보고 이해가 필요하네요.
결과를 그래프로 그리기 위한 출력을 시행합니다.
user_retention[['2009-06', '2009-07', '2009-08']].plot(figsize=(10,5))
plt.title('Cohorts: User Retention')
plt.xticks(np.arange(1, 12.1, 1))
plt.xlim(1, 12)
plt.ylabel('% of Cohort Purchasing');
plt.show()
import seaborn as sns
sns.set(style='white')
plt.figure(figsize=(12, 8))
plt.title('Cohorts: User Retention')
sns.heatmap(user_retention.T, mask=user_retention.T.isnull(), annot=True, fmt='.0%');
plt.show()
'Python' 카테고리의 다른 글
제휴 모델 자동화[1 : 애드픽(AdPick)의 뉴스픽(NewsPick) 링크 자동으로 만들기 (0) | 2021.05.08 |
---|---|
입문자 위한 Python 기본 안내서 [2] : 제어문에 대해 (0) | 2021.04.27 |
입문자 위한 Python 기본 안내서 [1] : 자료형에 대해 (0) | 2021.04.27 |
[실습] 매일 경제 기사 Python 크롤링 후 Dataframe에 넣은 후 CSV에 저장하기 (0) | 2021.04.26 |
Top Python Libraries for Data Science, Data Visualization & Machine Learning (0) | 2020.11.16 |
[TIP] Jupyter에서 다른 폴더의 library, import 호출하기 (0) | 2020.11.16 |
Python에서의 lambda(람다) Function의 사용 (1) | 2020.11.09 |
Pycharm과 Jupyter Notebook 연결하기 (0) | 2020.11.07 |