일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 데이터 증식
- sql
- 캐글 신용카드 사기 검출
- 인프런
- lightgbm
- tableau
- 3기가 마지막이라니..!
- WITH ROLLUP
- pmdarima
- python
- XGBoost
- 분석 패널
- 로그 변환
- 마케팅 보다는 취준 강연 같다(?)
- 데이터 핸들링
- 그룹 연산
- 리프 중심 트리 분할
- 컨브넷
- 부트 스트래핑
- 스태킹 앙상블
- 데이터 정합성
- ImageDateGenerator
- 그로스 마케팅
- 캐글 산탄데르 고객 만족 예측
- Growth hacking
- splitlines
- ARIMA
- 그로스 해킹
- WITH CUBE
- DENSE_RANK()
- Today
- Total
LITTLE BY LITTLE
[14] 사이트 내의 사용자 행동 파악하기(1) - landing/exit 페이지 파악하기, 이탈률/직귀율 계산하기, 성과로 이어지는 페이지 파악하기, 페이지 가치 산출하기 본문
[14] 사이트 내의 사용자 행동 파악하기(1) - landing/exit 페이지 파악하기, 이탈률/직귀율 계산하기, 성과로 이어지는 페이지 파악하기, 페이지 가치 산출하기
위나 2024. 2. 25. 18:48
목차
3. 데이터 가공을 위한 SQL 3-1. 하나의 값 조작하기 (5강) 3-2. 여러 개의 값에 대한 조작 (6강) 3-3. 하나의 테이블에 대한 조작 (7강)3-4. 여러 개의 테이블 조작하기 (8강)4. 매출을 파악하기 위한 데이터 추출 4-1. 시계열 기반으로 데이터 집계하기 (9강)4-2. 다면적인 축을 사용해 데이터 집약하기 (10강)
5. 사용자를 파악하기 위한 데이터 추출 5-1. 사용자 전체의 특징과 경향 찾기 (11강) 5-2. 시계열에 따른 사용자 전체의 상태 변화 찾기 (12강)
5-3. 시계열에 따른 사용자의 개별적인 행동 분석하기 (13강)
6. 웹사이트에서 행동을 파악하는 데이터 추출하기 6-1. 사이트 전체의 특징/경향 찾기
6-2. 사이트 내의 사용자 행동 파악하기
6-3. 입력 양식 최적화하기
7. 데이터 활용의 정밀도를 높이는 분석 기술
7-1. 데이터를 조합해서 새로운 데이터 만들기
7-2. 이상값 검출하기
7-3. 데이터 중복 검출하기
7-4. 여러 개의 데이터셋 비교하기
8. 데이터를 무기로 삼기 위한 분석 기술
8-1. 검색 기능 평가하기
8-2. 데이터 마이닝
8-3. 추천
8-4. 점수 계산하기
9. 지식을 행동으로 옮기기
9-1. 데이터 활용의 현장
※ Mysql 기준
6장. 웹사이트에서의 행동을 파악하는 데이터 추출하기
15강. 사이트 내의 사용자 행동 파악하기
웹사이트에서의 특징적인 지표 (방문자 수, 방문 횟수, 직귀율, 이탈률) 리포트를 작성하는 SQL 쿼리 소개
Create할 때 참고
CREATE TABLE activity_log(
stamp varchar(255),
session varchar(255),
action varchar(255),
`option` varchar(255), -- 백틱(`)을 사용하여 예약어를 이스케이프하기
path varchar(255),
search_type varchar(255)
);
15-1. 입구 페이지와 출구 페이지 파악하기
FIRST_VALUE 함수, LAST_VALUE 함수, 입구 페이지, 출구 페이지
- 입구 페이지는 사이트에 방문했을 때 처음 접근한 페이지로, 랜딩 페이지라고도 부름
- 출구 페이지는 마지막으로 접근한 페이지로, 이탈한 페이지를 나타냄
type(landing/exit)에 따른 경로와 입구(출구) 수를 집계하기
WITH activity_log_with_landing_exit AS(
SELECT
session,
path,
stamp,
FIRST_VALUE(path) OVER(PARTITION BY session
ORDER BY stamp ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
AS landing,
LAST_VALUE(path) OVER(PARTITION BY session
ORDER BY stamp ASC
ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
AS 'exit' -- MYSQL에서는 option, exit과 같은 단어는 예약어이기 때문에, alias로 사용시 backticks를 붙여줘야 함
FROM activity_log)
SELECT * FROM activity_log_with_landing_exit;
→ Session 별로 stamp 의 path 중 FIRST_VALUE를 landing으로 추가, LAST_VALUE를 exit으로 추가한 모습
추출한 각 세션의 입구 페이지와 출구 페이지의 URL을 기반으로 유니크한 세션의 수를 집계하여 방문 횟수 구하기
-- 앞 쿼리 동일
,
landing_count AS(
SELECT
landing AS path,
COUNT(DISTINCT session) AS count
FROM activity_log_with_landing_exit
GROUP BY landing),
exit_count AS(
SELECT
'exit' AS path,
COUNT(DISTINCT session) AS count
FROM activity_log_with_landing_exit
GROUP BY 'exit')
SELECT
'landing' AS type,
path,
count
FROM landing_count
UNION ALL
SELECT 'exit' AS type,
path,
count
FROM exit_count;
→ 마지막에 UNION ALL 할 때 >SELECT 'landing' AS type, * FROM ~ 은 실행되지 않음
→ 이유는 UNION(ALL)사용 시 테이블의 컬럼명과 컬럼수가 동일해야 하는데, AS type으로 새로운 컬럼을 추가해주었기 때문에, SELECT 절에 양쪽의 구조가 동일하다는 사실을 표시해주어야 함
세션 별 입구 페이지와 출구 페이지의 조합 집계하기
-- activity_log_with_landing_exit 까지 동일
SELECT
landing,
'exit',
COUNT(DISTINCT session) AS count
FROM activity_log_with_landing_exit
GROUP BY landing, 'exit';
→ 웹사이트 담당자는 최상위 페이지부터 사이트 설계를 시작하지만, 최상위 페이지부터 조회를 시작하는 사용자는 거의 없다.
→ 상세 페이지부터 조회를 시작하는 사용자가 많은 사이트도 존재하기에, 사용자가 어디에 유입되는지 입구 페이지를 파악하면 사이트 설계 시 도움이 될 것
15-2. 이탈률과 직귀율 계산하기
ROW_NUMBER 함수, COUNT 윈도 함수, AVG(CASE~END)
책에서의 이탈률 = 종료율
책에서의 직귀율 = 이탈율(아무것도 안하고 나갔을 때)
앞서 구한 출구 페이지를 사용해서 이탈률을 계산하고, 문제가되는 페이지 찾아내기
- 직귀율은 '특정 페이지만 조회하고 곧바로 이탈한 비율'- 단순하게 이탈률이 높은 페이지는 나쁘다고 할 수 없다. 사용자가 만족해서 이탈하는 페이지(ex.구매 완료 페이지)는 당연히 이탈률이 높아야 하기 때문에 문제가 되지 않음
이탈률 리포트(경로 별 출구 수, 페이지 뷰, 이탈률 집계) 생성
- 경로별 이탈률 집계하기
: CASE문으로 각 세션의 마지막 활동(가장 최근의 stamp)에 대해 is_exit 플래그를 1로 설정하여 집계
WITH activity_log_with_exit_flag AS(
SELECT *,
CASE WHEN
ROW_NUMBER() OVER(PARTITION BY session
ORDER BY stamp DESC) = 1 THEN 1 END AS is_exit
FROM activity_log)
SELECT
path,
SUM(is_exit) AS exit_count,
COUNT(*) AS page_view,
AVG(100.0 * COALESCE(is_exit, 0)) AS exit_ratio
FROM activity_log_with_exit_flag
GROUP BY path;
- 직귀율 집계하기
직귀율 = <직귀 수> / <입구 수> 혹은 <방문 횟수>
→ 순수하게 랜딩 페이지에서 다른 페이지로 이동하는지를 평가하기 위해 전자의 식 사용(직귀수 / 입구 수)
* 직귀율이 높은 원인
- 연관 기사 또는 상품으로 사용자를 이동시키는 모듈이 않아서
- 페이지 자체의 콘텐츠에 사용자가 만족하지 않는 경우
- 이동이 복잡해서 다음 단계로 이동하지 못하는 경우
직귀율 리포트(경로 별 직귀 수, 입구 수, 직귀율) 작성하기
- is_landing 플래그와 is_bounce(세션 당 count수가 1=직귀) 플래그를 설정
path가 랜딩 페이지인 경우 is_bounce에 해당하는, 즉 사이트에 들어와서 첫 페이지만 보고 바로 나간 비율(직귀율) 계산
※ ROW_NUMBER()
1. 첫 번째와 맨 끝 값을 찾아내고 싶을 때
2. 중복된 값을 제거하고 싶을 때 (조인 후 넘버링)
※ 직귀 판정 식
-- 직귀 판정
CASE WHEN
COUNT(*) OVER(PARTITION BY session) = 1 THEN 1 ELSE 0 END AS is_bounce
WITH activity_log_with_landing_bounce_flag AS(
SELECT
*,
CASE WHEN
-- 입구 페이지 판정 플래그 is_landing
ROW_NUMBER() OVER(PARTITION BY session
ORDER BY stamp ASC) = 1 THEN 1 ELSE 0 END AS is_landing,
-- 직귀 판정(세션 별 카운트 수가 1번인 경우) 플래그 is_bounce
CASE WHEN
COUNT(*) OVER(PARTITION BY session) = 1 THEN 1 ELSE 0 END AS is_bounce
FROM activity_log)
SELECT
path,
SUM(is_bounce) AS bounce_count,
SUM(is_landing) AS landing_count,
AVG(100.0 * CASE WHEN is_landing = 1 THEN is_bounce END) AS bounce_ratio
FROM activity_log_with_landing_bounce_flag
GROUP BY path;
15-3. 성과로 이어지는 페이지 파악하기
SIGN 함수, SUM 윈도 함수, CVR
성과와 직결되는 페이지를 파악하고 유도하여 웹사이트 전체의 CVR을 향상시킬 수 있다.
1. 페이지 또는 경로에 대한 방문 횟수
2. 방문이 성과로 연결되는지 집계하기
*보충 자료
https://noelee.tistory.com/217
1. activity_log_with_conversion_flag
: 컨버전 페이지보다 이전 접근에 플래그 추가하기
목적
: 세션별 전환 여부 판단
▼
세션별로 complete까지 갔는지 여부 체크하기
▼
세션이 complete를 포함하고 있을 경우 플래그를 추가하고, 세션의 sum이 1이 넘는지 확인하기
▼
sum(case when path = '/complete'~) 를 사용해서 각 세션에서 경로가 complete인 이벤트가 발생했는지 합산하기
& over(partition by~ orderby~)로 세션별로, stamp가 최신인 순서대로, old부터 현재까지로 윈도우를 정의
WITH activity_log_with_conversion_flag AS(
SELECT
session,
stamp,
path,
SIGN(SUM(CASE WHEN path = '/complete' THEN 1 ELSE 0 END)
OVER(PARTITION BY session ORDER BY stamp DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW))
AS has_conversion
FROM activity_log)
SELECT * FROM activity_log_with_conversion_flag
ORDER BY session, stamp;
SELECT
path,
COUNT(DISTINCT session) AS sessions,
SUM(has_conversion) AS conversions,
1.0 * SUM(has_conversion) / COUNT(DISTINCT session) AS cvr
FROM activity_log_with_conversion_flag
GROUP BY path;
→ 상품 구매, 자료 청구, 회원 등록이 성과라면, 성과 직전에 있는 페이지는 CVR이 높게 측정된다는 점을 고려하기
→ 같은 계층의 콘텐츠, 유사한 콘텐츠끼리 비교하는 것이 유의미할 것
15-4. 페이지 가치 산출하기
ROW_NUMBER(), 페이지 평가
- 특정 페이지를 경유한 사용자가 더 높은 성과로 이어진다면, 사이트 맵을 변경해서 해당 페이지를 경유하게 만들거나, 해당 페이지의 콘텐츠와 광고를 다른 페이지에도 적용하는 것이 좋다.
- 앞서 사용한 방법에 추가로 '금액' 개념을 사용해서 성과를 고려하는 "페이지 가치" 지표를 사용하면 더 자세하게 페이지를 분석할 수 있다.
페이지 가치 집계 준비하기
1-1. 성과(무엇을 평가해야 할지) 정의하기
1-2. 어떻게 해당 성과를 수치화할 수 있는지 정의하기
▼
2. 페이지 가치 할당하는 방법 정의하기
▼
3. 페이지 가치 집계하기
1. 성과 수치화하기
- 예를 들어 성과로 자료 청구, 견적 의뢰 신청이 이루어졌을 때라고 정의했다면, 해당 페이지로 이동하는 버튼을 클릭했는지 그 여부로 성과를 수치화할 수 있음
- 이러한 설정을 기반으로 자료 청구, 견적 의뢰를 할 때마다 1이라는 점수를 부여하는 방법
- 자료를 청구했을 때의 매출을 점수로 부여하는 방법
※ 매출 금액 등의 구체적인 정보를 산출할 수 없다면, 임시로 1CV의 가치를 1,000으로 설정하는 방법이 있다.
2. 페이지 가치를 할당하는 방법 정하기
: 페이지 가치로 "어떤 판단을 내리고 싶은지"에 따라 페이지에 가치를 할당하는 로직이 달라진다.
5가지 방법
1. 마지막 페이지에 할당하기
: 직접적인 효과가 있다고 판단할 수 있는 페이지에 성과를 모두 할당
→ 목적: 매출에 직접적으로 기여하는 페이지 판단하기
2. 첫 페이지에 할당하기
: 성과로 이어지는 계기가 되었던 첫 번째 페이지에 성과를 모두 할당
→ 목적: 매출에 간접적으로 기여하는 페이지 판단
(ex. 광고/검색 엔진 등의 외부 유입 中 가치가 높은 페이지 판단)
3. 균등하게 분산하기
: 성과에 이르기까지 거쳤던 모든 페이지에 성과를 균등하게 할당
→ 목적: 어떤 페이지를 '경유'했을 때 사용자가 성과에 이르는지 판단
(ex. 적은 페이지를 거쳐 성과로 이어지거나, 반복적으로 방문하는 페이지의 가치가 높게 측정됨)
4. 성과 지점에서 가까운 페이지에 더 높게 할당하기
: 마지막 페이지에 가까울수록 높은 가치 할당
5. 성과 지점에서 먼 페이지에 더 높게 할당하기
: 첫 페이지에 가까울수록 높은 가치를 할당
3. 페이지 가치 집계하기
특정한 계급 수로 히스토그램 만들기
a. 성과
: "신청 입력 양식을 제출하고 완료 화면이 출력된 경우"
b. 페이지 가치 할당 방법
: 성과 수치를 1,000으로 계산하여 경유헀던 페이지에 균등하게 할당(3번 방법)
c. 조건
: 페이지 평가 시 입력,확인,완료 페이지를 포함하면 집계가 제대로 이루어지지 않기에 집계에서 제외
※ 성과에 이르기까지의 로그 정렬
ROW_NUMBER() OVER(PARTITION BY session ORDER BY stamp ASC) AS asc_order
※ 균등 가치 부여
1000.0 / COUNT(*) OVER(PARTITION BY session) AS fair_assign,
※ 성과에 이르기까지의 접근 로그 성과 시점에서 가까운 페이지에 높은 가치 부여
- 순번을 오름차순으로 부여해서, 세션의 시작 부분에 방문한 페이지가 낮은 순번을 받게 됨
- 나누는 순번 합계는 전체 페이지 순번의 합 (n*(n+1)/2)
1000.0 * ROW_NUMBER() OVER(PARTITION BY session ORDER BY stamp ASC)
-- 순번 합계로 나누기 (N*(N+1)/2)
/ ( COUNT(*) OVER(PARTITION BY session)*( COUNT(*) OVER(PARTITION BY session)+1)/2)
※ 조건
-- 컨버전으로 이어지는 세션 로그만 필터링 / 입력, 확인, 완료 페이지 제외
WHERE has_conversion=1
AND path NOT IN ('/input', '/confirm', '/complete'))
전체 쿼리
- /complete 경로를 방문한 경우를 확인하고 플래그를 설정하는 과정까지 앞과 동일
- has_conversion 플래그가 1인 로그만 대상으로(전환된) 세션 내 페이지 방문 순서를 ASC, DESC으로 각각 순번 부여
- 각 세션의 총 페이지 방문 수 page_count 계산
- decrease_assign은 세션의 시작에서 멀어질 수록(asc로 정렬하여 세션의 시작에서 row_number이 낮음) 가치를 감소시키고, increase는 세션의 시작부터 가까워질수록(desc로 정렬하여 세션의 시작에서 row_number이 큼) 가치를 증가시키는 방식으로 1000을 할당한다.
WITH activity_log_with_conversion_flag AS(
SELECT
session,
stamp,
path,
SIGN(SUM(CASE WHEN path = '/complete' THEN 1 ELSE 0 END)
OVER(PARTITION BY session ORDER BY stamp DESC
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW))
AS has_conversion
FROM activity_log),
activity_log_with_conversion_assigning AS(
SELECT
session,
stamp,
path,
-- 성과에 이르기까지의 접근 로그 정렬(ASC)
ROW_NUMBER() OVER(PARTITION BY session ORDER BY stamp ASC) AS asc_order,
-- 성과에 이르기까지의 접근 로그에 순번 붙이기(DESC)
ROW_NUMBER() OVER(PARTITION BY session ORDER BY stamp DESC) AS desc_order,
-- 성과에 이르기까지 접근 수 세기
COUNT(*) OVER(PARTITION BY session) AS page_count,
-- 1. 성과에 이르기까지의 접근 로그에 균등한 가치 부여하기
1000.0 / COUNT(*) OVER(PARTITION BY session) AS fair_assign,
-- 2. 첫 페이지에 가치 부여
CASE WHEN ROW_NUMBER() OVER(PARTITION BY session ORDER BY stamp ASC)
= 1 THEN 1000.0 ELSE 0.0 END AS first_assign,
-- 3. 마지막 페이지에 가치 부여
CASE WHEN ROW_NUMBER() OVER(PARTITION BY session ORDER BY stamp DESC)
=1 THEN 1000.0 ELSE 0.0 END AS last_assign,
-- 4. 가까운 페이지에 높은 가치 부여
1000.0 * ROW_NUMBER() OVER(PARTITION BY session ORDER BY stamp ASC)
-- 순번 합계로 나누기 (N*(N+1)/2)
/ ( COUNT(*) OVER(PARTITION BY session)*( COUNT(*) OVER(PARTITION BY session)+1)/2)
AS decrease_assign,
-- 5. 먼 페이지에 높은 가치 부여
1000.0 * ROW_NUMBER() OVER(PARTITION BY session ORDER BY stamp DESC)
/ ( COUNT(*) OVER(PARTITION BY session)*( COUNT(*) OVER(PARTITION BY session)+1)/2)
AS increase_assign
FROM activity_log_with_conversion_flag
-- 컨버전으로 이어지는 세션 로그만 필터링 / 입력, 확인, 완료 페이지 제외
WHERE has_conversion=1
AND path NOT IN ('/input', '/confirm', '/complete'))
SELECT
session,
asc_order,
path,
fair_assign AS fair_a,
first_assign AS first_a,
last_assign AS last_a,
decrease_assign AS dec_a,
increase_assign AS inc_a
FROM activity_log_with_conversion_assigning
ORDER BY session, asc_order;
이어서 페이지 가치의 합계를 경로별로 집계하기
-- 앞의 쿼리와 동일
,
page_total_values AS(
SELECT
path,
SUM(fair_assign) AS fair_assign,
SUM(first_assign) AS first_assign,
SUM(last_assign) AS last_assign,
SUM(decrease_assign) AS dec_assign,
SUM(increase_assign) AS inc_assign
FROM activity_log_with_conversion_assigning
GROUP BY path)
select * from page_total_values;
→ 페이지 뷰가 많은 페이지에서의 페이지 가치가 높게 판정되는 경향이 있다는 한계점이 있다.
▼
페이지 뷰가 적으면서도 높은 페이지 가치를 가진 페이지 찾기
= <페이지 가치> / <페이지 방문횟수> 혹은 <페이지 뷰>
-- 앞 쿼리까지 동일
,
page_total_cnt AS(
SELECT
path,
COUNT(*) AS access_cnt -- 페이지 뷰, 방문횟수로 나눌 경우 count distinct session
FROM activity_log
GROUP BY path)
-- 한 번의 방문에 따른 페이지 가치 계산
SELECT
s.path,
s.access_cnt,
round(v.fair_assign / s.access_cnt,2) AS avg_fair,
round(v.first_assign / s.access_cnt,2) AS avg_first,
round(v.last_assign / s.access_cnt,2) AS avg_last,
round(v.dec_assign / s.access_cnt,2) AS avg_dec,
round(v.inc_assign / s.access_cnt,2) AS avg_asc
FROM page_total_cnt AS s
JOIN
page_total_values AS v
ON s.path = v.path
ORDER BY s.access_cnt DESC;
→ 검색 페이지(/search_list)가 상세 페이지(/detail)보다 전반적으로 높은 페이지 가치를 갖고 있다고(성과로 이어진다고) 해석할 수 있다.
'SQL > 데이터 분석을 위한 SQL레시피' 카테고리의 다른 글
[16] 입력 양식 최적화하기 (2) | 2024.03.06 |
---|---|
[15] 사이트 내의 사용자 행동 파악하기(2) - CTR, CVR 집계, 폴아웃(Fall-Out) 리포트 작성, 사용자 흐름 파악 (0) | 2024.03.02 |
데이터 분석을 위한 SQL 레시피 15강보충 - 성과 측정을 위한 지표 정의 (0) | 2024.02.25 |
[13] 웹사이트에서의 행동을 파악하는 데이터 추출 - 사이트 전체의 특징/경향 찾기 : 유입원/접근요일 별 방문자 수 파악 (0) | 2024.02.17 |
[12] 시계열에 따른 사용자의 개별적인 행동 분석하기 - 액션 간의 리드 타임, 카트 추가 후 구매까지 걸린 시간, 등록일로부터 경과한 일수 별 매출액 집계 (0) | 2024.02.17 |