코호트 분석과 동일한 데이터로 이어서 RFM 세그먼트를 분석해본다.
(RFM에 대한 개념과 예시는 별도 포스팅으로 게시할 예정입니다)
RFM을 구하기 위한 전처리
- 먼저 총 구매금액 컬럼부터 생성해준다.
- 상품 개당 가격과 판매량을 곱해준다.
# 총 구매금액 컬럼 생성
df['TotalSum'] = df['UnitPrice'] * df['Quantity']
- 송장번호 최솟값과 최댓값(가장 오래전 주문 건과 최근 주문 건의 날짜)을 출력해본다.
- 대략적인 시간 범위를 파악한다.
print('Min Invoice Date: ', df.InvoiceDate.dt.date.min(), 'max Invoice Date: ', df.InvoiceDate.dt.date.max(), '\n')
df.head(3)
- 보통 당일 또는 어제의 가장 최근 데이터를 기준으로 RFM을 측정한다.
- 따라서 이 예제에서는 InvoiceDate 열에서 가장 최대 날짜를 찾고, 그 날짜에 하루 더하는 연산을 수행한다.
snapshot_date = df['InvoiceDate'].max() + dt.timedelta(days=1)
snapshot_date
고객별로 RFM을 구하기
- rfm은 고객을 분류하는 기준이므로 CustomerID를 기준으로 Groupby한다.
- 이때 집계함수는 컬럼마다 각각 다르게 적용한다.(아래와 같다)
- 얼마나 최근에 구매했는지 확인하기 위해 snapshot_date 와 가장 최근 구매일(송장일 최댓값)을 빼주고, days로 일 수를 센다.
- 얼마나 자주 구매했는지 확인하기 위해 InvoiceNo의 개수를 count
- 얼마나 많이 구매했는지 확인하기 위해 Totalsum의 합을 구한다
rfm = df.groupby(['CustomerID']).agg({'InvoiceDate': lambda x : (snapshot_date - x.max()).days,
'InvoiceNo':'count',
'TotalSum':'sum'})
rfm.rename(columns={'InvoiceDate':'Recency', 'InvoiceNo':'Frequency', 'TotalSum':'MonetaryValue'}, inplace=True)
RFM Segment
- R, F, M 값들을 구했으면 이제 구간을 나눠야한다. qcut을 사용하고, 구간개수는 4로 한다.
- label은 미리 지정해주는데, 이때 recency만 작을수록 중요고객이므로 유의한다.
# RFM Segment
r_label = range(4, 0, -1) #작을수록 중요고객
f_label = range(1, 5) #클수록 중요고객
m_label = range(1, 5) #클수록 중요고객
r_quantiles = pd.qcut(rfm['Recency'], q=4, labels = r_label)
f_quantiles = pd.qcut(rfm['Frequency'], q=4, labels = f_label)
m_quantiles = pd.qcut(rfm['MonetaryValue'], q=4, labels = m_label)
- 이후 rfm 테이블에 위에서 구한 값들을 추가로 지정해준다.
rfm = rfm.assign(R = r_quantiles, F = f_quantiles, M = m_quantiles)
rfm.head()
RFM Score 구하기
- RFM Score는 위에서 각각 구한 R, F, M 값을 나란히 붙여서 만든다. 해당 함수를 작성한다.
- 함수를 적용하여 RFM_Segment 컬럼을 생성한다.
- 그리고 R, F, M 값을 모두 더하여 RFM Score를 구한다.
# RFM Score
def add_rfm(x):
return str(x['R']) + str(x['F']) + str(x['M'])
rfm['RFM_Segment'] = rfm.apply(add_rfm, axis=1)
rfm['RFM_Score'] = rfm[['R', 'F', 'M']].sum(axis=1)
rfm.head()
RFM Segment 살펴보기
- 바로 비즈니스 액션에 적용하거나 타겟 마케팅 등을 실행하기 전에 각 segment의 사이즈부터 확인해보는 것이 좋다.
rfm.groupby(['RFM_Segment']).size().sort_values(ascending = False)[:5]
- 특정 segment도 따로 필터링해서 살펴본다.
# segment 필터링
rfm[rfm['RFM_Segment']=='1.01.01.0'].head()
- RFM Score 별로 요약 통계도 살펴본다.
# RFM Score 별로 요약통계
rfm.groupby(['RFM_Score']).agg({'Recency':'mean', 'Frequency':'mean', 'MonetaryValue':['mean', 'count']}).round(1)
- 이제 RFM Score 별로 고객 군을 나누어 이름을 붙여준다.
- 데이터프레임을 매개변수로 넣었을 때, 점수에 따라 골드/실버/브론즈 등급을 매기는 함수를 작성한다.
def segments(df):
if df['RFM_Score'] > 9 :
return 'Gold'
elif (df['RFM_Score'] > 5) & (df['RFM_Score'] <= 9):
return 'Silver'
else:
return 'Bronze'
# 함수 적용
rfm['General_Segment'] = rfm.apply(segments, axis=1)
# 골드/실버/브론즈 별로 확인
rfm.groupby(['General_Segment']).agg({'Recency':'mean', 'Frequency':'mean', 'MonetaryValue':['mean', 'count']}).round(1)
🎖️부록. K-Means Clustering으로 고객 군집화하기
참고로, K-Means Clustering을 활용해 고객 군집을 생성할 수도 있다.
K-Means Clustering으로 군집화 시 다음 순서로 진행한다.
- 데이터 전처리 : 아래 예시 참고
- 군집의 개수 선택 : 엘보우(시각적 방법), 실루엣 계수(수학적 방법)
- 전처리된 데이터에서 k-평균 군집화 실행
- 각 군집의 평균 RFM 값 분석
▶︎ 데이터 전처리
- k-means의 성능과 정확도를 높이기 위해 다음과 같은 주요 가정을 확인해야한다.
- 변수의 대칭적 분포(왜도 없음) : 데이터가 한쪽으로 치우치지 않아야 함 👉 심하면 로그변환
- 변수들의 평균값이 유사해야함 : 군집화 알고리즘이 각 변수의 중요성을 동등하게 고려해야 하므로 👉 표준화
- 변수들의 분산이 유사해야함 : 분산이 크게 다르면, 군집화 알고리즘이 분산이 큰 변수에 민감하게 반응하므로 👉 스케일링
- 따라서 describe()로 평균과 분산을 확인하고
- distplot을 그려 왜도도 확인해본다.
rfm_rfm = rfm[['Recency','Frequency','MonetaryValue']]
rfm_rfm.describe()
f, ax = plt.subplots(figsize = (10, 12))
plt.subplot(3, 1, 1);sns.distplot(rfm.Recency, label = 'Recency')
plt.subplot(3, 1, 2);sns.distplot(rfm.Frequency, label = 'Frequency')
plt.subplot(3, 1, 3);sns.distplot(rfm.MonetaryValue, label = 'MonetaryValue')
plt.tight_layout()
plt.show(
- 이렇게 왜도가 심하면 로그변환을 취해줘야한다.
# 로그 변환으로 왜도 낮추기
rfm_log = rfm[['Recency','Frequency','MonetaryValue']].apply(np.log, axis=1).round(3)
# 로그변환된 RFM값 분포 확인
f, ax = plt.subplots(figsize=(10, 12))
plt.subplot(3, 1, 1);sns.distplot(rfm_log.Recency, label='Recency')
plt.subplot(3, 1, 2);sns.distplot(rfm_log.Frequency, label = 'Frequency')
plt.subplot(3, 1, 3);sns.distplot(rfm_log.MonetaryValue, label = 'MonetaryValue')
plt.style.use('fivethirtyeight')
plt.tight_layout()
plt.show()
728x90
'프로덕트 분석' 카테고리의 다른 글
그로스 해킹이란? (개념과 전제 조건) (0) | 2024.02.28 |
---|---|
리텐션(Retention)이란? (1) | 2024.01.27 |
[Pandas] Cohort Analysis(2) : 고객 유지율 구하기 (1) | 2024.01.26 |
[Pandas] Cohort Analysis(1) 코호트 분석 시작하기 (0) | 2024.01.26 |
코호트 분석이란? (1) | 2024.01.26 |