안녕하세요~ 꽁냥이에요.
오늘은 RFM 고객 분석의 마지막 내용으로 RFM 가중치를 계산하는 방법에 대해 소개하려고 합니다.
RFM 고객 분석에 대한 기본개념과 RFM 점수 계산에 대한 내용은 아래 포스팅을 참고하세요.
2. Python을 이용한 RFM 분석 - RFM 점수 계산
이번에 소개할 내용은 다음과 같습니다.
1. 분석 목표
꽁냥이의 데이터 분석 목표는 다음과 같아요.
즉, 위 그림과 같이 1) 매출 기여도의 분산을 최대화하는 가중치를 구하고, 2) 이 가중치와 RFM점수를 이용하여 고객별로 등급을 부여하고요. 마지막으로 3) 각 등급별 매출 기여도를 확인하는 것이 꽁냥이의 목표예요.
2. 데이터
저번 포스팅(RFM 점수 계산)에서 저장했던 데이터를 가져올게요. 혹시나 없으신 분들을 위해 아래에 데이터 파일을 첨부해놨으니 다운로드하면 됩니다~
데이터가 준비됐으면 아래와 같이 데이터를 읽어옵니다.
import pandas as pd
rfm_score = pd.read_csv('result.csv') ## 데이터 불러오기
데이터를 한번 확인해볼까요?
데이터에 대한 설명은 아래 표를 참고하세요.
변수 | 설명 |
CustomerID | 고객아이디 |
Recency | 최근구매일, 2011년 1월 1일 0시 0분을 기준으로 경과한 시간을 초단위로 계산 |
Frequency | 방문횟수 |
Monetary | 구매금액 |
Recency_R | Recency 점수, 1~5점까지이며 점수가 높을수록 좋음 |
Frequency_F | Frequency 점수, 1~5점까지이며 점수가 높을수록 좋음 |
Monetary_M | Monetary 점수, 1~5점까지이며 점수가 높을수록 좋음 |
3. 데이터 분석
1) 데이터 전처리
먼저 이번 데이터 분석에서 필요한 변수만 뽑아내겠습니다~
## 필요 변수 추출
rfm_score = rfm_score[['CustomerID', 'Monetary', 'Recency_R','Frequency_F','Monetary_M']]
2) 데이터 분석
여기서 데이터 분석 과정은 다음과 같습니다.
1. 매출 기여도의 분산을 최대화하는 가중치 찾기
2. 가중치와 RFM점수를 이용하여 고객별로 등급 부여
3. 각 등급별 매출 기여도를 확인
이제 과정별로 데이터 분석을 시작해보겠습니다.
1. 매출 기여도의 분산을 최대화하는 가중치 찾기
먼저 꽁냥이의 전략은 다음과 같아요.
꽁냥이의 전략으로 구한 최적 가중치는 이론상 최적 가중치의 근사값이라는 점을 기억해주세요. 왜냐하면 가중치의 모든 값을 고려한 것이 아닌 0.01단위의 값만 고려했기 때문이죠.
자 이제 코드로 구현을 해볼게요.
먼저 데이터 분석에 필요한 모듈을 임포트 하겠습니다.
import pandas as pd
import numpy as np
from tqdm import tqdm
다음으로 최적 가중치를 찾기 위한 함수 및 사전 준비 코드를 살펴보겠습니다.
def get_score(level, data, reverse = False):
'''
Description :
level안에 있는 원소를 기준으로
1 ~ len(level)+ 1 까지 점수를 부여하는 함수
Parameters :
level = 튜플 또는 리스트 타입의 숫자형 데이터이며 반드시 오름차순으로 정렬되어 있어야함.
예 - [1,2,3,4,5] O, [5,4,3,2,1] X, [1,3,2,10,4] X
data = 점수를 부여할 데이터. 순회가능한(iterable) 데이터 형식
reverse = 점수가 높을 때 그에 해당하는 값을 낮게 설정하고 싶을 때 True
return :
점수를 담고 있는 리스트 반환
'''
score = []
for j in range(len(data)):
for i in range(len(level)):
if data[j] <= level[i]:
score.append(i+1)
break
elif data[j] > max(level):
score.append(len(level)+1)
break
else:
continue
if reverse:
return [len(level)+2-x for x in score]
else:
return score
grid_number = 100 ## 눈금 개수, 너무 크게 잡으면 메모리 문제가 발생할 수 있음.
weights = []
for j in range(grid_number+1):
weights += [(i/grid_number,j/grid_number,(grid_number-i-j)/grid_number)
for i in range(grid_number+1-j)]
num_class = 5 ## 클래스 개수
class_level = np.linspace(1,5,num_class+1)[1:-1] ## 클래스를 나누는 지점을 정한다.
total_amount_of_sales = rfm_score['Monetary'].sum() ## 구매금액 총합 = 총 매출
위 코드를 살펴보겠습니다. 중요하다고 생각하는 것을 설명하고 그 외 코드는 주석을 참고하세요.
line 1~29
지난번 포스팅(RFM 점수 계산)에서 사용했던 함수입니다. 여기에 점수가 높을수록 해당하는 등급은 낮게 설정하는 옵션을 추가했습니다.
line 31~35
최근 구매일, 방문 횟수, 구매금액에 부여할 가중치가 가질 수 있는 값을 0 부터 1까지 0.01단위로 분할하고
세개의 가중치 합이 1이 되는 것만 뽑아냅니다. 여기서 주의하실 점은 grid_number를 100보다 크게 잡으시면 컴퓨터가 멈출 수 있어요(저 같은 경우 grid_number를 1000으로 잡았을 때 컴퓨터가 멈췄습니다. weights 변수에 너무 많은 값이 담겨있어 이로 인해 메모리 문제가 발생하는거 같아요).
line 36~37
등급의 개수를 정합니다. 꽁냥이는 1~5등급까지 정하기 위해서 개수를 5로 설정했습니다(line 36). 그리고 등급의 기준점을 구합니다(line 37). 등급의 기준점이 무엇인지 확인하기 위해 class_level을 출력해보면 아래와 같이 [1.8, 2.6, 3.4, 4.2]가 보입니다.
즉, 가중치와 RFM 점수를 이용한 총점수가 1.8점 이하면 5등급이고 4.2점 보다 크면 1등급이 된다는 뜻이지요. class_level은 이처럼 등급을 정하는 기준값이 되는거예요.
다음으로 최적 가중치를 찾는 코드입니다.
max_std = 0 ## 표준편차 초기값
for w in tqdm(weights,position=0,desc = '[Finding Optimal weights]'):
## 주어진 가중치에 따른 고객별 점수 계산
score = w[0]*rfm_score['Recency_R'] + \
w[1]*rfm_score['Frequency_F'] + \
w[2]*rfm_score['Monetary_M']
rfm_score['Class'] = get_score(class_level,score,True) ## 점수를 이용하여 고객별 등급 부여
## 등급별로 구매금액을 집계한다.
grouped_rfm_score = rfm_score.groupby('Class')['Monetary'].sum().reset_index()
## 클래스별 구매금액을 총구매금액으로 나누어 클래스별 매출 기여도 계산
grouped_rfm_score['Monetary'] = grouped_rfm_score['Monetary'].map(lambda x : x/total_amount_of_sales)
std_sales = grouped_rfm_score['Monetary'].std() ## 매출 기여도의 표준편차 계산
if max_std <= std_sales:
max_std = std_sales ## 표준편차 최대값 업데이트
optimal_weights = w ## 가중치 업데이트
먼저 꽁냥이는 계산 상의 이유로 최대 분산을 찾는 문제를 최대 표준편차를 찾는 문제로 바꿨습니다. 이렇게 해도 상관없는 이유는표준편차는 음이 아닌 값이고 표준편차가 커질수록 분산도 커지므로 최대 분산을 찾는 문제와 최대 표준편차를 찾는 문제가 같아지기 때문입니다.
line 1
표준편차 값을 초기화합니다.
line 4~12
가중치와 RFM 점수를 이용하여 고객별로 총점수를 구하고요(line 4~6). 그리고 이렇게 구한 점수를 이용해서 get_score함수로 등급을 매깁니다(line 7). 다음으로 등급별로 구매금액을 집계합니다(line 9). 마지막으로 등급별 매출 기여도를 계산합니다(line 12).
line 13
매출 기여도의 표준편차를 계산합니다.
line 14~16
현재 표준편차 값과 최대 표준편차 값을 비교하여 더 큰 값을 최대 표준편차 값으로 업데이트합니다.
자, 그럼 실행해볼까요?
보시는 것처럼 실행시간이 10분~11분 정도 걸려요. 최적 가중치는 최근 구매일, 방문 횟수, 구매금액 순으로 각각 0.2, 0, 0.8입니다. 방문 횟수에 대한 가중치는 0으로 나왔다는 것이 신기하네요.
2. 가중치와 RFM점수를 이용하여 고객별로 등급 부여
위에서 구한 가중치를 이용하여 고객별로 등급을 부여해보겠습니다. 아래 코드를 실행하세요.
score = optimal_weights[0]*rfm_score['Recency_R'] + \
optimal_weights[1]*rfm_score['Frequency_F'] + \
optimal_weights[2]*rfm_score['Monetary_M'] ## 고객별 점수 계산
rfm_score['Class'] = get_score(class_level,score,True) ## 고객별 등급 부여
보시면 알겠지만 최적 가중치를 구하는 과정에서 봤던 코드와 유사합니다. 차이점은 최적 가중치를 이용했다는 점만 달라요.
3. 각 등급별 매출 기여도를 확인
이제 매출 기여도를 확인해보겠습니다. 아래 코드를 실행하세요.
## 클래스별 고객 수 계산
temp_rfm_score1 = rfm_score.groupby('Class')['CustomerID'].count().reset_index().rename(columns={'CustomerID':'Count'})
## 클래스별 구매금액(매출)계산
temp_rfm_score2 = rfm_score.groupby('Class')['Monetary'].sum().reset_index()
## 클래스별 매출 기여도 계산
temp_rfm_score2['Monetary'] = temp_rfm_score2['Monetary'].map(lambda x : x/total_amount_of_sales)
## 데이터 결합
result_df = pd.merge(temp_rfm_score1,temp_rfm_score2,how='left',on=('Class'))
line 2
등급별 고객 수를 집계합니다.
line 5~8
등급별 구매금액을 집계한 후 매출 기여도를 계산합니다(line 5). 매출 기여도는 등급별 구매금액에 총 구매금액으로 나누어 계산합니다(line 8).
line 11
등급별 고객 수 데이터와 등급별 매출 기여도 데이터를 결합합니다.
이제 데이터 분석은 끝났어요~ 결과를 살펴볼까요?
흠.. 3등급 고객은 없고 5등급인 고객이 3800명으로 압도적으로 많네요. 이 때문에 매출 기여도 또한 약 82%를 차지하게 됐다고 추측이 되네요. 위 결과를 해석하면 1등급(등급이 가장 높은)인 고객의 매출 기여도는 약 6%이고 5등급(등급이 가장 낮은)인 고객은 매출 기여도가 무려 82% 가까이 된다는 것을 알 수 있습니다.
꽁냥이의 생각으로는 매출 기여도가 등급이 더 높은 고객에게서 높게나와야 되는데 정반대의 결과가 나왔어요. 그래서 꽁냥이는 등급이 높을수록 매출 기여도가 높아야 한다는 제약 조건을 추가했습니다.
아래 코드를 볼게요.
max_std = 0 ## 표준편차 초기값
for w in tqdm(weights,position=0,desc = '[Finding Optimal weights]'):
## 주어진 가중치에 따른 고객별 점수 계산
score = w[0]*rfm_score['Recency_R'] + \
w[1]*rfm_score['Frequency_F'] + \
w[2]*rfm_score['Monetary_M']
rfm_score['Class'] = get_score(class_level,score,True) ## 점수를 이용하여 고객별 등급 부여
## 등급별로 구매금액을 집계한다.
grouped_rfm_score = rfm_score.groupby('Class')['Monetary'].sum().reset_index()
## 제약조건 추가 - 등급이 높은 고객들의 매출이 낮은 등급의 고객들보다 커야한다.
grouped_rfm_score = grouped_rfm_score.sort_values('Class')
temp_monetary = list(grouped_rfm_score['Monetary'])
if temp_monetary != sorted(temp_monetary,reverse=True):
continue
## 클래스별 구매금액을 총구매금액으로 나누어 클래스별 매출 기여도 계산
grouped_rfm_score['Monetary'] = grouped_rfm_score['Monetary'].map(lambda x : x/total_amount_of_sales)
std_sales = grouped_rfm_score['Monetary'].std() ## 매출 기여도의 표준편차 계산
if max_std <= std_sales:
max_std = std_sales ## 표준편차 최대값 업데이트
optimal_weights = w ## 가중치 업데이트
최적 가중치를 찾는 기존 코드에 제약 조건을 추가했어요(line 12~16).
위 코드를 실행해볼까요?
이번에도 11분 정도 지나면 아래의 결과를 확인할 수 있어요.
최적 가중치는 최근 구매일, 방문 횟수, 구매금액 순으로 각각 0.74, 0.26, 0입니다. 아까와는 달리 구매 금액에 대한 가중치가 0으로 나왔어요.
이 가중치를 이용해서 다시 고객별 등급을 구하고 등급 별 매출 기여도를 확인해보겠습니다.
이번에는 1등급인 고객의 매출 기여도가 약 63%이고 5등급인 고객의 매출 기여도가 약 7%가 나왔네요. 이제야 뭔가 납득할만한 결과가 나온 거 같아요. 만약 마케터가 이 데이터 분석 결과를 본다면 1등급인 고객 961명에 대하여 집중적으로 마케팅 계획을 세울 수 있을 거예요.
또한 여기서 구한 가중치는 다음 연도(2012년) 고객 등급을 부여하는데 사용됩니다. 예를 들어 새로운 고객 A의 최근 구매일, 방문 횟수, 구매금액 점수가 각각 3, 4, 5라면 가중치를 이용하여 고객 점수를 다음과 같이 계산할 수 있습니다.
A고객 점수 = 0.74 X 3 + 0.26 X 4 + 0 X 5 = 3.26
즉, A고객의 점수는 3.26점이고 이는 3등급에 해당하는 구간(2.6 ~ 3.4)에 있으므로 A고객은 3등급 고객이 되는 것입니다. 이 점수를 가지고 마케터는 A고객에게 맞춤형 서비스를 세울 수 있지요.
이번 포스팅에서는 RFM 분석에서 RFM 가중치를 구하는 방법에 대해서 알아보았습니다.
RFM 고객 분석에 대해서 3편에 나눠서 포스팅했는데 여러분에게 도움이 됐으면 좋겠어요.
궁금하신 점이나 잘못된 점, 그 밖에 하고 싶은 말은 댓글로 남겨주세요~
다음 포스팅도 기대해주시고 지금까지 꽁냥이 글 읽어주셔서 감사합니다.
'데이터 분석 > 데이터 분석' 카테고리의 다른 글
[A/B 테스트] 2. A/B 테스트 사례에 대하여 알아볼까요?! (0) | 2020.08.09 |
---|---|
[A/B 테스트] 1. A/B 테스트란 무엇일까요? (0) | 2020.07.24 |
[RFM 고객 분석] 2. Python을 이용한 RFM 분석 - RFM 점수 계산 (1490) | 2020.06.20 |
[RFM 고객 분석] 1. RFM 고객 분석이 무엇일까요? (2182) | 2020.06.15 |
[프롤로그] 들어가는 글 (1111) | 2020.06.08 |
댓글