- RFM(Recency, Frequency, Monetary)
- RFM은 가치있는 고객을 추출해내어 이를 기준으로 고객을 분류할 수 있는 방법 -> 마케팅에서 가장 많이 사용되고 있는 분석방법 중 하나
- RFM은 구매 가능성이 높은 고객을 선정하기 위한 데이터 분석 방법으로 이 과정을 통해 데이터는 의미있는 정보로 전환
- Recency - 거래의 최근성: 고객이 얼마나 최근에 구입했는가?
- Frequency - 거래빈도: 고객이 얼마나 빈번하게 우리 상품을 구입했나?
- Monetary - 거래규모: 고객이 구입했던 총 금액은 어느 정도인가?
- 현재 개발된 RFM 모형은 크게 4가지로 분류 가능 -> but, 정설은 아니며 신뢰하기 어려움을 전제로 참고
- 모델1. RFM 각 요소의 20% rule의 적용
- 모델2. 비율 척도에 의한 양적인 정도의 차이에 따른 등간격의 5등급 분류
- 모델3. 상하 20%를 제외한 등간격 척도에 의한 그룹 분류
- 모델4. 군집 분석에 의한 각 요소 별 5개의 그룹 분류 / 참고: RFM(위키백과)
-> 가장 큰 과제는 그룹의 경계를 정의하는 것
- 파레토 법칙
- 상위 고객의 20%가 기업 총 매출의 80%를 차지
- 80:20 법칙을 고려하면 고객 매출 데이터가 누적됨에 따라 마케팅에 데이터를 활용해 마케팅에 활용할 수 있음
- 고객 세분화
- 상품과 서비스 판매정보 - 상품판매 자료 거래 금액, 횟수
- 인구통계학적 정보 - 나이, 성별, 직업, 학력, 거주지역, 소득수준
- 라이프 스타일 정보 - 순차적, 구매 정보, RFM 정보
- 심리 정보 - 구매욕구
- 행동 정보 - 구매패턴 Life Time Value
RFM 모형 분석에서는 제 2의 분석을 통하여 각 집단의 중요도를 측정하고 그 결과를 미래의 마케팅의 활용하는 것이 RFM 모형의 목적이다
데이터셋: http://archive.ics.uci.edu/ml/machine-learning-databases/00352/Online%20Retail.xlsx
유효 데이터 추출
# 유효 데이터 추출
raw_valid = raw[(raw['CustomerID'].notnull()) & (raw['Quantity'] > 0) & (raw['UnitPrice'] > 0)].copy()
# 구매 금액 계산
raw_valid["TotalPrice"] = raw_valid["Quantity"] * raw_valid["UnitPrice"]
# 이상치 제거
raw_valid = raw_valid[raw_valid["TotalPrice"] < 160000]
- 'CustomerID'가 있고 'Quantity', 'UnitPrice'가 0보다 큰 데이터를 가져온다
- 'TotalPrice'는 RFM 중 MonetaryValue 값이 된다
- 'TotalPrice'의 기술통계값 확인해보니 160000 이상인 이상치를 발견 -> 제외
중복 데이터 확인
df = raw_valid.drop_duplicates().copy()
- 중복 데이터 여러 이유로 발생할 수 있음 -> 네트워크 통신 문제나 쇼핑몰의 UI 구성 등의 다양한 이슈로 발생할 수 있음
- ex) 주문을 하고 새로고침을 했을 때 다시 주문 트랜잭션에 들어가거나 하는 이슈가 발생할 가능성도 있음
- drop_duplicates() 안에 keep 파라미터 지정 가능 -> 'first', 'last','False'로 선택적 입력 가능
df.hist() ;
RFM 계산
df['InvoiceDate'] = pd.to_datetime(df['InvoiceDate'])
last_timestamp = df['InvoiceDate'].max() + dt.timedelta(days = 1)
last_timestamp
- 날짜 형식으로 변환
- Recency 계산을 위해 해당 주문에서 가장 최근 구매가 일어난 시간 가져온다
- 최근 거래 기준일 만들기 위해 timedelta로 날짜 더해준다 -> 최소값 1 설정(RFM을 구할 때, 최근 마지막 거래일과 해당 고객의 마지막 거래일의 차이가 0이 아니라 1이 되도록)
- 고객별 Recency, Frequency, Monetary 구하기
- Recency : 최근 거래 기준일(last_timestamp)과 고객별 최근 구매한 날짜(x.max())와 차이값
- Frequency : 구매 빈도수
- Monetary : 총 구매 금액
rfm = df.groupby('CustomerID').agg({'InvoiceDate' : lambda x: (last_timestamp - x.max()).days,
'InvoiceNo' : 'count',
'TotalPrice' : 'sum'})
rfm.columns = ['Recency', 'Frequency', 'MonetaryValue']
rfm
- last_timestamp 모든 고객 통틀어서 맥스
- 고객별 최근 구매한 날짜(x.max())
rfm.hist(bins = 50) ;
- 한쪽에 고객이 치우쳐져 있어 몰려있는 부분 분석 어려움 -> 고르게 분포 되도록 분석해야 함
RFM 모형
- Scoring 기법: RFM의 요인을 각각 5등급으로 등간격으로 분류하는 방법
- 현재 개발된 RFM 모형은 크게 4가지로 분류 할 수 있다. 이 문서의 내용들은 정설이 아니며 신뢰하기 어려움을 전제로 참고
- 모델1. RFM 각 요소의 20% rule의 적용
- 모델2. 비율 척도에 의한 양적인 정도의 차이에 따른 등간격의 5등급 분류
- 모델3. 상하 20%를 제외한 등간격 척도에 의한 그룹 분류
- 모델4. 군집 분석에 의한 각 요소 별 5개의 그룹 분류 / 참고: RFM(위키백과)
- cut(): 히스토그램의 bins와 같은 역할, 같인 길이로 구간을 나눈다 => 절대평가, 예) 몇 점이상이면 A학점
- qcut(): 같은 개수로 구간을 나눈다. / qcut => 상대평가, 예) 상위 10명 A학점
- Recency 는 최근일수록 높은 스코어를 갖도록
- Frequency, MonetaryValue 는 값이 클 수록 높은 스코어를 갖도록
- qcut()으로 RFM 변수 만들기
r_labels = list(range(5, 0, -1))
f_labels = list(range(1, 6))
m_labels = list(range(1, 6))
cut_size = 5
r_cut = pd.qcut(rfm['Recency'], cut_size, labels = r_labels)
f_cut = pd.qcut(rfm['Frequency'], cut_size, labels = f_labels)
m_cut = pd.qcut(rfm['MonetaryValue'], cut_size, labels = m_labels)
rfm
-> 아직 변수 만들기 전
rfm = rfm.assign(R = r_cut, F = f_cut, M = m_cut)
rfm
-> assign을 사용하면 여러 변수를 한 번에 만들 수 있음
- RFM Segment
rfm["RFM_segment"] = rfm['R'].astype(str) + rfm['F'].astype(str) + rfm['M'].astype(str)
- RFM Score
rfm["RFM_score"] = rfm[['R', 'F', 'M']].sum(axis = 1)
rfm.head(5)
rfm.iloc[:, :-2].astype(float).hist(figsize = (10, 6), bins = 50) ;
-> 구간화를 통해 기존에 몰려 있던 데이터가 같은 비율로 나뉜 것을 알 수 있음
plt.figure(figsize=(20, 4))
plt.xticks(rotation=90)
sns.barplot(data = rfm.sort_values('RFM_segment'), x = 'RFM_segment', y = 'RFM_score')
- segment는 그냥 합쳐놓은 것 -> score는 실제 합계 => segment 111 이면 score 낮고 segment 555면 score높은 게 당연
-> 그냥 경향을보는
ax = plt.axes(projection='3d')
ax.scatter3D( rfm["R"], rfm["F"], rfm["M"])
ax = plt.axes(projection='3d')
ax.scatter3D(rfm["Recency"], rfm["Frequency"], rfm["MonetaryValue"])
-> 스케일 값 다르고 몰려있어서 구분하기 어려웠는데 -> rfm["R"], rfm["F"], rfm["M"] 해서 고르게, 보기 좋아짐
rfm.groupby('RFM_score').agg({"Recency": "mean",
"Frequency": "mean",
"MonetaryValue": ['mean', 'sum']}).style.format('{:,.0f}').background_gradient()
-> 문자열의 format 함수를 사용하여 소수점 아래는 표기하지 않도록({:,.0f}) 문자열 포맷을 지정
- qcut을 통한 고객군 나누기
- qcut 을 통해 3단계로 "silver", "gold", "platinum" 고객군을 나누기
labels = ["silver", "gold", "platinum"]
rfm['RFM_class'] = pd.qcut(rfm['RFM_score'], 3, labels)
rfm
sns.barplot(data=rfm, x="RFM_class", y="RFM_score")
sns.boxplot(data=rfm, x="RFM_class", y="RFM_score")
-> 이 시각화 목적은 실제 데이터 나누고 정리하는 코드 작성 때 그 작성한 코드가 잘 나뉘었는지 확인하기 위하여
- 'RFM_class' 별로 그룹화 -> "Recency", "Frequency" 의 평균을 구하기 -> "MonetaryValue"의 "mean", "sum", "count" 값을 구하기
rfm_c = rfm.groupby('RFM_class').agg({"Recency": "mean",
"Frequency": "mean",
"MonetaryValue": ['mean', 'sum', 'count']})
rfm_c.style.format('{:,.0f}').background_gradient()
- pairplot
- "RFM_class" 별로 분포를 시각화
sns.pairplot(data = rfm, hue = 'RFM_class')
- .corr() 함수로 변수간 상관관계(선형적 관계)를 분석
- 1에 가까울 수록 양의 상관관계, -1에 가까울 수록 음의 상관관계를 나타낸다
corr = rfm.corr()
corr
- 상관관계를 열분포 형태의 이미지로 보여주는 heatmap으로 데이터 시각화
mask = np.triu(np.ones_like(corr))
sns.heatmap(corr, cmap = 'coolwarm', vmin = -1, vmax = 1, annot = True, mask = mask)
- pairplot 그리는 이유
- RFM_class에 따라 RFM_score와 다른 변수들이 잘 나뉘었는지 확인할 수 있음
-> 상관계수를 통해 pairplot이 양의 상관관계인지 음의 상관관계인지 확인
-> 상관계수는 -1~1의 값이 나옴
- 코호트 분석
- 코호트분석은 분석 전에 데이터 세트의 데이터를 관련 그룹으로 나누는 일종의 행동분석이다
- 시간 패턴을 집단에 맞게 조정 가능
- 회사는 고객의 수명 주기 전반에 걸쳐 패턴을 명확하게 볼 수 있음
- 코호트 분석의 집단은 정의된 시간 범위 내에서 공통된 특성이나 경홈 공유
'AI SCHOOL > Python' 카테고리의 다른 글
[Python] 코딩도장 (0) | 2023.03.31 |
---|---|
[Python] 비즈니스 데이터 분석(Online Retail Data Set) (0) | 2023.03.07 |
[Python] 전국 신규 민간 아파트 분양가격 동향 (0) | 2023.02.09 |
[Python] Plotly / FinanceDataReader (1) | 2023.02.02 |
[Python] FinanceDataReader - 2 (0) | 2023.02.01 |