[ kaggle ] cosmetics ecommerce 분석 : 데이터 가공 및 추출, 시각화
※ 시각화(Tableau) : https://public.tableau.com/app/profile/.33103904/viz/analysis_cosmetics_ecommerce/CosmeticsEcommerceDashboard?publish=yes
목차
이전 글
https://nyeoki-log.tistory.com/73
[ kaggle ] cosmetic ecommerce 분석 : 분석 개요
1. 문제 인식 kaggle에서 제공되는 'cosmetics e Commerce' 이벤트 데이터를 사용하여 funnel analysis 및 segmentation, 혹은 cohort analysis 연습데이터를 BigQuery에 적재 후, SQL Query 문을 이용하여 데이터 가공 및
nyeoki-log.tistory.com
https://nyeoki-log.tistory.com/74
[ kaggle ] cosmetic ecommerce 분석 : 데이터 적재
1. 데이터 적재데이터베이스는 Google Cloud에 BigQuery를 사용원본 데이터를 Google Drive에 저장 후, BigQuery와 연동2019-Oct.csv2019-Nov.csv2019-Dec.csv2020-Jan.csv2020-Feb.csv BigQuery의 SQL 쿼리문을 통해 데이터를 가
nyeoki-log.tistory.com
0. 요약
- 월별 purchase(구매) 전환율은 11월에 가장 높음
- 연말 할인 이벤트를 통해 MAU를 높였을 것이라고 추정
- 월별 purchase 구매 전환율은 최소 6%로, 이탈 고객이 적은 안정적인 상태로 판단됨(Adobe 발표 자료 기준)
- 구매 브랜드에 따라 퍼널 단계별 전환율이 다름
- 'runail'은 월 매출과 MAU가 가장 높은 손발톱 관련 브랜드로, 앰플이나 케어, 아세톤과 같은 제품의 구매 주기를 파악해 고객의 재방문을 유도
- 'strong'과 'marathon'은 고가의 제품을 판매하는 브랜드로 추정. 고객이 cart로 전환될 수 있도록 최저가임을 어필하거나 할인 프로모션 등을 진행
- 'ingarden'은 remove_from_cart 이벤트가 많이 일어나는 브랜드로, ingarden 대신 runail과 irisk로 구매를 유도하거나, ingarden의 제품 경쟁력을 드러낼 수 있는 방법 고려
1. EDA
select count(*) as count_total_data
, count(event_time) as count_event_time
, count(event_type) as count_event_type
, count(product_id) as count_product_id
, count(category_id) as count_category_id
, count(category_code) as count_category_code
, count(brand) as count_brand
, count(price) as count_price
, count(user_id) as count_user_id
, count(user_session) as count_user_session
from 10월 테이블
;
category_code와 brand, user_session에 null 값이 존재하는 것을 확인할 수 있습니다. category_code로 고객을 segmentation하기에는 모든 제품에 카테고리가 할당되지 않았으므로, category_id에서 규칙성을 찾는 쪽을 고려해야할 것 같습니다.
2. category 규칙성 파악
select distinct category_id
, category_code
, brand
from 10월 테이블
where category_code is not null
order by category_id asc
limit 500
;
'appliances'를 category 속성으로 가지고 있는 category_id가 동일한 숫자로 구성돼 있음을 확인할 수 있습니다.
category_code가 'appliances'인 데이터만 추출하여 규칙성을 파악해 보겠습니다.
select distinct category_id
, category_code
, brand
from 10월 테이블
where category_code is not null
and category_code like 'appliances%'
order by category_id asc
limit 500
;
where 절에 like 구문을 추가하였습니다.
Fig 4를 통해 알 수 있듯이, 'appliances'로 똑같이 분류되더라도 category_id의 규칙성을 찾을 수 없는 경우가 존재했습니다.
따라서 category_id를 통해 제품의 category를 분류할 수 없을 것으로 생각됩니다. 고객 segmentation은 제품 브랜드로만 진행하겠습니다.
3. 퍼널 분석
'view - cart - (remove from cart) - purchase' 순으로 이벤트를 퍼널 분석해 보겠습니다.
한 명의 고객이 여러 번의 purchase 이벤트를 발생시킨 경우, 한 번의 이벤트로 간주하겠습니다(중복 X).
select format_date("%Y-%m", event_time) as date
,event_type
,count(distinct user_id) as count_event
from 10월
group by date, event_type
union distinct
select format_date("%Y-%m", event_time) as date
,event_type
,count(distinct user_id) as count_event
from 11월
group by date, event_type
union distinct
select format_date("%Y-%m", event_time) as date
,event_type
,count(distinct user_id) as count_event
from 12월
group by date, event_type
-- 나머지 테이블도 union distinct
위 쿼리를 통해 월별, 이벤트별 고객 수를 추출하겠습니다.
11월에 purchase로 전환된 비율이 가장 높은 것을 확인할 수 있습니다(Fig 5).
11월 달 전후로 view 이벤트 발생을 살펴보겠습니다. 10월에는 약 39만 건이 발생했으며 11월에는 약 36만 건이 발생했고, 12월에도 36만 건이 발생한 것을 확인할 수 있습니다(Fig 6~8).
10월에 cart 이벤트 전환이 11월보다 7%p나 높지만 purchase 이벤트 전환율이 높지 않았습니다. 반면에 11월의 remove from cart의 비율은 10월보다 3%p나 높음에도 불구하고, 전월보다 2%p 높은 전환 비율을 보였습니다.
이는 11월에 구매하고 싶은 제품을 10월에 미리 생각해 본 후(view) 장바구니에 담아두고(cart), 11월에 결제할 제품을 한 번 정리 후(remove from cart) 결제한 것으로 생각됩니다.
11월에 구매가 몰린 이유를 생각해 보자면, 연말 기념 할인 이벤트(블랙 프라이데이 혹은 재고 소진)를 실시했을 가능성이 있습니다.
purchase 이벤트까지 전환된 고객을 활성 고객으로 간주했을 때, 11월이 MAU와 ARPPU, 총 매출이 가장 높은 것을 확인할 수 있습니다. 할인 이벤트를 통해(가정) 매출이 전월에 비해 약 26% 상승했지만, 전월 대비 CAC가 어떻게 변했는지에 따라 영업 이익이 달라질 것으로 생각됩니다.
20년 1월에 ARPPU가 다시 상승했는데, 위와 같은 의미로 신년 기념 행사를 진행해, 고객 유입과 매출 상승이 이뤄졌다고 생각할 수 있습니다.
Fig 10은 2020년 Adobe에서 발표한 ecommerce별 구매 전환율을 나타낸 차트입니다. cosmetics의 구매 전환율은 2.9%이고 현재 분석 중인 ecommerce의 구매 전환율이 최소 6% 이상이므로, 해당 플랫폼은 고객 이탈이 적은 안정적인 상태를 보인다고 생각됩니다.
4. 브랜드별 퍼널 분석
고객이 구매하는 화장품의 브랜드에 따라 전환율을 퍼널 분석해 보겠습니다. 브랜드별로 분석하므로 고객의 user_id가 중복될 수 있습니다.
select format_date("%Y-%m", event_time) as date
,brand
,event_type
,count(distinct user_id) as count_event
from 10월
group by date, brand, event_type
union distinct
select format_date("%Y-%m", event_time) as date
,brand
,event_type
,count(distinct user_id) as count_event
from 11월
group by date, brand, event_type
union distinct
-- 나머지 테이블도 union distinct
차트를 살펴봤을 때(Fig 11), 브랜드별로 purchase 전환율이 다른 것을 확인할 수 있습니다. 위 차트(Fig 12)는 10월 차트만을 표현했고, 전체 차트를 살펴 봤을 때 2019년 10월부터 2020년 02월까지 'runail' 브랜드가 최고 매출을 달성하는 것을 확인할 수 있습니다.
4 - (1) runail 브랜드 분석
11월을 살펴봤을 때 월 매출이 올랐지만 ARPPU는 감소한 것을 확인할 수 있습니다(Fig 13). runail 브랜드를 이용하는 고객 수가 늘었음에도 불구하고 ARPPU가 하락했다는 것은, 높은 가격대의 제품보다는 비교적 낮은 가격대의 제품의 구매가 빈번했다고 가정할 수 있습니다.
10 ~ 11월에 purchase 비율이 1%p 차이나고, purchase 이벤트가 많았던 상위 4개 제품의 가격을 비교해 보겠습니다(Fig 14).
with oct as (
select format_date('%Y-%m', event_time) as date
, product_id
, avg(price) as price
from 10월
where 1=1
and brand = 'runail'
and event_type = 'purchase'
and product_id in (5700037, 5304, 5013, 5700046)
group by date, product_id
)
, nov as (
select format_date('%Y-%m', event_time) as date
, product_id
, avg(price) as price
from 11월
where 1=1
and brand = 'runail'
and event_type = 'purchase'
and product_id in (5700037, 5304, 5013, 5700046)
group by date, product_id
)
, jan as (
select format_date('%Y-%m', event_time) as date
, product_id
, avg(price) as price
from 12월
where 1=1
and brand = 'runail'
and event_type = 'purchase'
and product_id in (5700037, 5304, 5013, 5700046)
group by date, product_id
)
select oct.product_id
, round(oct.price,2) as price_of_october
, round(nov.price,2) as price_of_november
, round(Jan.price,2) as price_of_january
from oct
inner join nov
on oct.product_id = nov.product_id
inner join jan
on oct.product_id = jan.product_id
order by price_of_october desc
;
위 쿼리를 통해 특정 제품의 10월과 11월, 1월의 가격을 비교해 보았습니다(Fig 15). 4개의 제품 중 가격이 가장 높은 '5013'은 11월에 purchase 비율이 전월대비 0.91%p 감소했습니다. 가격이 동일한 '5700037'과 '5700046'의 10월 비율은 전체 31.99%이고 11월은 29.58%로, 전월대비 2%p 가량 감소했습니다. 가격이 제일 낮은 '5304'의 경우 전월대비 3.45%p 상승했습니다.
즉 11월 ARPPU 감소에는, 4가지 제품의 전체 가격 하락(할인 예상)과 상대적으로 가격이 저렴한 '5304'의 판매량 상승이 기여한 것으로 보입니다. ARPPU의 추세선(파란색)을 확인해 보면 약간 하향세를 그리고 있지만, 11월과 1월의 영향인 것으로 판단돼 runail이 부진하다고 판단하기에는 이르다고 생각됩니다.
Новинки — интернет-магазин Runail
Новинки 🆕 Большой выбор профессиональных продуктов 💅: материалы для моделирования и дизайна ногтей, средства для депиляции, материалы дл
runail.ru
(↑ runail 공식 홈페이지)
runail은 손발톱 제품을 판매하는 회사로, 매니큐어와 젤 네일, 인조 손톱과 같은 제품은 정기적으로 구매하지 않을 가능성이 큽니다. 그러나 앰플이나 케어, 아세톤과 같은 제품은 정기적으로 구매할 가능성이 존재하기에, 제품 구매 주기를 예측하여 푸시 알림 혹은 할인 쿠폰 지급이 유용할 것으로 사료됩니다.
4 - (2) strong, marathon 브랜드 분석
Fig 12 은 브랜드별 매출 상위 30개의 테이블 입니다. 30개 브랜드의 ARPPU의 중앙값을 기준으로 구분해 놓았으며, 그 중 'strong'과 'marathon' 값은 가장 높습니다.
두 브랜드의 purchase 이벤트는 많지 않음에도 불구하고, 월별 브랜드 매출이 상위 30위 안에 속합니다. 두 브랜드의 제품별 가격을 살펴본다면,
strong의 제품 평균 가격은 약 200루블이며, marathon도 약 100루블 정도에 형성돼 있습니다(Fig 18). 다른 브랜드보다 제품 가격이 월등하게 높으므로, 제품의 ARPPU가 높게 계산됩니다. 두 브랜드의 경우, 고가의 화장품이나 화장 / 미용에 관련된 전자제품일 것이라고 추측합니다. 따라서 구매 주기가 일정하지 않거나, 대부분의 고객들이 purchase 단계로 전환이 안 될 가능성이 큽니다.
Fig 19을 통해 알 수 있듯이, view 이벤트 대비 purchase 전환율이 3%를 넘지 않고 있습니다. 두 브랜드는 cart 이벤트 대비 purchase 전환율이 20% 이상이고 cart 이벤트 대비 remove_from_cart 전환율은 50% 이상이므로, 두 이벤트에서 전환율을 개선할 수 있다면 매출 상승에 영향이 있을 것이라고 생각합니다.
두 이벤트 퍼널을 개선했을 때 매출 변화를 확인할 수 있습니다(Fig 20 ~ 23). remove_from_cart를 5%로 개선했을 때 marathon 2.66%, strong 2.64% 매출 상승이 일어나고, 총 매출은 0.08% 상승합니다.
view → cart 5% 개선했을 때, marathon, strong 5% 매출 상승, 총 매출은 0.16% 상승합니다. view → cart 이탈이 가장 크기 때문에, 해당 퍼널을 개선했을 때 매출에 큰 영향을 끼칠 것이라고 생각합니다.
strong과 marathon은 cart 이벤트를 발생시키는 것이 쉽지 않지만, 현재 플랫폼이 최저가임을 어필하거나 할인 프로모션 등을 진행해 cart 전환을 유도하는 것이 필요하다고 생각합니다.
4 - (3) ingarden 브랜드 분석
ingarden 브랜드는 view 이벤트 대비 remove_from_cart 이벤트 비율이 39%로 가장 높습니다(2019년 10월 purchase 상위 30위 기준). 다른 월의 경우도 평균 38.9%로 비교적 높습니다. cart 이벤트 대비 remove_from_cart 이벤트 비율도 살펴보면,
select format_date("%Y-%m", event_time) as date
,brand
,count(distinct case when event_type = 'remove_from_cart' then user_id end)
/ count(distinct case when event_type = 'cart' then user_id end) as rate_remove_per_cart
from 10월
where brand = 'ingarden'
group by date, brand
union distinct
select format_date("%Y-%m", event_time) as date
,brand
,count(distinct case when event_type = 'remove_from_cart' then user_id end)
/ count(distinct case when event_type = 'cart' then user_id end) as rate_remove_per_cart
from 11월
where brand = 'ingarden'
group by date, brand
-- 나머지 테이블도 union distinct
;
( remove_from_cart / cart ) 비율도 평균 59.6%로 다른 브랜드에 비해 높습니다. ingarden은 브랜드 순 매출 상위 10위 안에 들 정도로 매출이 높은데, cart에서 제거되는 상품을 줄여 purchase로 유도한다면 매출 상승에 기여할 수 있을 것이라고 생각합니다.
4 - (3) - ① 가격
위 차트(Fig 26 ~ 27)는 ingarden의 제품별 remove_from_cart 횟수와 그에 따른 제품 가격을 나타냈습니다. 판매하는 제품 종류이 상이하지 않다면 매출 1위인 runail과 비교했을 때 ingarden의 ARPPU(9.0)가 동일하므로, 제품 가격이 remove_from_cart 이벤트 발생에 영향을 끼친다고 보기는 어렵습니다.
4 - (3) - ② 경쟁사 제품
고객마다 다르겠지만 cart에서 제품을 제거한다는 것은, 해당 제품을 구매할 마음이 없거나 다른 제품이 더 맘에 들어서 원래 담아놨던 제품을 제거하는 것이라고 생각합니다. 후자의 경우라면, 제품을 먼저 cart에 담고 그 후에 remove_from_cart를 할 가능성이 크다고 생각합니다. 따라서 ingarden이 remove_from_cart가 발생하기 전에 cart 이벤트가 발생한 제품을 탐색해 보겠습니다.
remove 이벤트보다 먼저 cart 이벤트가 발생하고 session은 동일한 데이터를 찾아 브랜드별로 count 해 보겠습니다.
-- 경쟁사 제품을 추가하고 ingarden의 제품을 장바구니에서 제거했다면, 해당 고객의 session이 유지됐을 수도 있다.
with oct_ingarden as (
select user_session
, event_time
from 10월
where 1=1
and brand = 'ingarden'
and event_type = 'remove_from_cart'
)
-- 나머지 테이블도 서브 쿼리 작성
select format_date('%Y-%m', oct.event_time) as date
, oct.brand as brand
, count(distinct oct.user_id) as counts
from 10월
inner join oct_ingarden oi
on oct.user_session = oi.user_session
and oi.event_time >= oct.event_time
where 1=1
and oct.event_type = 'cart'
and oct.brand != 'ingarden'
group by date, brand
-- 나머지 테이블도 join 후 union distinct
;
해당 쿼리로 불러온 데이터 중 cart 이벤트가 많았던 상위 5개의 브랜드를 월별로 추출하겠습니다.
(google colab python을 사용해 전처리했습니다.)
# 불러오기
df_ig = pd.read_csv(dir_path+'cart_something_remove_ingarden.csv')
date_origin = df_ig['date'].unique()
date_list = [re.sub(r'-', '_',i) for i in date_origin]
# 월별로 변수 분리
for i in range(len(date_list)) :
globals()['top5_counts_'+date_list[i]] = df_ig[df_ig['date']==date_origin[i]]
globals()['top5_counts_'+date_list[i]].sort_values(by='counts', ascending=False, inplace=True)
globals()['top5_counts_'+date_list[i]] = globals()['top5_counts_'+date_list[i]].head(5)
# 다시 concat
df_ig2 = pd.concat([globals()['top5_counts_'+date_list[i]] for i in range(5)], axis=0)
# 연도와 brand 순으로 정렬
df_ig2['date'] = pd.to_datetime(df_ig2['date'])
df_ig2.sort_values(by=['brand', 'date'], ascending=[False, True], inplace=True)
df_ig2.reset_index(drop=True, inplace=True)
df_ig_g = df_ig2.groupby('brand').mean('counts').sort_values(by='counts', ascending=False)
df_ig_g['rate'] = round(df_ig_g['counts'] / 4987.2, 2) # 4987.2는 remove_from_cart 평균
df_ig_g['rate'].sum()
위 테이블(Fig 28)은 ingarden이 cart에서 제거되기 전에 추가된 브랜드 중 상위 5개의 브랜드를 나타냅니다. 'rate' 컬럼은 ingarden의 remove_from_cart 이벤트 평균 대비 브랜드별 cart 이벤트 비율을 나타냈습니다. 위 6개의 브랜드가 총합 81%의 비율을 차지하고 있지만, 해당 브랜드의 영향으로 ingarden이 cart에서 제거됐다고 보기에는 근거가 부족해 보입니다.
고객이 동일한 세션을 유지하고 있는 상태에서, 새로운 제품이 cart에 추가되고 그에 따라 특정 제품이 제거되는 과정을 하나의 장바구니처럼 취급할 수 있다면,연관 규칙 분석을 시도해 볼 수 있을 것으로 생각됩니다. 해당 분석을 실시하기 위해 가정을 해 보겠습니다.
- remove_from_cart 이벤트를 발생시킨 고객의 user_id, event_time, user_session을 추출
- 1번 이벤트의 user_id와 user_session과 동일한 cart 이벤트 추출
- 2번 이벤트의 발생 시간이 1번 이벤트보다 빠른 조건으로 join
- 고객이 발생시킨 cart 이벤트와 remove_from_cart 이벤트 자체를, 하나의 장바구니처럼 취급
(예시 : user_id가 1이고 user_session이 aaaa인 고객이 장바구니에 'runail'과 'grattol'을 담고 'ingarden'을 뺐다면, 장바구니 = [runail, grattol, removed ingarden]) - lift가1인 규칙만 추출
(lift가 1을 초과하면 각 조건이 연관성을 가진다고 볼 수 있음)
연관 규칙 분석을 위해 데이터를 아래와 같이 추출합니다.
with oct_remove as (
select user_session
, event_time
, brand
, user_id
from 10월
where 1=1
and event_type = 'remove_from_cart'
)
, nov_remove as (
select user_session
, event_time
, brand
, user_id
from 11월
where 1=1
and event_type = 'remove_from_cart'
)
-- 나머지 테이블도 with절 서브쿼리로 작성
, test as (select
distinct oct.user_id as user_id
, oct.brand as competitor
, concat('removed ',orm.brand) as removed_brand
, oct.user_session
, format_date('%Y-%m-%d', oct.event_time) as date
from oct_remove orm
inner join 10월 oct
on orm.user_session = oct.user_session
and orm.user_id = oct.user_id
and orm.event_time >= oct.event_time
and orm.brand != oct.brand
where oct.event_type = 'cart'
union distinct
select
distinct nov.user_id as user_id
, nov.brand as competitor
, concat('removed ',nrm.brand) as removed_brand
, nov.user_session
, format_date('%Y-%m-%d', nov.event_time) as date
from nov_remove nrm
inner join 11월 nov
on nrm.user_session = nov.user_session
and nrm.user_id = nov.user_id
and nrm.event_time >= nov.event_time
and nrm.brand != nov.brand
where nov.event_type = 'cart'
-- 나머지 테이블도 union_distinct
)
select user_id
, user_session
, date
, array_agg(competitor) as competitor
, array_agg(removed_brand) as removed_brand
from test
group by user_id, user_session, date
order by date asc
;
bigquery의 array_agg 함수를 사용하면 집계된 데이터를 array 형태로 저장하고 json으로 불러올 수 있습니다.
저장된 json 데이터를 python으로 가공한 뒤 연관 규칙 분석을 진행합니다.
## json 불러오기
df = pd.read_json(dir_path + 'cart_and_removed_json.json', orient='records', lines=True)
## 리스트 형태의 데이터 합치기
df['all'] = df['competitor'] + df['removed_brand']
df['all'] = df['all'].apply(lambda x : list(set(x)))
brand_all = df['all'].to_list()
## mlxtend 라이브러리를 사용한 연관 규칙
te = TransactionEncoder() # 인코딩
te.fit(brand_all) # fit 후
brand_te = te.transform(brand_all) # 변환
brand_all_te = pd.DataFrame(data = brand_te, columns = te.columns_)
# apriori (최소 지지도 0.02)
frequency_brand = apriori(brand_all_te, min_support=0.02, use_colnames=True)
# 향상도를 기준으로 연관 규칙
asc_rules = association_rules(frequency_brand, metric="lift", min_threshold=1)
# 결과절이 removed ingarden인 것만 추출
sc_rules[asc_rules['consequents'].str.contains('removed ingarden', regex=False)].sort_values(by=['lift', 'confidence'], ascending=[False, False])
Fig 29는 ingarden이 cart에서 제거된 이벤트가 결과로써 발생한 경우를 추출한 데이터프레임입니다. ingarden이 cart에서 제거되기 전에 조건으로 발생한 cart 이벤트의 브랜드는 'runail', 'irisk', 'grattol'이 있습니다. 해당 브랜드 모두 lift(향상도)가 1 이상이기 때문에, 'runail', 'irisk', 'grattol'의 cart 이벤트와 ingarden의 remove_from_cart 이벤트는 연관성을 보인다고 볼 수 있습니다.
특히 (runail, ingarden)과 (ingarden, irisk)가 발생했을 때 removed_ingarden이 일어날 확률이 50%를 초과(confidence, 신뢰도)하고 lift도 5를 초과하는 강한 연관성을 보이는 것으로 보아, runail과 irisk, ingarden이 같이 cart에 담긴 후에 ingarden만 제거했을 가능성을 생각할 수 있습니다.
해당 규칙을 통해,
- remove된 ingarden 제품 특성과 카테고리를 잘 파악하여, 비슷한 runail, irisk 제품 재고를 충분히 확보(혹은 추천 시스템이나 푸시 알림을 통해, 해당 제품 입고를 알림)하여 runail과 irisk 판매 촉진
- ingarden 제품 경쟁력을 드러낼 수 있는 방법 고려
와 같은 행동을 고려할 수 있을 것입니다.
5. 배운 점, 어려웠던 점
5 - 1 배운 점
Google Drive 내 데이터를 BigQuery와 연동하는 법을 배울 수 있었습니다. 지난번 블로그 분석에서도 BigQuery를 통해 데이터를 가공하고 추출할 수 있었는데, 이번에 사용된 데이터의 row 수가 많아서(2천만 건 이상) 실제 로그 데이터를 다루는 듯한 느낌을 받을 수 있었습니다. 특히 group by로 집계할 때, array_agg 함수를 사용하면 string 형태의 데이터도 array로 묶어서 json으로 내보낼 수 있었던 점이 좋았습니다. 덕분에 연관 규칙 데이터 전처리 시간이 크게 줄었습니다.
시각화 툴은 Tableau를 사용해 봤는데, 차트를 다양한 형태로 전환하는 능력이 Looker Studio 보다는 뛰어난 느낌이었습니다. 블로그 분석을 할 때에는 고객의 단계별 전환이 일어나지를 않았어서 퍼널 분석이라고 하기 힘든 분석을 했었는데, 이번 데이터는 '구매'라는 확실한 단계와 전환이 존재해 단계별 퍼널 분석을 하기 용이했던 것 같습니다. 특히 데이터가 실제에 가까운 느낌이었는데(데이터에 사용된 브랜드가 실제 존재하는 브랜드), 실제 존재하는 기업이 kaggle 경진대회를 위해 제공한 데이터가 아니었을까? 하는 느낌이 드는 데이터였습니다.
중간에 퍼널 개선 계산을 잘못한 것을 알게 돼 수정한 일이 있었는데, 계산 결과가 달라지지 분석 방향이 달라지는 것을 알게 되었습니다. 계산 과정에서 상수와 수식 연결을 신중히 해 오류가 일어나지 않도록 해야겠습니다.
빅데이터 분석기사를 공부하면서 연관 규칙에 대해 이론으로만 알고 있었는데, SQL로 불러온 데이터를 Python으로 전처리 후 모델을 만들어 보는 경험을 해 볼 수 있어서 좋았습니다. 실제로 연관 규칙을 사용할 때는 같이 구매되는 제품과의 연관성을 파악하기 때문에 장바구니에 추가되고, 추가된 제품으로 인해 특정 제품이 장바구니에 제거됐는지에 대한 연관성을 파악하는 것이 정확한 분석인지는 모르겠습니다. 하지만 문서 요약에도 연관 규칙이 쓰인다고 하니 시도 자체는 나빴다고 보기는 힘들지 않을까....생각합니다. 분석가로 일하게 된다면 제품간 연관성 파악에 연관 규칙을 사용하도록 하겠습니다. 조금 더 개선한다면, 데이터 사이언티스트나 AI 엔지니어분들과 추천 시스템 개발에 기여할 수 있을지도 모르겠습니다.
5 - 2 어려웠던 점
Looker Studio랑 연동했던 것처럼 BigQuery는 Tableau와 연동이 가능합니다. 하지만 무료 버전에서는 해당 기능을 제공하지 않기에, 쿼리문으로 출력된 데이터셋을 csv와 json으로 저장한 뒤 불러와야 했습니다. Google Drive에 저장해도 원하는 경로와 파일명으로 저장되는 것이 아니기에, 경로와 이름을 바꾸는 것 때문에 작업 시간이 길어지는 어려움을 겪었습니다. 덕분에 데이터베이스와 BI 툴이 연동될 필요성을 느낄 수 있었습니다.
기획 초기에 user_id를 통해 cohort 분석을 진행할 수 있을 것이라고 생각했습니다. cohort 분석과 segmentation의 개념이 혼동돼 있었기 때문입니다. 하지만 고객의 유입시 정보가 없어서(특히 회원가입 날짜), cohort 분석을 할 수가 없었습니다. 단순하게 11월에 접속한 고객 중 10월에 접속하지 않았던 고객을 신규 방문으로 봐도 되지 않을까? 했지만, 그 고객들이 신규일 것이라는 확신은 없었습니다. 고객의 회원가입을 유도하여 가입 정보를 얻는다면, cohort와 LTV 파악이 용이할 것으로 생각됩니다(물론 너무 회원가입을 유도하면 불편한 경험이 될 것이기에...).