아래는 온라인 화장품 shop A사의 판매 전략을 개선하기 위해 고객의 행동 패턴과 선호도를 분석한 프로젝트이다.
🔖
A사는 온라인 화장품 shop의 판매 전략을 개선하기 위해 고객의 행동 패턴과 선호도를 분석하려 한다.
⛳ 문제정의
▶ 고객 이해에 대한 정보 부족
▶ Q. 어떤 제품 또는 브랜드가 가장 인기가 있을까?
▶ Q. 고객들이 카트에 담았으나 구매하지 않는 제품들은 무엇일까?
▶ Q. 구매 전환률을 높이기 위한 전략은 무엇일까?
⛳ 기대효과
▶ 매출 증대와 높은 고객 만족도를 달성
▶ 효과적인 마케팅 전략 수립
▶ 재고 관리 및 제품 전략의 효율화
⛳ 해결방안
▶ 데이터를 통한 고객의 제품 및 브랜드 선호도 파악
▶ 카트에 담기만 하고 구매되지 않는 제품들의 공통점 분석
▶ 구매 전환률을 높일 수 있는 마케팅 전략 제안
⛳ 성과측정
▶ 구매 전환률의 증가
▶ 고객 만족도 조사를 통한 평가
▶ 매출 증대 및 재구매율 증가
⛳ 운영
▶ 주기적으로 데이터를 수집하고 분석하여 전략을 수정 및 적용
▶ 고객의 피드백을 수집하여 서비스 개선
▶ 새로운 제품 또는 브랜드의 반응을 모니터링하여 전략 반영
# ▶ pd.set option
import numpy as np
import pandas as pd
pd.set_option('display.max_columns',100)
pd.set_option('display.max_rows',100)
# ▶ Data read
df = pd.read_csv('S_PJT11_DATA.csv')
df.head()
event_time event_type product_id category_id category_code brand price user_id user_session
0 2019-12-01 00:00:00 UTC remove_from_cart 5712790 1487580005268456287 None f.o.x 6.27 576802932 51d85cb0-897f-48d2-918b-ad63965c12dc
1 2019-12-01 00:00:00 UTC view 5764655 1487580005411062629 None cnd 29.05 412120092 8adff31e-2051-4894-9758-224bfa8aec18
2 2019-12-01 00:00:02 UTC cart 4958 1487580009471148064 None runail 1.19 494077766 c99a50e8-2fac-4c4d-89ec-41c05f114554
3 2019-12-01 00:00:05 UTC view 5848413 1487580007675986893 None freedecor 0.79 348405118 722ffea5-73c0-4924-8e8f-371ff8031af4
4 2019-12-01 00:00:07 UTC view 5824148 1487580005511725929 None None 5.56 576005683 28172809-7e4a-45ce-bab0-5efa90117cd5
``` ​:citation[oaicite:0]{index=0}​
event_time: 이벤트가 발생한 시간
event_type: 이벤트 유형= [view, cart, remove_from_cart, purchase] 중 하나
product_id: 제품 ID
category_id: 제품 카테고리 ID
category_code: 의미 있는 카테고리 이름 (있는 경우)
brand: 브랜드 이름 (소문자로, 있을 경우)
price: 제품 가격
user_id: 영구 사용자 ID
user_session: 사용자 세션 ID
# ▶ Data 형태 확인
# ▶ 3,533,286 row, 9 col로 구성됨
print('df', df.shape)
> df (3533286, 9)
# ▶ Data type 확인
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 3533286 entries, 0 to 3533285
Data columns (total 9 columns):
# Column Dtype
--- ------ -----
0 event_time object
1 event_type object
2 product_id int64
3 category_id int64
4 category_code object
5 brand object
6 price float64
7 user_id int64
8 user_session object
dtypes: float64(1), int64(3), object(5)
memory usage: 242.6+ MB
총 9개의 열 데이터가 있으며 event_time 시간형 타입의 데이터가 object 문자형 데이터로 선언이 돼있다. 그리고 user_id 와 같이 고객의 고유한 정보 문자열 데이터여야 할 것이 int64 정수형으로 선언이 되 있다.
필요에 따라 데이터 분석 진행 시 데이터 타입을 변경시키는게 좋을 거 같다.
event_time 0
event_type 0
product_id 0
category_id 0
category_code 3474821
brand 1510289
price 0
user_id 0
user_session 779
dtype: int64
category_code, brand, user_session 등의 데이터는 null 값을 삭제했을 때 데이터의 변형이 일어나 정확한 데이터 분석을 하기가 어렵기에 삭제하기 보다는 null 값을 다른 문자열None 이나 0으로 치환하는 것이 좋다. null 값 처리
# ▶ Null value 다른 값으로 치환
df['category_code'].fillna('None', inplace = True)
df['brand'].fillna('None', inplace = True)
df['user_session'].fillna('None', inplace = True)
# ▶ Outlier 확인
df.describe()
product_id category_id price user_id
count 3.533286e+06 3.533286e+06 3.533286e+06 3.533286e+06
mean 5.473054e+06 1.555023e+18 8.871856e+00 5.223318e+08
std 1.331331e+06 1.689262e+17 1.986474e+01 8.494819e+07
min 3.752000e+03 1.487580e+18 -7.937000e+01 1.180452e+06
25% 5.726191e+06 1.487580e+18 2.060000e+00 4.866830e+08
50% 5.811429e+06 1.487580e+18 4.210000e+00 5.566496e+08
75% 5.859462e+06 1.487580e+18 7.140000e+00 5.828019e+08
max 5.917178e+06 2.235524e+18 3.277800e+02 5.954145e+08
price의 최솟값 min 값이 -7.937000e+01로 이상치로 보이지만 취소 매출이나 할인된 값이 함께 있는 데이터인지 확실하지 않아 삭제하지 않았다.기본 판매 및 고객 구매지표 확인
A 온라인 화장품 판매 회사의 고객들이 제품을 구매할 때 발생하는 전체 이벤트 유형별 발생 횟수를 알아보았다.
# ▶ 이벤트 타입 횟수
event_counts = df['event_type'].value_counts()
event_counts
event_type
view 1728331
cart 927124
remove_from_cart 664655
purchase 213176
Name: count, dtype: int64
이 정보를 통해 우리는 고객들이 우리가 설계한 유저의 구매 경험 루트를 잘 따라가고 있는지, 최초 조회 및 장바구니부터 구매까지 단계를 나눠 살펴보아 이탈율이 얼마인지 알아볼 필요가 있다.
이때 사용하는 분석법이 바로 퍼널분석(Funnel Analysis) 이다.
제품을 구매할 때 최초 조회 -> 장바구니 -> 구매 까지 각 단계를 통과할 때마다 제품을 구매하는 유저 수는 당연히 줄어드는 모양세를 보인다. 위처럼 처음 조회 횟수는 약 170만명이나 되지만 최중 구매는 21만명만 나온 것처럼 말이다.
그리고 여기서 조회 -> 장바구니 -> 구매
↑ ↓
↑ 장바구니에서 삭제
←←←←← ←
각각의 단계를 넘어가는 것을 전환(Conversion) 이라고 부르고 그 비율은 전환율이(Conversion rate)이 된다.
퍼널 분석에서 이렇게 각 단계별 이탈율이나 Conversion rate를 살펴보는 것은 중요하다. 아래에서 고객의 구매 정보를 통해 퍼널 분석을 진행해보겠다.
# ▶ 각 단계에서의 이탈률 계산, 퍼널 분석
# 조회만 하고 이탈한 고객 데이터
view_to_cart_dropout = (event_counts['view'] - event_counts['cart']) / event_counts['view'] * 100
# 장바구니에서 구매까지 이어지지 않고 이탈한 고객 데이터 비율
cart_to_purchase_dropout = (event_counts['cart'] - event_counts['purchase']) / event_counts['cart'] * 100
# 장바구니에서 상품을 삭제하고 이탈한 고객 데이터 비율
cart_to_remove_dropout = (event_counts['remove_from_cart']) / event_counts['cart'] * 100
dropout_rates = {
'View to Cart Dropout Rate (%)': view_to_cart_dropout,
'Cart to Purchase Dropout Rate (%)': cart_to_purchase_dropout,
'Cart to Remove Dropout Rate (%)': cart_to_remove_dropout
}
dropout_rates
{'View to Cart Dropout Rate (%)': 46.35726605609689,
'Cart to Purchase Dropout Rate (%)': 77.00674343453518,
'Cart to Remove Dropout Rate (%)': 71.68997890249848}
# ▶ 사용자별 구매 횟수 계산
user_purchase_counts = df[df['event_type'] == 'purchase'].groupby('user_id').size()
# ▶ 사용자별 평균 구매 횟수 계산
average_purchase_per_user = user_purchase_counts.mean()
average_purchase_per_user
> 8.322960996369032
사용자별 평균 구매 횟수는 평균 약 8회 정도이다.
판매 데이터 에서 각 제품 별로 어떤 제품이 가장 인기가 있는지 알아보기 위해 판매량 TOP10 제품을 확인해보았다.
일단 'reservation_status' 즉 전체적인 예약의 현황을 살펴보았다.
# ▶ 가장 많이 판매된 상품 TOP 10 계산
top_sold_products = df[df['event_type'] == 'purchase']['product_id'].value_counts().head(10)
top_sold_products
product_id
5809910 1659
5854897 786
5802432 714
5700037 621
5809912 620
5833330 594
5304 549
5751422 548
5815662 521
5751383 435
Name: count, dtype: int64
# ▶ 가장 많이 판매된 상품 TOP 10 계산 (NA가 많아 의미가 없음)
top_sold_products = df[df['event_type'] == 'purchase']['category_code'].value_counts(dropna=False).head(20)
top_sold_products
category_code
None 210470
stationery.cartrige 984
apparel.glove 771
appliances.environment.vacuum 636
furniture.bathroom.bath 183
accessories.bag 42
furniture.living_room.cabinet 40
accessories.cosmetic_bag 34
appliances.personal.hair_cutter 14
appliances.environment.air_conditioner 2
Name: count, dtype: int64
'None' 값으로 사실상 어떤 제품이 많이 판매되는지 알아보기가 어려워 제품의 인기도를 알아보는건 의미가 없어졌다. 그래서 판매 데이터는 신뢰성이 적다고 할 수 있다. # ▶ 상품별 매출 계산
df['sales'] = df['price'] * df['event_type'].apply(lambda x: 1 if x == 'purchase' else 0)
# ▶ 가장 많은 매출을 기록한 상품 TOP 10
top_sales_products = df.groupby('product_id').sum()['sales'].sort_values(ascending=False).head(10)
# product_id 열을 그룹화하고 이후 sales 열의 값들의 합계를 계산하고 내림차순으로 정렬하는 조건을 건 것
# 또는 top_sales_products = df.groupby('product_id')['sales'].sum().sort_values(ascending=False).head(10)
top_sales_products
product_id
5850281 10471.28
5560754 10110.88
5809910 8693.16
5751422 6000.60
5751383 4489.20
5877454 4473.29
5909810 4326.63
5846437 4297.80
5849033 4066.08
5792800 4066.08
Name: sales, dtype: float64
제품의 매출을 살펴보니 판매량과는 조금 순위가 바뀐 것을 확인할 수 있으며, 이는 판매량보다는 제품의 가격에 따라 순위가 책정된 것이라고 할 수 있겠다.
하지만 제품명이 숫자로만 명시되어 있어 정확히 어떤 제품이 매출이 많은지 알기 어렵기에 정확한 브랜드별 판매량 및 매출을 확인해보고자 한다.
# ▶ 브랜드별 판매량 계산
brand_sales_count = df[df['event_type'] == 'purchase'].groupby('brand').size()
# ▶ 브랜드별 매출 계산
brand_sales_revenue = df[df['event_type'] == 'purchase'].groupby('brand').sum()['sales']
brand_sales = pd.DataFrame({
'Sales Count': brand_sales_count,
'Sales Revenue': brand_sales_revenue
}).sort_values(by='Sales Revenue', ascending=False)
brand_sales.head(10)
Sales Count Sales Revenue
brand
None 91695 440207.57
runail 18199 58177.26
grattol 8171 43793.50
irisk 10583 35291.51
uno 2780 29084.76
estel 4116 24474.19
jessnail 1823 24075.00
strong 120 22266.41
masura 6985 19809.19
cnd 1299 19378.92
가장 많이 매출을 낸 제품 브랜드가 'None' 값으로 브랜드가 없는 제품에 대한 데이터가 가장 많다.
이를 제외하고 runail 브랜드가 가장 많은 매출을 달성했으며 그 다음은 grattol 매출이 뒤를 이었다. estl 브랜드부터 하위 브랜드들은 매출의 큰 차이가 없는 것으로 보인다.
최종적으로 우리의 목표는 구매전환율을 올리는 것으로 현재 카테고리 별, 브랜드 별 인기도 및 선호도를 살펴본 결과 의미가 없는 데이터가 많아 전략을 짤 수가 없었다.
그래서 상품id 별로 조회, 장바구니, 구매 전환율이 어떻게 되는지 확인하여 이를 토대로 판매전략을 마련하고자 한다.
# ▶ 상품별 조회, 장바구니 추가, 구매 데이터 계산
product_events = df.groupby(['product_id', 'event_type']).size().unstack().fillna(0)
# ▶ 구매 전환률 계산: 구매수 / 조회수
product_events['conversion_rate'] = product_events['purchase'] / product_events['view'] * 100
# ▶ 상품별 조회수가 10회 이상인 상품들만 필터링하여 전환률 TOP 10 확인
top_conversion_products = product_events[product_events['view'] >= 10].sort_values(by=['view', 'conversion_rate'], ascending=[False, True]).head(10)
top_conversion_products[['view', 'cart', 'purchase', 'conversion_rate']]
event_type view cart purchase conversion_rate
product_id
5809910 24419.0 6513.0 1659.0 6.793890
5909810 8473.0 675.0 231.0 2.726307
5877454 6621.0 519.0 101.0 1.525449
5809912 5944.0 2634.0 620.0 10.430686
5886282 5488.0 459.0 90.0 1.639942
5877456 5022.0 161.0 15.0 0.298686
5649236 4372.0 621.0 148.0 3.385178
5809911 4307.0 1757.0 386.0 8.962155
5769877 4100.0 188.0 27.0 0.658537
5856186 4015.0 245.0 42.0 1.046077
5809910, 5809912, 5909810, 5809911 제품 조회 수 대비 구매 전환율이 6프로나 10프로 정도가 된다.5877456, 5769877, 5856186 제품은 각각 6번째, 9번째, 10번째로 조회가 많이 됐지만 구매 전환율이 낮은 것을 볼 수 있다. 따라서 해당 제품들의 구매 전환율을 높히기 위한 전략을 마련해야 할 것이다.상품 별 분석은 마쳤으니 이제 효율적인 판매 마케팅 전략을 마련할 수 있도록 고객의 시간대별 구매 행동 패턴을 분석해보자
# ▶ event_time에서 시간대 정보 추출
df['hour'] = df['event_time'].astype(str).str[11:13]
# ▶ 시간대별 이벤트 유형별 발생 횟수 계산
hourly_events = df.groupby(['hour', 'event_type']).size().unstack().fillna(0)
# ▶ 시간대별 구매 전환률 계산: 구매수 / 조회수
hourly_events['conversion_rate'] = hourly_events['purchase'] / hourly_events['view'] * 100
hourly_events[['view', 'cart', 'purchase', 'conversion_rate']]
# ▶ gradient 시각화
styled_all_columns = hourly_events.style.background_gradient(cmap='coolwarm', subset=['conversion_rate'])
styled_all_columns

gradient 시각화로 데이터 프레임 내의 구매 전환율이 가장 높은 시간대를 살펴보니 오전 7시~11시 사이에 고객의 구매 전환율이 가장 높게 나오는 것을 확인할 수 있다.결론
이탈률 확인 결과 조회만 하고 이탈한 고객이 46프로, 장바구니에서 구매하지 않은 고객이 77프로, 장바구니에서 삭제하고 이탈한 고객이 71프로를 차지했다.
각 이탈률을 어떻게 줄일 것인지 전략이 필요할 것이다.
가장 많이 판매되는 제품 및 제품의 카테고리가 'None' 값으로 사실상 어떤 제품이 많이 판매되는지 알아보기가 어려워 제품의 인기도를 알아보는건 의미가 없어졌다. 그래서 판매 데이터는 신뢰성이 적다고 할 수 있다.
그리고 가장 많이 매출을 낸 제품 브랜드가 'None' 값으로 브랜드가 없는 제품에 대한 데이터가 가장 많다.
이를 제외하고 runail 브랜드가 가장 많은 매출을 달성했으며 그 다음은 grattol 매출이 뒤를 이었다. estl 브랜드부터 하위 브랜드들은 매출의 큰 차이가 없는 것으로 보인다.
조회 결과 5809910, 5809912, 5909810, 5809911 제품 조회 수 대비 구매 전환율이 6프로나 10프로 정도가 된다.
5877456, 5769877, 5856186 제품은 각각 6번째, 9번째, 10번째로 조회가 많이 됐지만 구매 전환율이 낮은 것을 볼 수 있다. 따라서 해당 제품들의 구매 전환율을 높히기 위한 전략을 마련해야 할 것이다.
이탈률 확인 결과 조회만 하고 이탈한 고객이 46프로, 장바구니에서 구매하지 않은 고객이 77프로, 장바구니에서 삭제하고 이탈한 고객이 71프로를 차지했다.
따라서 해당 시간대에 할인 이벤트나 제품 이벤트, 배너 광고 이벤트 등을 타겟 마케팅 하는 전략을 세울 필요가 있어 보인다.