▶ 이전 포스팅 에 적혀있던 분석 목표와 방향
데이터 확인
SELECT *
FROM 2019dec
LIMIT 20;
더 많은 내용은 이전 포스팅에서 확인 가능
파악한 문제점
event_type에서 cart > purchase
로 간 데이터보다 cart > remove_from_cart
로 간 비율이 더 많다. 그 이유가 무엇일까?
SELECT COUNT(DISTINCT ct.user_id, ct.user_session) AS cart_count
, COUNT(DISTINCT pt.user_id, pt.user_session) AS purchase_count
, COUNT(DISTINCT pt.user_id, pt.user_session) / COUNT(DISTINCT ct.user_id, ct.user_session) AS cart_purchase_ratio
-- , COUNT(DISTINCT rt.user_id, rt.user_session) / COUNT(DISTINCT vt.user_id, vt.user_session) AS view_remove_ratio #이건 의미가 없는 값인 것 같은데. 전체 뷰에서 삭제를 봐서 뭐하지
FROM ct
LEFT JOIN pt ON ct.user_id = pt.user_id
AND ct.user_session = pt.user_session
AND ct.event_time <= pt.event_time;
cart_count | remove_count | cart_remove_count |
---|---|---|
165571 | 23475 | 0.1418 |
🔼 카트에 담긴 14.18% 만이 구매로 이어진다.
SELECT COUNT(DISTINCT ct.user_id, ct.user_session) AS cart_count
, COUNT(DISTINCT rt.user_id, rt.user_session) AS remove_count
, COUNT(DISTINCT rt.user_id, rt.user_session) / COUNT(DISTINCT ct.user_id, ct.user_session) AS cart_remove_ratio
FROM ct
LEFT JOIN rt ON ct.user_id = rt.user_id
AND ct.user_session = rt.user_session
AND ct.event_time <= rt.event_time;
cart_count | remove_count | cart_remove_count |
---|---|---|
165571 | 59823 | 0.3613 |
🔼 36.13% 정도가 카트에 들어갔다가 삭제된다.
가설
순번 | 가설 | 세부내용 | 확인방법 |
---|---|---|---|
1 | 특정 브랜드 문제 | 특정 브랜드에서 많이 발생해 제거율이 높아졌는가? | 브랜드 별 카트 제거 이벤트 수 비교 |
2 | 특정 제품 문제 | 특정 제품에서 카트 제거 이벤트가 많이 발생했는가? | 제품 별 카트 제거 이벤트 수 비교 |
3 | 단순변심 | 카트에 넣었다가 뺐다가 다시 넣는 경우 | 조건에 해당하는 데이터 수를 추출하여 확인 |
4 | 가격 비교 | 일단 카트에 넣었다가 더 저렴한 곳을 찾아 구매한 경우 | category_id에 다른 가격대 물건이 얼마나 있는지 파악 |
5 | 할인 쿠폰 | 쿠폰을 사용하려고 했으나 적용되지 않거나 기대한 만큼 할인이 되지 않아서 구매를 취소하는 경우 | 프로모션 추가 데이터 필요 |
위와 같이 생각해볼 수 있다.
데이터를 통해 어떤 현상이 있는지 살펴본다.
진행 내용
가설 1 : 특정 브랜드 문제 - 가은, 소리
🔼 brand에 null값이 큰 비중을 차지해 제일 상단에 위치했다. 현재 결과에서는 특정 브랜드의 문제인지 확인하기가 어렵다.
🔼 cart
에 많이 담길 수록 remove_from_cart
가 되는 값도 많을 것이다. 비율로 크게 튀는 값이 있는지 확인한다.
➡️ 0.5에서 0.9 사이까지 골고루 있어 눈에 띄는 브랜드가 있진 않지만, 1에 가까운 브랜드에 대해 문제가 없다고 판단해도 될까요?
가설 2: 특정 제품 문제 - 소리, 예나
🔼 5809912 제품이 8828번 카트에서 제거되었다. (left join c_to_r 테이블을 활용했을 때)
cart
에 많이 담길 수록 remove_from_cart
가 되는 값도 많을 것이다. 제품이 카트에서 제거되는 횟수/ 카트에 담긴 횟수를 확인해보자🔍 cart_counts 수로 정렬한 테이블
🔼 cart_counts 수로 정렬한 테이블을 확인했을 때 ratio 값이 큰 제품으로 이슈가 되는 특정 제품을 추릴 수 있다.
🔍 ratio로 정렬한 테이블
🔼 테이블에서 1을 넘는 product_id 데이터를 확인하였다. 값이 매우 큰 경우 39배에 달하는 데이터를 포착했다.
➡️ 가설을 푸는 방향이 맞는지 확신이 없습니다.
가설 3 : 단순 변심 - 가은, 예나, 소리
cart > purchase
로 넘어가는 시간 파악SELECT product_id, AVG(time_gap) AS gap
FROM (
SELECT ct.*
, pt.event_time AS remove_event_time
, TIMESTAMPDIFF(SECOND, ct.event_time, pt.event_time) / 86400 AS time_gap -- 1일 기준
FROM ct
LEFT JOIN pt ON ct.user_id = pt.user_id
AND ct.user_session = pt.user_session
AND ct.product_id = pt.product_id
AND ct.event_time <= pt.event_time) t3
GROUP BY product_id
ORDER BY gap DESC;
🔼 평균적으로 당일부터 16일까지 시간 차이가 있다.
cart > remove_from_cart
로 넘어가는 시간🔼 평균적으로 당일부터 23일까지 시간 차이가 있다.
➡️ 그러나 기준점이 없어서 결과에 대한 판단 불가능
➡️ 위 코드가 가설을 확인하기 위한 방향이 맞는지 궁금합니다. 이 방향이 아니라면 이 상황에서 어떻게 일시적인 관심을 데이터로 확인할 수 있을까요?
remove_from_cart > cart
로 다시 간 경우 횟수➡️ 이 때 cart > remove > purchase
수를 세었기 때문에
cart → remove → cart → remove → purchase
의 경우의 수가 누락되었음. 위에 것까지 포함해야 해야하는지 고민
➡️ 12월에 remove_from_cart가 일어난 이벤트 수는 총 664,655 건.
이 중 단순 변심은 약 11만건 이상이다. 라고 얘기하면 나머지 55만건은 그냥 안 산 것이라고 생각해도 될지 에 대한 궁금증
➡️ 가설을 푸는 방향이 맞는지 확신이 없습니다.
가설 4 : 가격 비교 - 소리
더 저렴한 제품을 찾아서 이동한 것일까 가설을 생각했을 때, 이를 확인하기 위해서
product_id와 카테고리 별 평균 가격과 표준편차를 비교하였다.
WITH cart_count AS (
SELECT DISTINCT product_id, category_id, brand, price
, COUNT(product_id) OVER (PARTITION BY product_id) AS count
FROM ct
), remove_count AS (
SELECT DISTINCT product_id, category_id, brand, price
, COUNT(product_id) OVER (PARTITION BY product_id) AS count
FROM rt
), avg_price AS(
SELECT category_id, ROUND(AVG(price),2) AS avg_price, ROUND(STD(price),2) AS std
FROM 2019dec
GROUP BY category_id
), main AS (
SELECT DISTINCT cc.product_id
, cc.category_id
, cc.brand
, cc.price
, rc.count AS remove_counts
, cc.count AS cart_counts
, COALESCE(rc.count, 0) / cc.count AS ratio
FROM remove_count rc
INNER JOIN cart_count cc ON rc.product_id = cc.product_id
AND rc.brand = cc.brand
AND rc.price = cc.price
ORDER BY ratio DESC
)
SELECT m.*, a.avg_price, a.std
FROM main m
LEFT JOIN avg_price a ON m.category_id = a.category_id;
➡️ remove/cart 비율이 높은 순으로 확인했을 때 표준편차가 어느 정도 있음을 발견하였다.
(1.38 평균 가격에 0.59 표준편차는 약 +- 43% 변동범위 가 있다고 볼 수 있다)
➡️ 제품 하나하나가 아닌 전체적인 그림으로 해석할 수 있을까요?
고민 지점
1. 가장 큰 고민은 가설을 세우는 부분에서 확신이 없다는 것입니다. 가설을 세우고 쿼리로 검증하는 과정에서 계속 풀어내는 방향이 맞는지 확신이 없습니다. 계속 가설을 푸는 과정에서 또 다른 가설이 생기면서 결론 없이 쳇바퀴 도는 느낌입니다.
그래서 가설 2, 3, 4의 방향이 맞는 것인지, 더 나은 방법이 있는지 궁금합니다.
2. 분석 시 초기 테이블을 만들 때 2가지 방향으로 갈렸는데, 어떤 게 현재 데이터에서 더 적절한지 궁금합니다.
event_type에만 조건을 줘서 remove_from_cart
인 데이터와 cart
인 데이터로 쿼리 작성
WITH removed AS (
SELECT brand, COUNT(product_id) AS removed_cnt
FROM dec19
WHERE event_type = 'remove_from_cart'
GROUP BY brand
ORDER BY removed_cnt DESC
), cart AS (
SELECT brand, COUNT(product_id) AS cart_cnt
FROM dec19
WHERE event_type = 'cart'
GROUP BY brand
ORDER BY cart_cnt DESC
), purchased AS (
SELECT brand, COUNT(product_id) AS purchased_cnt
FROM dec19
WHERE event_type = 'purchase'
GROUP BY brand
ORDER BY purchased_cnt DESC
)
SELECT cart.brand
, cart_cnt
, removed_cnt
, ROUND(removed_cnt/cart_cnt,2) AS removed_rate
, purchased_cnt
, ROUND(purchased_cnt/cart_cnt,2) AS purchased_rate
FROM cart LEFT JOIN removed ON cart.brand = removed.brand
LEFT JOIN purchased ON purchased.brand = cart.brand
WHERE cart.brand IS NOT NULL
ORDER BY cart_cnt DESC;
event_type을 조건으로 vt, ct, pt, rt
테이블을 생성하고 (각각 view, cart, purchase, remove_from_cart table
)
event_time 순서를 적용해
v_to_c, c_to_p, c_to_r
테이블을 생성하여 쿼리 작성
CREATE TEMPORARY TABLE vt AS
SELECT user_id, user_session, event_time, category_id, product_id, brand, price
FROM 2019dec
WHERE event_type = 'view';
CREATE TEMPORARY TABLE ct AS
SELECT user_id, user_session, event_time, category_id, product_id, brand, price
FROM 2019dec
WHERE event_type = 'cart';
CREATE TEMPORARY TABLE pt AS
SELECT user_id, user_session, event_time, category_id, product_id, brand, price
FROM 2019dec
WHERE event_type = 'purchase';
CREATE TEMPORARY TABLE rt AS
SELECT user_id, user_session, event_time, category_id, product_id, brand, price
FROM 2019dec
WHERE event_type = 'remove_from_cart';
CREATE TEMPORARY TABLE v_to_c AS -- 같은 아이디, 같은 세션, 같은 제품에 대해서 view 후 cart에 넣은 데이터들을 추출하는 테이블
SELECT vt.*
, ct.event_time AS cart_event_time
, TIMESTAMPDIFF(SECOND, vt.event_time, ct.event_time) AS time_gap
FROM vt
LEFT JOIN ct ON vt.user_id = ct.user_id -- left join 매칭으로 갯수가 더 커지는 이슈 있음
AND vt.user_session = ct.user_session
AND vt.product_id = ct.product_id
AND vt.event_time <= ct.event_time;
CREATE TEMPORARY TABLE c_to_r AS -- 같은 아이디, 같은 세션, 같은 제품에 대해서 카트를 넣은 시간보다 카트 제거한 시간이 더 늦을 경우에 속하는 값들을 추출하는 테이블
SELECT ct.*
, rt.event_time AS remove_event_time
, TIMESTAMPDIFF(SECOND, ct.event_time, rt.event_time) AS time_gap
FROM ct
LEFT JOIN rt ON ct.user_id = rt.user_id
AND ct.user_session = rt.user_session
AND ct.product_id = rt.product_id
AND ct.event_time <= rt.event_time;
CREATE TEMPORARY TABLE c_to_p AS -- 같은 아이디, 같은 세션, 같은 제품에 대해서 카트에 넣고 구매로 이어진 값을 추출하는 테이블
SELECT ct.*
, pt.event_time AS purchase_event_time
, TIMESTAMPDIFF(SECOND, ct.event_time, pt.event_time) AS time_gap
FROM ct
LEFT JOIN pt ON ct.user_id = pt.user_id
AND ct.user_session = pt.user_session
AND ct.product_id = pt.product_id
AND ct.event_time <= pt.event_time;
3. 해당 프로젝트의 결론을 어떤 식으로 내야하는 지 궁금합니다.