공부

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를 가진 고객은 거의 없음 → 상위 고객군 타겟팅 어려움