공부
LTV 고객 생애 가치(BG-NBD 모델) 공부
무른2
2025. 5. 31. 21:14
🍀LTV(Customer Lifetime Value)
✔️정의
한 명의 고객이 기업과의 관계에서 예상되는 총 수익
하나의 고객이 기업에게 얼마만큼의 돈을 벌어다 주는지 예측하는 지표
LTV를 높이는 것 = 충성 고객을 확보하고 유지하는 전략
✔️구성 요소
Recency | 마지막 구매 이후 얼마나 시간이 흘렀는가 |
Frequency | 일정 기간 내 몇 번 구매했는가 |
Monetary Value | 평균 구매 금액 |
Retention Rate | 고객이 계속 거래할 확률 |
Margin | 이익율(총수익이 아니라 순수익 기준으로도 사용) |
✔️단순 계산식
LTV = 평균 구매 금액 * 구매 빈도 * 고객 유지 기간
✔️BG/NBD + Gamma-Gamma 모델 기반 계산식
LTV = 예측 구매 횟수(BG/NBD) * 예측 평균 구매 금액(Gamma-Gamma)
1. BG/NBD 모델
고객의 재구매 빈도와 이탈 확률 예측을 위한 통계 모델
사용 함수: BetaGeoFitter
BG/NBD 모델 학습시 필요 데이터
Frequency | 첫 구매 이후 거래 횟수 |
Recency | 첫 구매부터 마지막 구매까지 걸린 시간 |
T | 첫 구매부터 관측 종료 시점까지 걸린 시간 |
2. Gamma-Gamma 모델
고객의 평균 구매 금액 예측
사용 함수: GammaGammaFitter
🍀요약
모델 | 설명 | 예측대상 |
LTV | 고객 전체 수익 예측 | 총가치 |
BG/NBD | 고객의 향후 구매 횟수 예측 | 재구매 가능성 |
Gamma-Gamma | 평균 구매 금액 예측 | 수익 규모 |
🍀실습코드(feat. chatgpt)
#데이터셋 생성
import pandas as pd
import numpy as np
from lifetimes.utils import summary_data_from_transaction_data
# 시드 고정
np.random.seed(42)
# 고객 수
n_customers = 1000
# 고객 ID
customer_ids = [f'CUST_{i}' for i in range(1, n_customers + 1)]
# 거래 수 생성
n_transactions = np.random.poisson(5, n_customers) # 고객당 평균 5회 구매
# 트랜잭션 데이터 생성
transaction_data = []
for cust_id, n_tx in zip(customer_ids, n_transactions):
for _ in range(n_tx):
purchase_date = pd.Timestamp('2021-01-01') + pd.to_timedelta(np.random.randint(0, 180), unit='D')
amount = np.round(np.random.gamma(2, 50), 2) # 평균 약 100 정도
transaction_data.append([cust_id, purchase_date, amount])
# 데이터프레임 생성
df = pd.DataFrame(transaction_data, columns=['CustomerID', 'InvoiceDate', 'MonetaryValue'])
#날짜 타입 변환
df['InvoiceDate'] = pd.to_datetime(df['InvoiceDate'])
df
# 고객별 요약 (Frequency, Recency, T, Monetary)
summary = summary_data_from_transaction_data(df, 'CustomerID', 'InvoiceDate', monetary_value_col='MonetaryValue')
summary.head()
from lifetimes import BetaGeoFitter
bgf = BetaGeoFitter()
bgf.fit(summary['frequency'], summary['recency'], summary['T'])
# 180일 이내 재구매 횟수 예측
summary['expected_purchases_6m'] = bgf.conditional_expected_number_of_purchases_up_to_time(
180,
summary['frequency'],
summary['recency'],
summary['T']
)
# 구매 횟수와 평균 구매 금액이 모두 양수인 고객만 사용
valid_ggf = (summary['frequency'] > 0) & (summary['monetary_value'] > 0)
summary_valid = summary[valid_ggf].copy()
# 모델 학습
from lifetimes import GammaGammaFitter
ggf = GammaGammaFitter()
ggf.fit(summary_valid['frequency'], summary_valid['monetary_value'])
# 예측값 계산 후 summary에 병합
summary.loc[valid_ggf, 'expected_avg_value'] = ggf.conditional_expected_average_profit(
summary_valid['frequency'],
summary_valid['monetary_value']
)
#LTV 계산(6개월 기준)
summary['expected_LTV_6m'] = summary['expected_purchases_6m'] * summary['expected_avg_value']
summary.sort_values(by='expected_LTV_6m', ascending=False).head(10)
#LTV 분포 시각화
plt.figure(figsize=(8,5))
plt.hist(summary['expected_LTV_6m'].dropna(), bins=30, color='lightgreen')
plt.title("Distribution of Predicted LTV (6 months)")
plt.xlabel("Expected LTV")
plt.ylabel("Number of Customers")
plt.grid(True)
plt.show()
✔️ 해석:
- 가로축 (Expected LTV): 각 고객이 앞으로 6개월간 가져올 것으로 예상되는 수익 (Lifetime Value)
- 세로축 (Number of Customers): 해당 LTV 값을 가진 고객 수
✔️인사이트:
- 대부분 고객의 LTV는 약 500~510 사이에 분포되어 있음
- 정규분포처럼 중앙에 몰려 있고 양쪽으로 퍼지는 모양
- 극단적으로 높은 LTV를 가진 고객은 거의 없음 → 상위 고객군 타겟팅 어려움