안녕하세요! 3-13 리텐션 과제 제출합니다. 2, 3번 과제의 경우 클로드의 도움을 조금 받았으며, 최대한 스스로 생각하고 검토만 받는 방향으로 진행하였습니다. 부족한 부분이나 더 생각해볼 수 있는 부분들 피드백 주시면 감사하겠습니다! 과제 링크 https://inquisitive-toy-5d0.notion.site/3c6bc12dee6d80dc9b2ed0e7d1c9a33c?source=copy_link
안녕하세요 카일님, 잘 듣고 있습니다. 강의 말미에서 app logs 데이터로 쿼리 연습 해보라고 말씀주셔서 아래와 같이 몇 가지 연습해 보았습니다. 더 정확한, 효율적인 쿼리가 있는지, 틀린 부분이 있다면 피드백 부탁드립니다. 1. Screen 탐색량이 가장 많은 유저 찾기 질문: 어떤 유저가 앱 내 screen을 가장 많이 탐색했는가? 목적: 유저별 screen 조회 횟수를 집계하여 heavy user 탐색. SELECT user_id, -- IF(event_params.key="firebase_screen", event_params.value.string_value, null) as screen, COUNT(*) as cnt_screen FROM advanced.app_logs CROSS JOIN UNNEST(event_params) as event_params WHERE event_params.key='firebase_screen' GROUP BY ALL HAVING user_id is not null ORDER BY cnt_screen DESC 2. 날짜별 Screen 조회량 및 Screen 구성 질문: 날짜별 전체 screen 조회량은 어떻게 변화하며, 각 screen은 얼마나 조회되었는가? 목적: Screen View의 시계열 변화와 screen별 조회량을 동시에 분석. double check 컬럼을 통해 정의한 screen들의 합계도 검증. WITH unnest_table as ( SELECT *, IF(event_params.key="firebase_screen", event_params.value.string_value, null) as screen FROM advanced.app_logs CROSS JOIN UNNEST(event_params) as event_params GROUP BY ALL HAVING screen is not null) SELECT event_date, count(screen) as total_screen_view, COUNTIF(screen IN ('cart','welcome', 'food_category', 'home', 'search_result', 'food_detail', 'search','restaurant')) as double_check, --검증용 컬럼 COUNTIF(screen='cart') as cart, COUNTIF(screen='welcome') as welcome, COUNTIF(screen='food_category') as food_category, COUNTIF(screen='home') as home, COUNTIF(screen='search_result') as serach_result, COUNTIF(screen='food_detail') as food_detail, COUNTIF(screen='search') as serach, COUNTIF(screen='restaurant') as restaurant FROM unnest_table GROUP BY ALL 3. Heavy User의 실제 Screen Journey 추적 질문: 특정 heavy user는 실제로 어떤 순서로 screen을 탐색하는가? 목적: Timestamp를 기준으로 사용자의 screen 이동 순서를 확인하고, firebaase screen 퍼널 순서 정의를 위한 탐색 수행. SELECT TIMESTAMP_MICROS(event_timestamp) as timestamp, if(event_params.key="firebase_screen", event_params.value.string_value, null) as screen FROM advanced.app_logs CROSS JOIN UNNEST(event_params) as event_params WHERE user_Id=57410 and event_date between '2022-08-01' and '2023-12-30' GROUP BY ALL HAVING screen is not null ORDER BY timestamp limit 100 4. Cart 도달 유저 vs Non-Cart 유저의 Screen 탐색량 비교 질문: Cart를 한 번이라도 조회한 유저는 그렇지 않은 유저보다 평균적으로 더 많은 screen을 탐색하는가? 목적: 사용자를 has_cart 여부로 segmentation하고 두 그룹의 평균 screen 탐색량 비교. WITH basic AS ( SELECT user_id, COUNT(*) AS screen_cnt_per_user, COUNTIF(event_params.value.string_value='cart') >0 AS has_cart FROM advanced.app_logs CROSS JOIN UNNEST(event_params) as event_params WHERE event_params.key='firebase_screen' GROUP BY user_id) SELECT AVG(IF(has_cart, screen_cnt_per_user,NULL )) as avg_view_cart, AVG(IF( not has_cart, basic.screen_cnt_per_user, null)) as avg_view_non_cart FROM basic unnest 와 집계함수를 연속적으로 쓰려고 할 때나 unnest+집계함수+having 쓰려고 할 때는 반드시 with문으로 분리해서 사용해야 오류가 안 나는 것 같더라고요. 그러다 보니 쿼리가 길어지는데 더 가독성 좋은 쿼리 작성법이 있을 것 같습니다. ㅎㅎ
안녕하세요 카일님, 강의 잘 듣고 있습니다. 연습문제 쿼리 작성해 보았는데 잘못된 부분이 있는지, 더 나은 쿼리 방식이 있다면 피드백 부탁드립니다 감사합니다. WITH basic AS (SELECT event_date, event_name, user_pseudo_id, event_params, if(event_params.key="firebase_screen", event_params.value.string_value, null) as screen FROM advanced.app_logs CROSS JOIN UNNEST(event_params) as event_params WHERE event_date between '2022-08-01' and '2022-08-18' ), basic2 as ( SELECT event_date, concat(event_name, '-', screen) as event_name_with_screen, COUNT(user_pseudo_id) as cnt FROM basic WHERE event_name in ('screen_view', 'click_payment') GROUP BY ALL HAVING event_name_with_screen is not null ORDER BY event_date) SELECT event_date, MAX(if(event_name_with_screen='screen_view-welcome', cnt, null)) as screen_view_welcome, MAX(if(event_name_with_screen='screen_view-restaurant', cnt, null)) as screen_view_restaurant, MAX(if(event_name_with_screen='screen_view-food_category', cnt, null)) as screen_view_food_category, MAX(if(event_name_with_screen='screen_view-food_detail', cnt, null)) as screen_view_food_detail, MAX(if(event_name_with_screen='screen_view-cart', cnt, null)) as screen_view_cart, MAX(if(event_name_with_screen='click_payment-cart', cnt, null)) as click_payment_cart, MAX(if(event_name_with_screen='screen_view-search', cnt, null)) as screen_view_search, MAX(if(event_name_with_screen='screen_view-search_result', cnt, null)) as screen_view_search_result FROM basic2 GROUP BY all ORDER BY event_date
퍼널 분석을 통한 Foodie Express의 비즈니스 인사이트를 도출하는 레포트를 작성하였습니다. 아래의 노션 링크 첨부하여 드립니다. 감사합니다. https://app.notion.com/p/6-1-3a96c0de4db680fda4d5f30c3ecc0b43?source=copy_link
안녕하세요. 리텐션 과제 제출합니다. 실무 기반의 문제라 그런지 역시 난이도가 있네요. 고민을 많이 해보게 되었습니다. 리텐션 유저 기준은 게임 업계 기준으로 정의하고 문제를 풀었습니다. (플랫폼에 따라서 기준도 다르고 하지만) 보시고 피드백 있으시면 말씀을 부탁드리겠습니다. https://app.notion.com/p/2b00de0d9a16809f94f5e378ee375b2f?source=copy_link
해당 리텐션 연습과제를 아래의 노션 링크에 담아 제출합니다. 2번과 3번과제는 너무 어려워서 AI의 도움을 받아 수행하였습니다. 많이 고민하는 계기가 되었고, 덕분에 노션도 처음 사용해보았습니다. 부족한 점은 없는지 피드백 주시면 감사하겠습니다. https://app.notion.com/p/3-13-3986c0de4db68063b1b9efa55c1d4b4f?source=copy_link
안녕하세요 강사님! 최종 과제 피드백 요청 드립니다🙇♀️ 로그 데이터 분석이 처음이라 데이터 해석부터 분석 스킬까지 부족한 점이 많습니다! 하지만, 강사님께서 처음부터 이해하기 쉽게 알려주신 덕분에 많이 배울 수 있었습니다. 저는 현재 CRM 마케터를 희망하고 있어, CRM 개선 전략을 목표로 분석을 진행해보았습니다. 바쁘시겠지만 피드백 주시면 앞으로의 역량 강화에 큰 도움이 될 것 같습니다 :) 감사합니다~! 과제 링크
--Weekly Retention WITH base AS( SELECT user_pseudo_id, event_name, DATE(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_date, DATE_TRUNC(DATE(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul'), WEEK(MONDAY)) AS event_week, FROM advanced.app_logs WHERE event_date BETWEEN '2022-08-01' AND '2022-11-03' ), first_week_data AS( #first_week 추출 SELECT DISTINCT user_pseudo_id, event_week, MIN(event_week) OVER(PARTITION BY user_pseudo_id) AS first_week, FROM base ), week_diff_user_cnt_data AS( #week_diff 및 user_cnt 추출 SELECT week_diff, COUNT(DISTINCT user_pseudo_id) AS user_cnt FROM( SELECT *, DATE_DIFF(event_week, first_week, WEEK(MONDAY)) AS week_diff FROM first_week_data ) GROUP BY week_diff ) #first_week_user_cnt 및 retention_ratio 추출 SELECT *, ROUND(SAFE_DIVIDE(user_cnt, first_week_user_cnt), 3) AS retention_rate FROM( SELECT *, FIRST_VALUE(user_cnt) OVER(ORDER BY week_diff) AS first_week_user_cnt FROM week_diff_user_cnt_data ) ORDER BY week_diff --Monthly Retention WITH base AS( SELECT user_pseudo_id, event_name, DATE(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_date, DATE_TRUNC(DATE(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul'), MONTH) AS event_month, FROM advanced.app_logs WHERE event_date BETWEEN '2022-08-01' AND '2022-11-03' ), first_month_data AS( #first_month 추출 SELECT DISTINCT user_pseudo_id, event_month, MIN(event_month) OVER(PARTITION BY user_pseudo_id) AS first_month, FROM base ), month_diff_user_cnt_data AS( #month_diff 및 user_cnt 추출 SELECT month_diff, COUNT(DISTINCT user_pseudo_id) AS user_cnt FROM( SELECT *, DATE_DIFF(event_month, first_month, MONTH) AS month_diff FROM first_month_data ) GROUP BY month_diff ) #first_month_user_cnt 및 retention_ratio 추출 SELECT *, ROUND(SAFE_DIVIDE(user_cnt, first_month_user_cnt), 3) AS retention_rate FROM( SELECT *, FIRST_VALUE(user_cnt) OVER(ORDER BY month_diff) AS first_month_user_cnt FROM month_diff_user_cnt_data ) ORDER BY month_diff 더 보완할 점은 없는지 평가해 주시면 감사하겠습니다. 강의 항상 정말 잘 듣고있습니다.
안녕하세요, 처음 인사드립니다! 분석 내용을 정리하다 보니 분량이 길어져 부득이하게 아래와 같이 3개의 페이지로 나누어 작성하였습니다. Food Express DAU·WAU·MAU 및 시간대별 패턴 분석 Food Express 퍼널 분석 Food Express 리텐션 및 코호트 분석 전체적인 흐름은 시계열 관점에서 DAU·WAU를 통해 전반적인 추세를 먼저 파악한 뒤, 퍼널 분석과 리텐션 분석으로 확장하는 방식 으로 구성하였습니다. 해석 과정에서는 가능한 한 개인적인 추측이나 과도한 주관을 배제하고, 데이터 기반으로 내용을 정리하고자 노력하였습니다. 아직 많이 부족하지만, 분석 기법의 적절성이나 논리 전개의 타당성 측면에서 보완이 필요한 부분이 있다면 편하게 조언해주시면 감사하겠습니다. https://www.notion.so/3097a7fdec7f802ca46cf2a615b3fc97?source=copy_link
안녕하세요, 티스토리에 구매 완료 작성글을 만든 후 gtm에서 디버깅을 해보려고 하는데 티스토리 미리보기에 들어가면 제가 쓴 작성글이 안보입니다! 혹시 몰라서 게시물을 비공개-->공개로 설정도 변경해봤는데 여전히 글이 안 나와서 확실히 설치가 된 건 지 알고 싶은데 방법이 있을까요?
안녕하세요 강사님의 디지털마케팅에 대한 강의를 듣고 공부하며 디지털 마케팅을 시작해보려는 사람인데요. 마케터를 위한 즐겨찾기/북마크에 대한 구글 sheet를 정리하여 공유 해주신 거 같은데, 해당 sheet에 대한 공유해주신 링크 부분을 확인하지 못하여 문의 드립니다. 강의 영상에 나와있는 링크 자체를 수동으로 입력을 해야하는 것인지, 아니면 별도로 공유를 해주셨는데 제가 찾지 못하는 것인지에 대해 문의 드리고자 합니다. 확인 후 말씀 한 번 주시면 감사드리겠습니다.
안녕하세요 카일스쿨님! BigQuery 기초편부터 활용편까지 유익하게 수강 중인 학생입니다 🙂 BigQuery 활용편 18강 "연결된 시트에서 매개 변수 사용하기" 부분에서 질문이 있습니다! 스샷 왼쪽(강의창)에서 선택하신 데이터 범위가 오른쪽(제 구글 시트 창)의 어떤 셀에 해당하는지 제가 잘 이해하지 못해서, 혹시 알려주실 수 있을까요~? 기술적인 내용이라 여쭤보기 민망하고 죄송스럽지만 가장 정확하게 답을 얻을 수 있을 것 같아 질문드립니다! 추신__ 에어팟 맥스처럼 귀에 챠악 감기는 강의 항상 감사합니당
-- Weekly 리텐션 -- 핵심 : event_date => event_week으로 변경하면 됨 -- 2024-06-30(일) => 2024년 26주차. 2024-06-24(월)도 같은 26주차 -- 데이터를 전처리(가공)하기 위해서 WEEK 함수를 사용할 수도 있고, DATE_TRUNC(일자, 자를 기준) -- DATE_TRUNC : 2024-06-30 => 2024-06-24 -- WEEK : 26. 2024년 26주차! 주차 별 date를 직관적으로 알기 어렵다고 생각하는 편(개인 생각) -- (깨알 지식) WEEK vs ISO_WEEK -- 주 번호를 계산할 때 사용할 수 있는 함수 -- WEEK : 일요일이 주의 첫 날로 간주. 1월 1일이 속한 주가 1주차 -- ISO_WEEK : 월요일이 주의 첫 날로 간주. ISO 8601 국제 표준에 따라 정의. 목요일이 속한 주를 기준으로 주 번호를 지정 -- 목요일이 속하면 그 주의 4일 이상이 포함되기 때문 -- 연도의 첫 목요일이 있는 주부터 1주차 -- 2022년 1월 1일(토요일) WEEK : 2022년 1주차. ISO_WEEK 2021년 52주차. -- 첫 목요일은 2022-01-06. 2022-01-03~2022-01-09가 2022년 1주차 WITH base AS ( SELECT DISTINCT user_id, user_pseudo_id, event_name, DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul')) AS event_date, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_datetime FROM advanced.app_logs WHERE event_date BETWEEN "2022-08-01" AND "2022-11-03" ), first_week_and_diff AS ( SELECT *, -- DATE_DIFF(event_date, first_date, DAY) AS diff_of_day DATE_DIFF(event_week, first_week, WEEK) AS diff_of_week FROM ( SELECT # 일자별로 중복 제거 DISTINCT user_pseudo_id, -- DATE_TRUNC DATE_TRUNC(MIN(event_date) OVER(PARTITION BY user_pseudo_id), WEEK(MONDAY)) AS first_week, DATE_TRUNC(event_date, WEEK(MONDAY)) AS event_week FROM base ) ), user_counts AS ( SELECT diff_of_week, COUNT(DISTINCT user_pseudo_id) AS user_cnt FROM first_week_and_diff GROUP BY diff_of_week ) SELECT *, ROUND(SAFE_DIVIDE(user_cnt, first_week_user_cnt), 2) AS retention_rate FROM ( SELECT diff_of_week, user_cnt, FIRST_VALUE(user_cnt) OVER(ORDER BY diff_of_week ASC) AS first_week_user_cnt FROM user_counts ) -- SELECT -- diff_of_week, -- COUNT(DISTINCT user_pseudo_id) AS user_cnt -- FROM first_week_and_diff -- GROUP BY diff_of_week -- ORDER BY diff_of_week # Monthly 리텐션 쿼리 작성해보기! 지금 코드가 각 diff_week마다 남은 유저들을 전체 유저로 나눠서 아 몇주차쯤 되면 얼마나 남아있는지를 계산한 거 같은데 생각해보니까 예를들어 지금 기간이 11월 3일까진데 한 10월 중순에 들어온 유저 같은 경우엔 diff_week가 한 3 이상인 부분부턴 아예 데이터가 없는거 아닌가요? 데이터가 11월 3일까지 밖에 없으니까요 분모로 사용하는 diff_week=0인 지점에서의 값은 그런 경우들까지 전부 포함된거고 그걸 그대로 모든 retention week마다 분모로 사용하면 위 예시 같은 경우 10월 중순 user들은 한 3주차쯤엔 전부 이탈하는 것 처럼 집계되는거 아닌가요? 그 경우 diff_week가 커질수록 실제 리텐션 보다 과소평가 되는게 아닌가 하는 의문점이 들어 문의 남깁니다
WITH base AS ( SELECT DISTINCT user_id, user_pseudo_id, event_name, DATE(DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul')) AS event_date, DATETIME(TIMESTAMP_MICROS(event_timestamp), 'Asia/Seoul') AS event_datetime FROM advanced.app_logs WHERE event_date BETWEEN "2022-08-01" AND "2023-08-03" ), first_week_and_diff AS ( SELECT *, DATE_DIFF(event_week, first_week, WEEK) AS weeks_after_first_week FROM ( SELECT DISTINCT user_pseudo_id, DATE_TRUNC(MIN(event_date) OVER(PARTITION BY user_pseudo_id), WEEK(MONDAY)) AS first_week, DATE_TRUNC(event_date, WEEK(MONDAY)) AS event_week FROM base ) ), user_counts AS ( SELECT first_week, weeks_after_first_week, COUNT(DISTINCT user_pseudo_id) AS active_users FROM first_week_and_diff GROUP BY first_week, weeks_after_first_week ) SELECT *, ROUND(SAFE_DIVIDE(active_users, cohort_users), 2) AS retention_rate FROM ( SELECT first_week, weeks_after_first_week, active_users, FIRST_VALUE(active_users) OVER(PARTITION BY first_week ORDER BY weeks_after_first_week ASC) AS cohort_users FROM user_counts ) ORDER BY first_week, weeks_after_first_week 수업때 사용했던 코드인데 제가 처음엔 지금 하고 있는 코호트 분석은 first_week(가입주) 마다 각자 시간이 흐르면서(기준은 week) 리텐션이 어떻게 바뀌는지를 보는 것 이라고 이해했었습니다 그래서 예를들어 첫 달 부터 확 떨어지면 이거 온보딩에 문제가 있는거 아닌가? 라는 문제정의를 하는 식의 생각을 할 수있다... 라고 이해하고 있었는데 다시 보니까 지금처럼 base에 날짜 조건을 필터링 하고 시작하면 min(event_date)를 걸어도 그게 실제 첫 가입일이 아닐 수 있는거 아닌가요? 예를들어 필터링 조건 이전인 2022년 7월에 가입을 한 사람이 2022년 10월에 다시 돌아왔다고 치면 이 경우 2022년 10월 가입 user로 집계되는거지 않나요? 그럼 본래 보려던 거랑 결이 달라지는게 아닌가 싶어서요