이미지 로딩 중...

구매 패턴 분석으로 고객 이해하기 완벽 가이드 - 슬라이드 1/9
A

AI Generated

2025. 11. 15. · 2 Views

구매 패턴 분석으로 고객 이해하기 완벽 가이드

실제 구매 데이터를 분석하여 고객의 행동 패턴을 발견하는 방법을 배웁니다. Python과 Polars를 활용한 빠르고 효율적인 데이터 분석 기법을 실무 예제와 함께 소개합니다.


목차

  1. RFM 분석 - 고객 가치 평가의 핵심
  2. 상품 연관성 분석 - 장바구니 분석
  3. 고객 세그먼테이션 - K-Means 클러스터링
  4. 시계열 구매 패턴 - 트렌드와 계절성 분석
  5. 고객 생애 가치(CLV) 예측
  6. 상품 추천 시스템 - 협업 필터링
  7. 이탈 예측 - 위험 고객 조기 발견
  8. 가격 민감도 분석 - 최적 가격 찾기

1. RFM 분석 - 고객 가치 평가의 핵심

시작하며

여러분이 온라인 쇼핑몰을 운영하는데, 수만 명의 고객 중 누구에게 마케팅 비용을 집중해야 할지 고민해본 적 있나요? 모든 고객에게 동일한 프로모션을 보내면 비용만 낭비되고, 그렇다고 감으로 선택하자니 불안합니다.

이런 문제는 실제 개발 현장에서 자주 발생합니다. 데이터는 쌓여있지만 어떤 고객이 진짜 중요한 고객인지, 어떤 고객이 이탈 위험이 있는지 파악하기 어렵습니다.

결과적으로 마케팅 ROI가 낮아지고 고객 관리가 비효율적으로 이루어집니다. 바로 이럴 때 필요한 것이 RFM 분석입니다.

최근성(Recency), 빈도(Frequency), 금액(Monetary)이라는 세 가지 지표만으로 고객을 체계적으로 분류하고 각 그룹에 맞는 전략을 수립할 수 있습니다.

개요

간단히 말해서, RFM 분석은 고객의 구매 행동을 세 가지 핵심 지표로 평가하는 분석 기법입니다. 실무에서 고객 세그먼테이션은 매우 중요합니다.

최근에 구매한 고객은 다시 구매할 가능성이 높고, 자주 구매하는 고객은 충성도가 높으며, 많은 금액을 쓰는 고객은 비즈니스에 큰 가치를 제공합니다. 예를 들어, 최근 1주일 내에 3번 구매하고 총 100만원을 쓴 고객과 1년 전에 1번 구매하고 1만원을 쓴 고객은 완전히 다른 전략으로 접근해야 합니다.

기존에는 Excel로 수작업으로 계산하거나 SQL로 복잡한 쿼리를 작성했다면, 이제는 Polars를 사용하여 몇 줄의 코드로 빠르게 분석할 수 있습니다. RFM 분석의 핵심 특징은 첫째, 구현이 간단하면서도 효과적이라는 점, 둘째, 모든 산업에 적용 가능하다는 점, 셋째, 실행 가능한 인사이트를 즉시 제공한다는 점입니다.

이러한 특징들이 RFM을 가장 널리 사용되는 고객 분석 기법으로 만들었습니다.

코드 예제

import polars as pl
from datetime import datetime, timedelta

# 구매 데이터 로드
purchases = pl.read_csv("purchases.csv")

# 분석 기준일 설정 (보통 오늘 날짜)
analysis_date = datetime(2024, 1, 1)

# RFM 계산
rfm = purchases.group_by("customer_id").agg([
    # Recency: 마지막 구매일로부터 경과 일수
    ((analysis_date - pl.col("purchase_date").max()).dt.days()).alias("recency"),
    # Frequency: 총 구매 횟수
    pl.col("order_id").n_unique().alias("frequency"),
    # Monetary: 총 구매 금액
    pl.col("amount").sum().alias("monetary")
])

설명

이것이 하는 일: 구매 데이터에서 각 고객별로 마지막 구매가 얼마나 최근인지, 얼마나 자주 구매했는지, 총 얼마를 지출했는지를 계산합니다. 첫 번째로, 분석 기준일을 설정합니다.

보통은 오늘 날짜나 데이터의 마지막 날짜를 사용합니다. 이 기준일로부터 각 고객의 마지막 구매일까지의 일수를 계산하여 Recency를 구합니다.

예를 들어, 기준일이 1월 1일이고 고객의 마지막 구매일이 12월 25일이라면 Recency는 7일이 됩니다. 그 다음으로, group_by로 고객별로 그룹화한 후 agg 함수로 세 가지 지표를 동시에 계산합니다.

Polars의 강력한 표현식 시스템 덕분에 복잡한 계산도 간결하게 표현할 수 있습니다. Frequency는 고유한 주문 건수를 세고, Monetary는 전체 구매 금액을 합산합니다.

마지막으로, 결과 데이터프레임에는 각 고객의 ID와 함께 세 가지 지표가 담깁니다. 이 값들을 기반으로 고객을 세그먼트로 나누거나 점수를 부여할 수 있습니다.

여러분이 이 코드를 사용하면 수십만 건의 거래 데이터를 몇 초 만에 분석할 수 있습니다. Polars는 Pandas보다 5배에서 10배 빠른 성능을 제공하므로 대용량 데이터 처리에 특히 유용합니다.

또한 메모리 효율성이 뛰어나 제한된 리소스 환경에서도 안정적으로 작동합니다.

실전 팁

💡 Recency는 낮을수록, Frequency와 Monetary는 높을수록 좋은 고객입니다. 각 지표를 5분위나 10분위로 나누어 점수를 부여하면 555점 고객(최상위)부터 111점 고객(최하위)까지 명확하게 분류할 수 있습니다.

💡 날짜 컬럼이 문자열로 저장되어 있다면 반드시 pl.col("purchase_date").str.strptime(pl.Date, "%Y-%m-%d")로 변환하세요. 그렇지 않으면 날짜 계산이 불가능하거나 잘못된 결과가 나옵니다.

💡 이상치 처리가 중요합니다. 한 고객이 실수로 1000만원을 결제했다가 환불한 경우, Monetary 값이 왜곡될 수 있으므로 환불 데이터는 제외하거나 별도로 처리하세요.

💡 산업별로 기준이 다릅니다. 식료품 업계에서는 Recency 7일이 양호하지만, 가구 업계에서는 180일도 정상입니다. 여러분의 비즈니스 특성에 맞게 기준을 조정하세요.

💡 RFM 점수가 낮아지는 추세를 보이는 고객을 조기에 발견하면 이탈 방지 캠페인을 실행할 수 있습니다. 매월 RFM을 계산하여 변화를 추적하세요.


2. 상품 연관성 분석 - 장바구니 분석

시작하며

여러분이 이커머스 사이트에서 "이 상품을 구매한 고객은 이런 상품도 함께 구매했습니다"라는 추천을 본 적 있나요? 아마존이 매출의 35%를 이런 추천 시스템에서 얻는다는 사실을 알고 계신가요?

이런 추천은 우연이 아니라 구매 패턴 분석의 결과입니다. 어떤 상품들이 함께 구매되는지 파악하면 교차 판매, 상품 배치, 프로모션 전략을 효과적으로 수립할 수 있습니다.

하지만 수천 개의 상품과 수만 건의 거래에서 의미 있는 패턴을 찾는 것은 쉽지 않습니다. 바로 이럴 때 필요한 것이 장바구니 분석입니다.

특정 상품이 함께 구매되는 빈도를 계산하여 연관 규칙을 발견하고, 이를 비즈니스 전략에 활용할 수 있습니다.

개요

간단히 말해서, 장바구니 분석은 동일한 거래에서 함께 구매된 상품들의 패턴을 찾는 기법입니다. 실무에서 이 분석은 추천 시스템의 기초가 됩니다.

맥주와 기저귀가 함께 판매된다는 유명한 사례처럼, 언뜻 관련 없어 보이는 상품들의 연관성을 발견할 수 있습니다. 예를 들어, 노트북을 구매하는 고객의 80%가 마우스도 함께 구매한다면, 노트북 상세 페이지에서 마우스를 추천하거나 번들 할인을 제공할 수 있습니다.

기존에는 복잡한 통계 패키지나 데이터 마이닝 툴을 사용했다면, 이제는 Polars의 조인과 집계 기능만으로도 효과적인 분석이 가능합니다. 핵심 지표는 지지도(Support), 신뢰도(Confidence), 향상도(Lift)입니다.

지지도는 두 상품이 함께 나타나는 빈도, 신뢰도는 A를 구매했을 때 B도 구매할 확률, 향상도는 우연보다 얼마나 더 자주 함께 구매되는지를 나타냅니다. 이러한 지표들이 어떤 연관 규칙이 실제로 의미 있는지 판단하는 기준이 됩니다.

코드 예제

import polars as pl

# 주문 상세 데이터 로드 (주문ID, 상품ID)
order_items = pl.read_csv("order_items.csv")

# 자기 조인으로 같은 주문 내 상품 쌍 생성
product_pairs = order_items.join(
    order_items, on="order_id", suffix="_pair"
).filter(
    # 자기 자신과의 쌍 제거
    pl.col("product_id") < pl.col("product_id_pair")
)

# 상품 쌍별 빈도 계산
pair_frequency = product_pairs.group_by(
    ["product_id", "product_id_pair"]
).agg(
    pl.col("order_id").n_unique().alias("frequency")
).sort("frequency", descending=True)

설명

이것이 하는 일: 동일한 주문에 포함된 상품들의 조합을 찾아내고, 각 조합이 얼마나 자주 나타나는지 계산합니다. 첫 번째로, 주문 상세 데이터를 자기 자신과 조인합니다.

같은 order_id를 키로 조인하면, 한 주문 내의 모든 상품 조합이 생성됩니다. 예를 들어, 주문 A에 상품 1, 2, 3이 있다면 (1,2), (1,3), (2,3) 같은 쌍들이 만들어집니다.

그 다음으로, filter를 사용하여 불필요한 쌍을 제거합니다. product_id < product_id_pair 조건으로 (1,2)와 (2,1)처럼 중복되는 쌍과 (1,1)처럼 자기 자신과의 쌍을 제거합니다.

이렇게 하면 각 조합이 정확히 한 번씩만 나타나게 됩니다. 세 번째로, group_by로 상품 쌍별로 그룹화하고 해당 쌍이 나타난 주문 건수를 셉니다.

n_unique를 사용하는 이유는 같은 주문에 동일한 상품이 여러 개 있을 수 있기 때문입니다. 마지막으로 빈도순으로 정렬하여 가장 자주 함께 구매되는 상품 쌍을 상위에 배치합니다.

여러분이 이 코드를 사용하면 수백만 건의 거래에서도 빠르게 상품 연관성을 발견할 수 있습니다. 결과를 기반으로 "함께 구매하면 좋은 상품" 추천, 묶음 할인 기획, 매장 내 상품 배치 최적화 등 다양한 전략을 수립할 수 있습니다.

또한 계절별, 시간대별로 분석하면 더 정교한 인사이트를 얻을 수 있습니다.

실전 팁

💡 대용량 데이터에서는 최소 지지도를 설정하세요. 전체 주문의 0.1% 미만으로 나타나는 쌍은 우연일 가능성이 높으므로 filter(pl.col("frequency") > total_orders * 0.001)로 필터링하세요.

💡 향상도(Lift)를 계산하면 더 정확합니다. 단순 빈도가 높아도 두 상품이 모두 인기 상품이라 우연히 많이 나타날 수 있습니다. Lift = P(A∩B) / (P(A) * P(B))로 계산하여 1보다 큰 값만 의미 있는 연관성으로 봅니다.

💡 카테고리별로 분석하세요. 전자제품끼리, 식품끼리 묶는 것보다 다른 카테고리 간 연관성이 더 흥미로운 인사이트를 제공할 수 있습니다.

💡 시간 차원을 고려하세요. 크리스마스 시즌의 구매 패턴과 평상시의 패턴은 다릅니다. with_columns(pl.col("order_date").dt.month().alias("month"))를 추가하여 계절별 분석을 하세요.

💡 네거티브 연관성도 중요합니다. 함께 구매되지 않는 상품 쌍을 찾으면 경쟁 상품이나 대체재를 파악할 수 있습니다.


3. 고객 세그먼테이션 - K-Means 클러스터링

시작하며

여러분의 고객 데이터베이스에 10만 명의 고객이 있다면, 이들을 어떻게 그룹화하여 관리하시겠습니까? 단순히 나이나 성별로만 나누면 너무 단순하고, 수작업으로 세분화하자니 객관성이 떨어집니다.

이런 문제는 모든 데이터 기반 비즈니스에서 발생합니다. 고객마다 구매 패턴, 선호도, 가치가 다르지만, 이를 체계적으로 분류하지 못하면 일대일 마케팅도 불가능하고 리소스 낭비만 발생합니다.

결국 모든 고객에게 동일한 메시지를 보내거나, 감에 의존한 잘못된 타게팅을 하게 됩니다. 바로 이럴 때 필요한 것이 K-Means 클러스터링입니다.

머신러닝 알고리즘이 자동으로 유사한 특성을 가진 고객들을 그룹화해주므로, 객관적이고 데이터 기반의 세그먼테이션이 가능합니다.

개요

간단히 말해서, K-Means는 데이터를 K개의 그룹으로 자동 분류하는 비지도 학습 알고리즘입니다. 실무에서 고객 세그먼테이션은 마케팅의 출발점입니다.

같은 특성을 가진 고객 그룹을 찾으면 각 그룹에 최적화된 메시지, 상품, 가격 전략을 수립할 수 있습니다. 예를 들어, 고빈도-저금액 그룹과 저빈도-고금액 그룹은 완전히 다른 접근이 필요합니다.

K-Means는 RFM 점수, 평균 구매액, 선호 카테고리 등 여러 변수를 동시에 고려하여 자연스러운 그룹을 찾아냅니다. 기존에는 주관적인 기준으로 그룹을 나누거나 복잡한 통계 분석이 필요했다면, 이제는 scikit-learn과 Polars를 조합하여 쉽고 빠르게 클러스터링할 수 있습니다.

K-Means의 핵심은 각 데이터 포인트를 가장 가까운 중심점(centroid)에 할당하고, 중심점을 재계산하는 과정을 반복한다는 것입니다. 보통 10~20회 반복하면 안정적인 그룹이 형성됩니다.

이 알고리즘은 빠르고 확장성이 좋아 수백만 고객도 처리할 수 있다는 장점이 있습니다.

코드 예제

import polars as pl
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

# RFM 데이터 준비 (앞서 계산한 결과 사용)
rfm_array = rfm.select(["recency", "frequency", "monetary"]).to_numpy()

# 스케일링 (각 변수의 단위가 다르므로 필수)
scaler = StandardScaler()
rfm_scaled = scaler.fit_transform(rfm_array)

# K-Means 클러스터링 (5개 그룹)
kmeans = KMeans(n_clusters=5, random_state=42, n_init=10)
clusters = kmeans.fit_predict(rfm_scaled)

# 결과를 원본 데이터에 추가
rfm_with_cluster = rfm.with_columns(
    pl.Series("cluster", clusters)
)

설명

이것이 하는 일: 고객의 RFM 값을 기반으로 유사한 패턴을 가진 고객들을 5개 그룹으로 자동 분류합니다. 첫 번째로, Polars 데이터프레임에서 분석에 사용할 컬럼들만 선택하여 NumPy 배열로 변환합니다.

scikit-learn은 NumPy 배열을 입력으로 받기 때문입니다. to_numpy()를 사용하면 Polars의 빠른 성능을 유지하면서도 머신러닝 라이브러리와 호환됩니다.

그 다음으로, StandardScaler로 데이터를 정규화합니다. 이 단계가 매우 중요한데, Recency는 0365일, Frequency는 1100회, Monetary는 1000~1000000원처럼 단위와 범위가 완전히 다르기 때문입니다.

스케일링 없이 클러스터링하면 큰 값을 가진 변수(Monetary)가 결과를 지배하게 됩니다. StandardScaler는 각 변수를 평균 0, 표준편차 1로 변환합니다.

세 번째로, KMeans 객체를 생성하고 fit_predict로 클러스터링을 수행합니다. n_clusters=5는 5개 그룹으로 나눈다는 의미이고, random_state=42는 재현성을 위한 시드값, n_init=10은 다른 초기값으로 10번 실행하여 최적의 결과를 선택한다는 뜻입니다.

반환값은 각 고객이 속한 클러스터 번호(0~4)의 배열입니다. 마지막으로, 클러스터 레이블을 원본 Polars 데이터프레임에 새 컬럼으로 추가합니다.

이제 각 고객은 cluster 0부터 4까지의 레이블을 가지며, 같은 레이블을 가진 고객들은 유사한 구매 패턴을 보입니다. 여러분이 이 코드를 사용하면 주관성을 배제하고 데이터가 말하는 자연스러운 고객 그룹을 발견할 수 있습니다.

각 클러스터의 평균 RFM 값을 계산하여 "VIP 고객", "잠재 이탈 고객", "신규 고객" 같은 의미 있는 이름을 부여하고, 맞춤형 전략을 수립할 수 있습니다. 또한 새로운 고객이 가입하면 즉시 어느 세그먼트에 속하는지 예측할 수 있습니다.

실전 팁

💡 최적의 K 값 찾기: Elbow Method를 사용하세요. k를 2부터 10까지 변경하며 inertia_(군집 내 분산)를 계산하고, 감소폭이 급격히 줄어드는 지점(팔꿈치)이 최적 클러스터 수입니다.

💡 스케일링은 선택이 아닌 필수입니다. 한 번이라도 스케일링 없이 실행해보면 Monetary만으로 그룹이 나뉘는 것을 확인할 수 있습니다. 반드시 StandardScaler나 MinMaxScaler를 적용하세요.

💡 클러스터 프로파일링을 하세요. rfm_with_cluster.group_by("cluster").agg([pl.col("recency").mean(), ...])로 각 그룹의 평균값을 계산하면 "클러스터 0은 최근 구매, 고빈도, 고금액의 VIP 그룹"처럼 해석할 수 있습니다.

💡 이상치 제거가 중요합니다. 전체 고객의 0.1%가 평균의 100배를 소비한다면 이들이 별도의 클러스터를 형성하거나 다른 그룹을 왜곡할 수 있습니다. 사전에 pl.col("monetary").quantile(0.99)로 상위 1%를 제거하거나 별도 처리하세요.

💡 시계열로 추적하세요. 매월 클러스터링을 수행하고 고객의 클러스터 이동을 추적하면 "VIP에서 일반으로 하향" 같은 변화를 조기에 감지할 수 있습니다.


4. 시계열 구매 패턴 - 트렌드와 계절성 분석

시작하며

여러분의 매출이 작년 같은 달에 비해 20% 증가했다면, 이게 정말 좋은 신호일까요? 아니면 단지 계절적 요인일까요?

12월에 매출이 급증했다고 해서 비즈니스가 잘 되고 있다고 판단할 수 있을까요? 이런 질문은 실제 데이터 분석에서 매우 중요합니다.

단순히 절대값만 보면 계절성, 요일 효과, 일회성 이벤트의 영향을 구분할 수 없습니다. 크리스마스 시즌의 매출 증가는 당연한 것이고, 진짜 중요한 것은 작년 크리스마스보다 나아졌는지, 트렌드가 상승 중인지입니다.

바로 이럴 때 필요한 것이 시계열 분석입니다. 트렌드(장기적 방향), 계절성(주기적 패턴), 잔차(우연적 변동)를 분리하여 진짜 성장과 예측 가능한 변동을 구분할 수 있습니다.

개요

간단히 말해서, 시계열 분석은 시간 순서를 가진 데이터에서 패턴을 발견하고 미래를 예측하는 기법입니다. 실무에서 시계열 분석은 수요 예측, 재고 관리, 예산 계획의 핵심입니다.

매주 월요일에 주문이 급증한다는 패턴을 알면 월요일 새벽에 재고를 미리 준비할 수 있습니다. 매년 78월에 특정 상품의 수요가 2배로 증가한다면 56월에 미리 발주해야 합니다.

예를 들어, 아이스크림 매출은 여름에 높지만, 작년 여름보다 낮다면 문제가 있는 것입니다. 기존에는 복잡한 통계 모델이나 R의 패키지를 사용했다면, 이제는 Polars의 윈도우 함수와 간단한 Python 라이브러리로도 효과적인 분석이 가능합니다.

핵심 개념은 시계열 분해(decomposition)입니다. 관측값 = 트렌드 + 계절성 + 잔차로 분리하면, 장기적으로 성장 중인지(트렌드), 언제 수요가 높은지(계절성), 예상치 못한 변화가 있는지(잔차)를 명확히 파악할 수 있습니다.

이러한 분해가 데이터 기반 의사결정의 기초가 됩니다.

코드 예제

import polars as pl

# 일별 매출 데이터 로드 및 날짜순 정렬
daily_sales = pl.read_csv("daily_sales.csv").sort("date")

# 이동 평균으로 트렌드 파악 (7일)
sales_with_trend = daily_sales.with_columns([
    pl.col("sales").rolling_mean(window_size=7).alias("trend_7d"),
    pl.col("sales").rolling_mean(window_size=30).alias("trend_30d")
])

# 요일별 평균 (계절성 - 주간 패턴)
weekday_pattern = daily_sales.with_columns(
    pl.col("date").dt.weekday().alias("weekday")
).group_by("weekday").agg(
    pl.col("sales").mean().alias("avg_sales_by_weekday")
)

# 전년 동월 대비 성장률
yoy_growth = daily_sales.with_columns(
    pl.col("date").dt.year().alias("year"),
    pl.col("date").dt.month().alias("month")
).group_by(["year", "month"]).agg(
    pl.col("sales").sum().alias("monthly_sales")
).sort(["month", "year"]).with_columns(
    pl.col("monthly_sales").pct_change(12).alias("yoy_growth")
)

설명

이것이 하는 일: 일별 매출 데이터에서 장기 트렌드, 요일별 패턴, 전년 대비 성장률을 계산하여 다양한 시간 차원에서 패턴을 파악합니다. 첫 번째로, rolling_mean으로 이동 평균을 계산합니다.

7일 이동 평균은 요일 효과를 제거하고 주간 트렌드를 보여주고, 30일 이동 평균은 월간 트렌드를 보여줍니다. 예를 들어, 매일 매출이 등락을 반복해도 7일 평균선이 상승한다면 전반적으로 좋아지고 있는 것입니다.

이동 평균은 노이즈를 제거하여 진짜 방향을 보여주는 강력한 도구입니다. 그 다음으로, 요일별 평균을 계산하여 주간 계절성을 파악합니다.

dt.weekday()로 0(월요일)부터 6(일요일)까지의 숫자를 추출하고, 각 요일별로 평균 매출을 계산합니다. 만약 일요일이 평일보다 50% 높다면, 이는 주말 쇼핑 패턴이 뚜렷하다는 뜻입니다.

이런 패턴을 알면 요일별로 다른 프로모션 전략을 세울 수 있습니다. 세 번째로, 전년 동월 대비 성장률(Year-over-Year Growth)을 계산합니다.

먼저 연도와 월을 추출하고, 월별 매출을 집계한 후, pct_change(12)로 12개월 전 대비 변화율을 구합니다. 12를 인자로 주는 이유는 1년이 12개월이기 때문입니다.

2024년 1월과 2023년 1월을 비교하여 계절성의 영향 없이 순수한 성장을 측정합니다. 마지막으로, 이 세 가지 분석을 종합하면 현재 비즈니스의 건강 상태를 정확히 진단할 수 있습니다.

트렌드가 상승 중이고, 계절성 패턴이 예측 가능하며, YoY 성장률이 양수라면 비즈니스가 잘 되고 있는 것입니다. 여러분이 이 코드를 사용하면 단순한 숫자 나열이 아닌 의미 있는 인사이트를 얻을 수 있습니다.

예를 들어, "이번 주 매출이 저번 주보다 10% 낮지만, 30일 트렌드는 여전히 상승 중이고 작년 같은 주보다는 15% 높으므로 일시적 변동일 뿐"이라는 정확한 판단이 가능합니다. 또한 미래 수요를 예측하여 재고와 인력을 최적화할 수 있습니다.

실전 팁

💡 이동 평균의 윈도우 크기는 주기에 맞춰 선택하세요. 주간 패턴을 제거하려면 7일, 월간은 30일, 분기는 90일입니다. 짝수보다는 홀수 크기를 사용하면 중심값이 명확합니다.

💡 결측치 처리가 중요합니다. rolling_mean은 기본적으로 null이 하나라도 있으면 null을 반환하므로 .fill_null(strategy="forward")나 .fill_null(0)로 먼저 처리하세요.

💡 이상치가 트렌드를 왜곡합니다. 블랙프라이데이 같은 특별 이벤트 날은 제외하거나 별도 분석하세요. filter(pl.col("is_special_event") == False)로 걸러내면 정상적인 패턴만 볼 수 있습니다.

💡 여러 수준의 계절성을 고려하세요. 요일별, 주별, 월별, 분기별 패턴이 모두 다를 수 있습니다. dt.quarter()로 분기를 추출하면 연말 쇼핑 시즌(Q4) 같은 분기별 패턴도 파악 가능합니다.

💡 지수 이동 평균(EMA)을 사용하면 최근 데이터에 더 큰 가중치를 줄 수 있습니다. ewm_mean(span=7)을 사용하면 최신 트렌드를 더 민감하게 포착합니다.


5. 고객 생애 가치(CLV) 예측

시작하며

여러분이 신규 고객 한 명을 유치하는 데 1만원의 마케팅 비용을 썼다면, 이게 합리적인 투자일까요? 그 고객이 향후 얼마나 가치를 제공할지 모른다면 판단할 수 없습니다.

이런 문제는 모든 비즈니스에서 핵심적입니다. 고객 획득 비용(CAC)이 증가하는 상황에서, 각 고객이 평생 동안 얼마나 수익을 가져다줄지 예측하지 못하면 마케팅 예산을 효율적으로 배분할 수 없습니다.

결과적으로 수익성 없는 고객에게 과도하게 투자하거나, 가치 있는 고객을 놓치게 됩니다. 바로 이럴 때 필요한 것이 고객 생애 가치(Customer Lifetime Value) 예측입니다.

과거 구매 데이터를 기반으로 각 고객이 미래에 가져다줄 총 수익을 추정하여, 데이터 기반의 마케팅 투자 결정을 내릴 수 있습니다.

개요

간단히 말해서, CLV는 한 고객이 관계를 유지하는 동안 기업에게 제공할 것으로 예상되는 총 수익의 현재 가치입니다. 실무에서 CLV 예측은 마케팅 ROI 계산의 핵심입니다.

예상 CLV가 10만원인 고객이라면 1만원의 획득 비용은 합리적이지만, 예상 CLV가 5천원인 고객이라면 손해입니다. 또한 고객을 가치별로 계층화하여 VIP는 프리미엄 서비스를 제공하고 저가치 고객은 자동화된 관리를 하는 등 차별화된 전략을 수립할 수 있습니다.

예를 들어, 구독 서비스에서 평균 3개월 후 이탈하는 고객과 3년간 유지되는 고객은 60배의 가치 차이가 있습니다. 기존에는 복잡한 확률 모델이나 머신러닝이 필요했다면, 이제는 간단한 역사적 평균 방법으로도 실용적인 CLV를 계산할 수 있습니다.

핵심 공식은 CLV = (평균 구매액 × 구매 빈도 × 고객 수명) - 획득 비용입니다. 더 정교한 방법으로는 각 시점의 수익을 할인율로 현재 가치로 환산하는 방법이 있습니다.

또한 이탈 확률을 고려하면 더 현실적인 예측이 가능합니다. 이러한 계산이 고객별로 투자할 최대 금액을 결정하는 기준이 됩니다.

코드 예제

import polars as pl
import numpy as np

# 고객별 구매 이력 집계
customer_metrics = purchases.group_by("customer_id").agg([
    pl.col("amount").mean().alias("avg_purchase_value"),
    pl.col("order_id").n_unique().alias("purchase_count"),
    (pl.col("purchase_date").max() - pl.col("purchase_date").min()).dt.days().alias("customer_age_days"),
    pl.col("purchase_date").min().alias("first_purchase")
])

# CLV 계산 (간단한 역사적 방법)
clv = customer_metrics.with_columns([
    # 구매 빈도 (년 단위)
    (pl.col("purchase_count") / (pl.col("customer_age_days") / 365)).alias("annual_frequency"),
    # 예상 고객 수명 (년) - 업계별로 조정 필요
    pl.lit(3.0).alias("expected_lifetime_years")
]).with_columns([
    # CLV = 평균 구매액 × 연간 빈도 × 예상 수명
    (pl.col("avg_purchase_value") * pl.col("annual_frequency") * pl.col("expected_lifetime_years")).alias("predicted_clv")
])

설명

이것이 하는 일: 각 고객의 과거 구매 패턴을 분석하여 향후 몇 년간 얼마나 가치를 제공할지 금액으로 환산합니다. 첫 번째로, 고객별로 평균 구매액, 총 구매 횟수, 첫 구매일부터 마지막 구매일까지의 기간(고객 연령)을 계산합니다.

평균 구매액은 한 번 구매할 때 평균적으로 얼마를 쓰는지, 구매 횟수는 얼마나 자주 오는 충성 고객인지를 나타냅니다. 고객 연령은 관계 기간을 의미하며, 이를 통해 구매 빈도를 계산할 수 있습니다.

그 다음으로, 연간 구매 빈도를 계산합니다. 예를 들어, 고객이 730일(2년) 동안 10번 구매했다면 연간 빈도는 10 / (730/365) = 5회입니다.

이는 1년에 평균 5번 구매한다는 뜻으로, 미래 예측의 기준이 됩니다. 또한 예상 고객 수명을 설정하는데, 이는 업계와 비즈니스 모델에 따라 다릅니다.

구독 서비스는 35년, 전자제품은 12년 정도가 일반적입니다. 세 번째로, 최종 CLV를 계산합니다.

한 번에 평균 5만원을 쓰고(avg_purchase_value), 1년에 4번 구매하며(annual_frequency), 3년간 관계를 유지할 것으로 예상되면(expected_lifetime_years), CLV = 5만원 × 4 × 3 = 60만원입니다. 이는 이 고객이 향후 3년간 제공할 것으로 예상되는 총 수익입니다.

마지막으로, 이 CLV 값을 기준으로 마케팅 의사결정을 내립니다. CLV가 60만원이라면 최대 6만원(10% 규칙)까지 획득 비용을 쓸 수 있고, 연간 6만원까지 유지 비용을 투자할 수 있습니다.

여러분이 이 코드를 사용하면 "이 고객에게 얼마까지 투자할 수 있는가?"라는 질문에 명확한 답을 얻을 수 있습니다. 신규 고객 캠페인의 목표 CAC를 설정하고, 고객별로 차별화된 혜택을 제공하며, 이탈 방지에 투자할 최대 금액을 결정할 수 있습니다.

또한 CLV가 낮아지는 추세를 조기에 발견하여 대응할 수 있습니다.

실전 팁

💡 신규 고객은 데이터가 부족합니다. customer_age_days가 30일 미만인 고객은 빈도 계산이 부정확하므로 filter(pl.col("customer_age_days") >= 90)로 최소 3개월 이상 데이터가 있는 고객만 분석하세요.

💡 할인율을 적용하면 더 정확합니다. 3년 후의 10만원은 현재 가치로 약 7.5만원(연 10% 할인율 가정)입니다. (1 + discount_rate) ** -years로 미래 가치를 현재 가치로 변환하세요.

💡 이탈 확률을 반영하세요. 모든 고객이 3년을 유지하는 것은 아닙니다. 역사적 이탈률이 연 30%라면 1년 후 70%, 2년 후 49%, 3년 후 34%만 남으므로 각 연도의 수익에 생존 확률을 곱해야 합니다.

💡 세그먼트별로 다르게 계산하세요. VIP 고객과 일반 고객의 예상 수명이 다릅니다. 클러스터별로 expected_lifetime_years를 다르게 설정하면 더 정교한 예측이 가능합니다.

💡 CLV 대비 CAC 비율을 추적하세요. 일반적으로 CLV/CAC 비율이 3:1 이상이면 건강한 상태입니다. 1:1에 가까우면 마케팅 효율성을 개선해야 합니다.


6. 상품 추천 시스템 - 협업 필터링

시작하며

여러분이 넷플릭스에서 영화를 볼 때, "당신을 위한 추천" 목록이 신기하게도 취향에 딱 맞는 경험을 한 적 있나요? 아마존에서 "이 상품을 본 고객이 함께 본 상품" 추천이 실제로 구매로 이어진 적은요?

이런 추천은 우연이 아니라 협업 필터링이라는 기법의 결과입니다. 비슷한 취향을 가진 다른 고객들의 구매 패턴을 분석하여 여러분이 좋아할 만한 상품을 예측하는 것입니다.

이커머스에서 추천 시스템은 매출의 20~40%를 차지할 정도로 중요하지만, 복잡해 보여서 많은 개발자들이 시도조차 하지 않습니다. 바로 이럴 때 필요한 것이 간단한 협업 필터링 구현입니다.

Polars와 기본적인 유사도 계산만으로도 효과적인 추천 시스템을 만들 수 있습니다.

개요

간단히 말해서, 협업 필터링은 "당신과 비슷한 사람들이 좋아한 것을 당신도 좋아할 것"이라는 원리를 사용하는 추천 기법입니다. 실무에서 추천 시스템은 고객 경험과 매출 모두를 향상시킵니다.

고객은 수천 개 상품 중에서 일일이 찾는 수고를 덜고, 기업은 교차 판매와 객단가 상승을 달성합니다. 예를 들어, 고객 A가 상품 1, 2, 3을 구매하고, 고객 B가 상품 1, 2, 4를 구매했다면, A에게는 상품 4를, B에게는 상품 3을 추천할 수 있습니다.

두 고객의 구매 패턴이 2/3 일치하므로 서로의 선택이 좋은 예측 지표가 됩니다. 기존에는 복잡한 행렬 분해나 딥러닝 모델이 필요했다면, 이제는 사용자 기반 또는 아이템 기반의 간단한 협업 필터링으로도 충분한 성능을 얻을 수 있습니다.

핵심 개념은 유사도 계산입니다. 코사인 유사도나 자카드 유사도를 사용하여 고객 간 또는 상품 간 유사성을 0~1 사이의 점수로 계산합니다.

유사도가 높은 고객들이 공통으로 선택한 아이템, 또는 이미 구매한 상품과 유사한 상품을 추천하면 됩니다. 이러한 방법이 복잡한 알고리즘 없이도 놀라운 추천 정확도를 제공합니다.

코드 예제

import polars as pl
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np

# 고객-상품 구매 매트릭스 생성
purchase_matrix = purchases.pivot(
    index="customer_id",
    columns="product_id",
    values="order_id",
    aggregate_function="count"
).fill_null(0)

# NumPy 배열로 변환 (고객 ID 제외)
customer_ids = purchase_matrix.select("customer_id").to_series()
matrix_values = purchase_matrix.drop("customer_id").to_numpy()

# 고객 간 유사도 계산 (코사인 유사도)
similarity_matrix = cosine_similarity(matrix_values)

# 특정 고객(예: customer_id=1)에게 추천
target_idx = customer_ids.to_list().index(1)
similar_customers = np.argsort(similarity_matrix[target_idx])[::-1][1:6]  # 상위 5명

# 유사 고객들이 구매했지만 타겟 고객은 안 산 상품 찾기
target_purchases = set(purchase_matrix.row(target_idx)[1:])
recommendations = []
for sim_idx in similar_customers:
    sim_purchases = set(purchase_matrix.row(sim_idx)[1:])
    recommendations.extend(sim_purchases - target_purchases)

설명

이것이 하는 일: 각 고객이 어떤 상품을 구매했는지를 매트릭스로 만들고, 비슷한 구매 패턴을 가진 고객들을 찾아 그들이 산 상품을 추천합니다. 첫 번째로, pivot 함수로 고객-상품 매트릭스를 생성합니다.

행은 고객, 열은 상품이며, 각 셀의 값은 구매 여부(1 또는 0)입니다. 예를 들어, 고객 A의 행을 보면 [1, 1, 0, 1, 0...]처럼 상품 1, 2, 4를 구매했다는 것을 알 수 있습니다.

fill_null(0)로 구매하지 않은 상품은 0으로 채웁니다. 그 다음으로, 이 매트릭스를 NumPy 배열로 변환하여 scikit-learn의 cosine_similarity 함수에 입력합니다.

코사인 유사도는 두 벡터 간의 각도를 측정하여 방향이 얼마나 비슷한지 계산합니다. 결과는 N×N 크기의 유사도 행렬로, 각 고객 쌍의 유사도가 0~1 사이의 값으로 표현됩니다.

1에 가까울수록 구매 패턴이 거의 동일하다는 뜻입니다. 세 번째로, 타겟 고객과 가장 유사한 상위 5명의 고객을 찾습니다.

argsort로 유사도를 정렬하고, [::-1]로 내림차순으로 뒤집은 후, [1:6]으로 자기 자신(항상 유사도 1.0)을 제외한 상위 5명을 선택합니다. 이들이 타겟 고객과 가장 비슷한 취향을 가진 사람들입니다.

마지막으로, 유사 고객들이 구매한 상품 중 타겟 고객이 아직 구매하지 않은 상품을 추천 후보로 선정합니다. 집합 차집합 연산(-)을 사용하면 간단하게 구할 수 있습니다.

여러 유사 고객에게서 공통으로 나타나는 상품일수록 좋은 추천입니다. 여러분이 이 코드를 사용하면 각 고객에게 개인화된 상품 목록을 제공할 수 있습니다.

이메일 마케팅, 웹사이트 메인 화면, 상품 상세 페이지 등에서 "당신을 위한 추천" 섹션을 만들어 고객 참여도와 전환율을 크게 높일 수 있습니다. 또한 신규 고객이라도 첫 구매 후 즉시 유사 고객을 찾아 추천할 수 있습니다.

실전 팁

💡 희소성 문제를 주의하세요. 대부분의 고객이 전체 상품의 1% 미만만 구매하므로 매트릭스가 대부분 0으로 채워집니다. 최소 5번 이상 구매된 상품만 포함하면 계산 속도와 정확도가 모두 개선됩니다.

💡 아이템 기반 필터링도 시도하세요. 고객 대신 상품을 행으로 하는 매트릭스를 만들면 "이 상품과 비슷한 상품"을 추천할 수 있습니다. 고객 수가 많고 상품 수가 적을 때 더 효율적입니다.

💡 가중치를 적용하면 더 정교합니다. 단순 구매 여부(0/1)보다 구매 횟수나 금액을 사용하면 선호도 강도를 반영할 수 있습니다. aggregate_function="sum"으로 변경하고 amount 값을 사용하세요.

💡 콜드 스타트 문제 대비: 신규 고객이나 신규 상품은 데이터가 없어 추천이 어렵습니다. 이 경우 인기 상품이나 카테고리 기반 추천을 백업으로 제공하세요.

💡 실시간 업데이트는 비용이 큽니다. 매번 전체 유사도를 재계산하는 대신, 하루나 일주일 단위로 배치 계산하고 캐싱하세요. 대부분의 경우 실시간성보다 정확도가 더 중요합니다.


7. 이탈 예측 - 위험 고객 조기 발견

시작하며

여러분의 충성 고객이 어느 날 갑자기 구매를 멈춘다면, 언제 알아차리시겠습니까? 3개월 후?

6개월 후? 그때는 이미 늦었을 수 있습니다.

고객을 잃는 것보다 새 고객을 유치하는 비용이 5배나 더 비싸다는 사실을 알고 계신가요? 이런 문제는 모든 비즈니스의 생존과 직결됩니다.

이탈은 서서히 진행되며, 명확한 신호 없이 일어납니다. 마지막 구매 후 얼마나 지나야 이탈로 봐야 할까요?

구매 주기가 긴 상품이라면 6개월도 정상일 수 있고, 짧은 상품이라면 1주일도 위험 신호일 수 있습니다. 바로 이럴 때 필요한 것이 데이터 기반 이탈 예측입니다.

고객의 구매 패턴 변화를 모니터링하여 이탈 위험이 높은 고객을 조기에 발견하고, 선제적으로 대응할 수 있습니다.

개요

간단히 말해서, 이탈 예측은 고객의 과거 행동 패턴을 분석하여 향후 관계를 끊을 가능성을 추정하는 기법입니다. 실무에서 이탈 예측은 고객 유지 전략의 핵심입니다.

이탈 위험이 높은 고객을 미리 파악하면 특별 할인, 1:1 상담, 맞춤 프로모션 등으로 관계를 회복할 수 있습니다. 예를 들어, 매월 구매하던 고객이 2개월째 구매하지 않으면 이탈 초기 단계일 수 있습니다.

이때 "오랜만이에요! 특별 쿠폰을 드립니다" 메시지를 보내면 60~70%는 돌아옵니다.

하지만 6개월 후에는 10%도 돌아오지 않습니다. 기존에는 복잡한 머신러닝 모델이 필요했다면, 이제는 간단한 규칙 기반 방법과 RFM 점수만으로도 효과적인 이탈 예측이 가능합니다.

핵심 지표는 Recency의 변화입니다. 고객의 평균 구매 주기보다 Recency가 2배 이상 길어지면 이탈 위험 신호입니다.

또한 구매 빈도와 금액의 감소 추세도 중요한 지표입니다. 지난 3개월 구매액이 이전 3개월의 50% 미만이라면 관심이 줄어들고 있다는 뜻입니다.

이러한 지표들을 조합하면 이탈 확률을 계산할 수 있습니다.

코드 예제

import polars as pl
from datetime import datetime, timedelta

# 고객별 구매 주기 계산
customer_cycles = purchases.sort(["customer_id", "purchase_date"]).with_columns([
    pl.col("purchase_date").shift(1).over("customer_id").alias("prev_purchase_date")
]).filter(
    pl.col("prev_purchase_date").is_not_null()
).with_columns([
    (pl.col("purchase_date") - pl.col("prev_purchase_date")).dt.days().alias("days_between")
]).group_by("customer_id").agg([
    pl.col("days_between").mean().alias("avg_purchase_cycle"),
    pl.col("purchase_date").max().alias("last_purchase_date")
])

# 이탈 위험 고객 식별
analysis_date = datetime(2024, 1, 1)
at_risk = customer_cycles.with_columns([
    ((analysis_date - pl.col("last_purchase_date")).dt.days()).alias("days_since_last"),
    (pl.col("avg_purchase_cycle") * 2).alias("churn_threshold")
]).filter(
    pl.col("days_since_last") > pl.col("churn_threshold")
).select(["customer_id", "days_since_last", "avg_purchase_cycle"])

설명

이것이 하는 일: 각 고객의 평균 구매 주기를 계산하고, 현재 그 주기의 2배 이상 구매하지 않은 고객을 이탈 위험 고객으로 식별합니다. 첫 번째로, 각 고객의 연속된 구매일 사이의 간격을 계산합니다.

shift(1).over("customer_id")를 사용하면 같은 고객의 이전 구매일을 가져올 수 있습니다. 예를 들어, 고객 A가 1월 1일, 2월 1일, 3월 1일에 구매했다면 간격은 [null, 31일, 28일]이 됩니다.

첫 구매는 이전이 없으므로 null이고, 이는 filter로 제거합니다. 그 다음으로, 고객별로 구매 간격의 평균을 계산합니다.

이것이 그 고객의 정상적인 구매 주기입니다. 예를 들어, 평균이 30일이라면 이 고객은 보통 한 달에 한 번 구매한다는 뜻입니다.

또한 마지막 구매일도 함께 저장하여 현재 얼마나 시간이 지났는지 계산할 수 있게 합니다. 세 번째로, 분석 기준일로부터 마지막 구매일까지의 경과 일수를 계산합니다.

이것이 현재 Recency입니다. 그리고 평균 구매 주기의 2배를 이탈 기준(churn_threshold)으로 설정합니다.

보통 30일마다 구매하는 고객이 60일 이상 구매하지 않으면 비정상적이라는 논리입니다. 마지막으로, filter로 days_since_last > churn_threshold 조건을 만족하는 고객만 선택합니다.

이들이 이탈 위험 고객입니다. 예를 들어, 평균 주기가 20일인데 현재 50일째 구매하지 않은 고객은 2.5배 초과이므로 고위험군입니다.

여러분이 이 코드를 사용하면 매주 또는 매일 이탈 위험 고객 목록을 자동으로 생성할 수 있습니다. 이들에게 타게팅된 이메일, SMS, 푸시 알림을 보내거나, 고객 서비스팀이 직접 연락하여 문제를 파악하고 해결할 수 있습니다.

실제로 많은 기업들이 이런 조기 개입으로 이탈률을 20~30% 감소시켰습니다.

실전 팁

💡 신규 고객과 기존 고객을 분리하세요. 한 번만 구매한 고객은 구매 주기를 계산할 수 없으므로 filter(pl.col("purchase_count") >= 2)로 제외하거나 별도 기준을 적용하세요.

💡 세그먼트별로 다른 기준을 사용하세요. VIP 고객은 1.5배, 일반 고객은 2배, 저빈도 고객은 3배처럼 차별화하면 더 정확합니다. 중요한 고객일수록 민감하게 반응해야 합니다.

💡 다차원 분석을 하세요. Recency뿐 아니라 최근 3개월 구매 빈도와 금액의 감소 추세도 함께 보면 더 정확합니다. 모든 지표가 악화되는 고객이 가장 위험합니다.

💡 이탈 단계를 나누세요. 주기의 1.5배는 "주의", 2배는 "경고", 3배는 "위험"처럼 단계를 나누면 대응 강도를 조절할 수 있습니다. 초기 단계에는 가벼운 푸시 알림, 후기 단계에는 고액 쿠폰을 제공하세요.

💡 이탈 원인도 함께 분석하세요. 최근 반품이 있었는지, 고객 서비스 문의가 있었는지, 경쟁사 프로모션이 있었는지 등을 함께 보면 근본 원인을 파악하고 해결할 수 있습니다.


8. 가격 민감도 분석 - 최적 가격 찾기

시작하며

여러분이 상품 가격을 10% 인상하려고 할 때, 매출이 늘어날까요 줄어들까요? 가격을 내리면 판매량은 증가하지만 수익은 오히려 감소할 수도 있습니다.

어떻게 최적의 가격을 찾을 수 있을까요? 이런 질문은 모든 비즈니스의 수익성을 결정하는 핵심입니다.

가격이 너무 높으면 고객을 잃고, 너무 낮으면 이익을 남기지 못합니다. 하지만 대부분의 기업은 경쟁사 가격을 보거나 원가에 일정 마진을 더하는 단순한 방법으로 가격을 책정합니다.

고객이 실제로 얼마나 가격에 민감한지 데이터로 확인하지 않습니다. 바로 이럴 때 필요한 것이 가격 민감도 분석입니다.

과거 가격 변동과 판매량의 관계를 분석하여 가격 탄력성을 계산하고, 수익을 극대화하는 최적 가격을 찾을 수 있습니다.

개요

간단히 말해서, 가격 민감도 분석은 가격 변화가 수요에 미치는 영향을 측정하여 최적의 가격 전략을 수립하는 기법입니다. 실무에서 가격 전략은 수익성의 핵심입니다.

가격 탄력성이 높은 상품(예: 생필품)은 가격을 조금만 올려도 수요가 크게 줄어들므로 경쟁력 있는 가격을 유지해야 합니다. 반면 탄력성이 낮은 상품(예: 명품, 필수품)은 가격을 올려도 수요가 별로 안 줄어들므로 마진을 높일 수 있습니다.

예를 들어, 가격을 10% 올렸을 때 판매량이 5%만 감소한다면 총 수익은 (1.1 × 0.95 = 1.045) 4.5% 증가합니다. 기존에는 A/B 테스트나 복잡한 경제 모델이 필요했다면, 이제는 Polars로 역사적 데이터를 분석하여 실용적인 인사이트를 얻을 수 있습니다.

핵심 개념은 가격 탄력성입니다. 탄력성 = (수요 변화율) / (가격 변화율)로 계산되며, 절댓값이 1보다 크면 탄력적(가격에 민감), 작으면 비탄력적(가격에 둔감)입니다.

이 값을 알면 가격 변화가 매출과 이익에 미칠 영향을 예측할 수 있습니다. 또한 상품별, 고객 세그먼트별로 다르게 나타나므로 차별화된 가격 전략이 가능합니다.

코드 예제

import polars as pl
import numpy as np

# 상품별 일자별 가격과 판매량 데이터
price_sales = pl.read_csv("price_sales_history.csv")

# 상품별 가격 변화와 수요 변화 계산
elasticity = price_sales.sort(["product_id", "date"]).with_columns([
    pl.col("price").shift(1).over("product_id").alias("prev_price"),
    pl.col("quantity").shift(1).over("product_id").alias("prev_quantity")
]).filter(
    pl.col("prev_price").is_not_null()
).with_columns([
    # 가격 변화율
    ((pl.col("price") - pl.col("prev_price")) / pl.col("prev_price")).alias("price_change_pct"),
    # 수요 변화율
    ((pl.col("quantity") - pl.col("prev_quantity")) / pl.col("prev_quantity")).alias("quantity_change_pct")
]).filter(
    pl.col("price_change_pct").abs() > 0.01  # 최소 1% 이상 가격 변화
).with_columns([
    # 가격 탄력성
    (pl.col("quantity_change_pct") / pl.col("price_change_pct")).alias("elasticity")
]).group_by("product_id").agg([
    pl.col("elasticity").mean().alias("avg_elasticity"),
    pl.col("price").mean().alias("avg_price"),
    pl.col("quantity").mean().alias("avg_quantity")
])

설명

이것이 하는 일: 상품의 가격이 변했을 때 판매량이 어떻게 반응하는지 분석하여 가격에 대한 민감도를 측정합니다. 첫 번째로, 각 상품의 이전 시점 가격과 판매량을 가져옵니다.

shift(1).over("product_id")를 사용하면 같은 상품의 전날(또는 전 기간) 데이터를 참조할 수 있습니다. 예를 들어, 1월 15일의 가격이 10,000원이고 1월 14일이 9,000원이었다면 prev_price는 9,000원이 됩니다.

그 다음으로, 가격 변화율과 수요 변화율을 계산합니다. (현재값 - 이전값) / 이전값 공식으로 백분율 변화를 구합니다.

가격이 9,000원에서 10,000원으로 올랐다면 가격 변화율은 11.1%이고, 판매량이 100개에서 90개로 줄었다면 수요 변화율은 -10%입니다. 가격이 거의 변하지 않은 경우(1% 미만)는 제외하여 노이즈를 줄입니다.

세 번째로, 가격 탄력성을 계산합니다. 탄력성 = 수요 변화율 / 가격 변화율이므로, -10% / 11.1% = -0.9입니다.

음수인 이유는 가격이 오르면 수요가 줄어드는 정상적인 관계이기 때문입니다. 절댓값 0.9는 가격이 1% 오를 때 수요가 0.9% 감소한다는 의미입니다.

마지막으로, 상품별로 평균 탄력성을 계산합니다. 여러 가격 변동 사례를 평균내어 안정적인 탄력성 추정치를 얻습니다.

탄력성이 -0.5라면 가격을 10% 올려도 수요가 5%만 줄어들므로 가격 인상이 유리합니다. 반대로 -2.0이라면 가격을 10% 올리면 수요가 20% 줄어들므로 가격을 낮추는 것이 유리합니다.

여러분이 이 코드를 사용하면 감이 아닌 데이터로 가격을 결정할 수 있습니다. 탄력성이 낮은 상품은 가격을 올려 마진을 개선하고, 탄력성이 높은 상품은 낮은 가격으로 시장 점유율을 높이는 차별화된 전략을 수립할 수 있습니다.

또한 시즌별, 세그먼트별로 탄력성이 다를 수 있으므로 동적 가격 전략도 가능합니다.

실전 팁

💡 외부 요인을 통제하세요. 프로모션, 광고, 시즌 등이 동시에 변하면 순수한 가격 효과를 측정할 수 없습니다. filter로 정상 기간만 선택하거나 with_columns로 통제 변수를 추가하세요.

💡 충분한 가격 변동이 필요합니다. 가격이 항상 동일하면 탄력성을 계산할 수 없습니다. 최소 3~5회 이상의 가격 변화가 있어야 의미 있는 분석이 가능합니다.

💡 시차를 고려하세요. 가격을 올린 즉시 수요가 반응하지 않을 수 있습니다. shift(7)처럼 7일 후 수요와 비교하면 지연 효과를 포착할 수 있습니다.

💡 세그먼트별로 분석하세요. VIP 고객과 일반 고객의 가격 민감도가 다릅니다. group_by(["product_id", "customer_segment"])로 세그먼트별 탄력성을 계산하면 차별적 가격 전략이 가능합니다.

💡 최적 가격 공식: 최적 가격 = 한계비용 × (탄력성 / (탄력성 + 1)) 입니다. 예를 들어, 원가가 5,000원이고 탄력성이 -2라면 최적 가격은 5,000 × (2 / (2-1)) = 10,000원입니다.


#Python#Polars#데이터분석#RFM분석#구매패턴#데이터분석,Python,Polars

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.