인프런 커뮤니티 질문&답변

진혁님의 프로필 이미지
진혁

작성한 질문수

BigQuery(SQL) 활용편(퍼널 분석, 리텐션 분석)

[인프런 빅쿼리 빠짝스터디 3주차] 리텐션 연습문제

작성

·

52

0

1)WeeklyRetention을구하는쿼리를바닥부터스스로작성해보세요

WITH event_log_base AS (
    SELECT DISTINCT
        DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_datetime,
        DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul')) AS event_date,
        DATE_TRUNC(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul'), WEEK(MONDAY)) AS event_week,
        DATE_TRUNC(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul'), MONTH) AS event_month,
        user_id,
        user_pseudo_id,
        event_name,
        platform,
        event_params
    FROM advanced.app_logs
),

user_first_visit AS (
    SELECT
        user_pseudo_id,
        MIN(event_week) OVER (PARTITION BY user_pseudo_id) AS first_visit_week,
        event_week
    FROM event_log_base
),


weekly_retention_base AS (
    SELECT
        first_visit_week,
        DATE_DIFF(event_week, first_visit_week, WEEK) AS week_diff,
        COUNT(DISTINCT user_pseudo_id) AS active_users
    FROM user_first_visit
    GROUP BY first_visit_week, week_diff
)


SELECT
    first_visit_week,
    week_diff,
    active_users,
    SAFE_DIVIDE(active_users, 
                FIRST_VALUE(active_users) OVER (PARTITION BY first_visit_week ORDER BY week_diff ASC)) AS retention_rate
FROM weekly_retention_base
ORDER BY first_visit_week, week_diff;

2)RetainUser를New+Current+Resurrected+DormantUser로나누는쿼리를 작성해보세요.

신규 사용자: 첫 방문 후 30일 이내에 활동한 사용자. 첫 방문 날짜와 마지막 방문 날짜 간의 차이가 30일 이하일 경우

현재 사용자: 첫 방문 후 30일이 지난 사용자 중, 최근 30일 이내에 접속한 사용자. 첫 방문과 마지막 방문 간 차이가 30일을 넘고, 가장 최근 활동으로부터 30일 이내에 접속한 경우

휴면 사용자: 마지막 방문 이후 30일 이상 비활동 상태에 있는 사용자. 마지막 방문이 가장 최근 이벤트로부터 30일 이상 경과한 경우

복귀 사용자: 30일 이상 비활동 상태였다가 다시 활동을 시작한 사용자. 이전 방문 이후 30일 동안 비활동이 이어지다 다시 방문한 경우

WITH event_data AS (
    SELECT DISTINCT
        DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul')) AS event_date,
        user_pseudo_id
    FROM advanced.app_logs
),

-- 사용자별 첫 방문 및 마지막 방문 날짜 계산
user_first_last_visit AS (
    SELECT
        user_pseudo_id,
        MIN(event_date) AS first_visit_date,
        MAX(event_date) AS last_visit_date
    FROM event_data
    GROUP BY user_pseudo_id
),

-- 전체 이벤트 데이터에서 가장 최근의 이벤트 날짜를 계산
latest_event_date AS (
    SELECT MAX(event_date) AS current_date
    FROM event_data
),

-- 사용자의 이벤트 로그를 통해 비활동 기간을 기록하여 휴면 여부 판단
user_activity AS (
    SELECT
        user_pseudo_id,
        event_date,
        LEAD(event_date) OVER (PARTITION BY user_pseudo_id ORDER BY event_date) AS next_event_date,
        CASE
            WHEN DATE_DIFF(LEAD(event_date) OVER (PARTITION BY user_pseudo_id ORDER BY event_date), event_date, DAY) > 30 THEN 1
            ELSE 0
        END AS dormant_history
    FROM event_data
),

-- 사용자 유형 분류: 신규, 현재, 휴면, 복귀 사용자
user_category AS (
    SELECT
        u.user_pseudo_id,
        u.first_visit_date,
        u.last_visit_date,
        led.current_date,
        MAX(ua.dormant_history) AS dormant_history,
        CASE 
            WHEN DATE_DIFF(led.current_date, u.last_visit_date, DAY) > 30 THEN 'inactive_user'
            WHEN DATE_DIFF(u.last_visit_date, u.first_visit_date, DAY) <= 30 THEN 'first_month_user'
            WHEN MAX(ua.dormant_history) = 1 THEN 'returning_user'
            ELSE 'active_user'
        END AS user_type
    FROM user_first_last_visit AS u
    CROSS JOIN latest_event_date AS led
    LEFT JOIN user_activity AS ua ON u.user_pseudo_id = ua.user_pseudo_id
    GROUP BY u.user_pseudo_id, u.first_visit_date, u.last_visit_date, led.current_date
),

-- 사용자 유형별 첫 방문 주차와 현재 주차 간 차이 계산
user_weekly_retention AS (
    SELECT
        uc.user_type,
        ed.user_pseudo_id,
        ed.event_date,
        DATE_DIFF(DATE_TRUNC(ed.event_date, WEEK(MONDAY)), DATE_TRUNC(uc.first_visit_date, WEEK(MONDAY)), WEEK) AS week_difference
    FROM event_data AS ed
    JOIN user_category AS uc ON ed.user_pseudo_id = uc.user_pseudo_id
),

-- 사용자 유형과 주차별 활성 사용자 수 집계
user_count_by_type_and_week AS (
    SELECT
        user_type,
        week_difference,
        COUNT(DISTINCT user_pseudo_id) AS user_count
    FROM user_weekly_retention
    GROUP BY user_type, week_difference
),

-- 유지율 계산을 위한 초기 사용자 수와 현재 주차별 유지율 계산
retention_calculation AS (
    SELECT
        user_type,
        week_difference,
        user_count,
        FIRST_VALUE(user_count) OVER (PARTITION BY user_type ORDER BY week_difference) AS initial_user_count
    FROM user_count_by_type_and_week
)

SELECT
    user_type,
    week_difference,
    ROUND(SAFE_DIVIDE(user_count, initial_user_count), 2) AS retention_rate
FROM retention_calculation
ORDER BY user_type, week_difference;

3)주어진데이터에서어떤사람들이리텐션이그나마높을까요?찾아보세요

2번을 참고해서 고객을 4개의 타입으로 분류하였을 때

first_month_user: 첫 주 이후 리텐션이 높지만 이후 감소하는 모습을 보인다.

 

active_user: first_month_user와 비슷하게 첫 주 이후 빠르게 감소한다.

 

returning_user: 2주부터 0.08로 떨어지지만 이후 완만하게 리텐션이 감소한다.

오랜기간 10주차 이후에도 일부 사용자가 유지되고 있는 모습을 보인다.

 

inactive_user: 리텐션이 다른 유저에 비해 높다고는 할 수 없지만 20주차까지 꾸준하게 소수의사용자가 유지되고 있는 모습을 보인다.

 

--> 따라서 returning_use이 가장 완만하게 리텐션이 감소, 가장 오랫동안 리텐션이 지속했기때문에 가장 높은 리텐션을 유지했다고 판단하였습니다.

 

 

4)CoreEvent를“click_payment”라고설정하고WeeklyRetention을구해주세요

WITH event_data AS (
    SELECT DISTINCT
        user_pseudo_id,
        DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul')) AS event_date,
        DATE_TRUNC(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul'), WEEK(MONDAY)) AS event_week,
        event_name
    FROM advanced.app_logs
    WHERE event_name = 'click_payment'  -- Core event 필터링
),

-- 사용자별 첫 방문 주차와 현재 이벤트 주차 간의 차이 계산
user_first_week_data AS (
    SELECT
        user_pseudo_id,
        MIN(event_week) OVER (PARTITION BY user_pseudo_id) AS first_visit_week,
        event_week AS current_week,
        DATE_DIFF(event_week, MIN(event_week) OVER (PARTITION BY user_pseudo_id), WEEK) AS week_difference
    FROM event_data
),

-- 주차별 사용자 수 집계
user_count_by_week AS (
    SELECT
        first_visit_week,
        week_difference,
        COUNT(DISTINCT user_pseudo_id) AS user_count
    FROM user_first_week_data
    GROUP BY first_visit_week, week_difference
    ORDER BY first_visit_week, week_difference
),

-- 유지율 계산을 위한 초기 사용자 수와 주차별 유지율 계산
retention_base AS (
    SELECT
        first_visit_week,
        week_difference,
        user_count,
        FIRST_VALUE(user_count) OVER (PARTITION BY first_visit_week ORDER BY week_difference) AS initial_user_count
    FROM user_count_by_week
)

-- 최종 리텐션 비율 계산 및 결과 출력
SELECT
    first_visit_week,
    week_difference,
    ROUND(SAFE_DIVIDE(user_count, initial_user_count), 2) AS retention_rate
FROM retention_base
ORDER BY first_visit_week, week_difference;


답변 1

0

안녕하세요, 인프런 AI 인턴입니다.

질문하신 자료에서 리텐션 분석을 위한 SQL 쿼리를 제공하셨네요! 각 항목에 대한 적절한 가이드와 관련된 내용을 제공합니다.

  1. Weekly Retention 쿼리 작성하기:

    • 주어진 쿼리로 잘 작성하셨습니다. 하지만 리텐션 비율 계산 부분에서 SAFE_DIVIDE로 나누기를 안전하게 처리하고 있으므로 나누는 수가 0일 가능성을 고려했습니다. 이는 쿼리를 실행할 때 생길 수 있는 오류를 방지하는 유용한 방법입니다.
  2. 사용자 분류 쿼리 (신규, 현재, 휴면, 복귀 사용자):

    • 각 사용자 유형을 명확하게 구분하고 있으며, 사용자가 30일 기준으로 어떤 유형에 속하는지 분류하고 있어 분석에 실용적입니다. 쿼리가 긴 만큼, 각 스텝별로 결과물이 정확히 나오는지 추가적인 테스트 쿼리를 실행하여 검증하실 것을 권장드립니다.
  3. 어떤 사람들이 리텐션이 가장 높은지 찾기:

    • 이 부분에서는 분석 보고서를 작성할 때 각 사용자 유형의 특징과 그들이 어떻게 리텐션에 영향을 미치는지를 설명하는 것이 중요합니다. 질문에도 설명이 포함되어 있지만, 각 유형별 수치와 그래프를 첨부하면 더욱 명확한 이해가 가능합니다.
  4. Core Event를 ‘click_payment’로 설정한 Weekly Retention:

    • Core Event를 설정하여 이벤트 중심의 리텐션 분석을 진행하는 것은 매우 유익한 방법입니다. 특히, 구매 이벤트를 중심으로 리텐션을 분석함으로써 실질적인 비즈니스 성과를 파악할 수 있습니다. 쿼리로서 적절하게 계산식과 집계가 이루어지고 있습니다.

추가로 관련된 사례와 해결 방안들이 아래의 질문 및 답변에서 유용할 수 있으니 참고하시기 바랍니다:
- 4-8. 지표 정의 연습 문제 풀이 답변 올려볼게요!

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

진혁님의 프로필 이미지
진혁

작성한 질문수

질문하기