캐글에서 제공해주는 데이터셋을 SQL으로 분석해보자!
분석하고자 하는 데이터셋은 아래에서 구하였다.
https://www.kaggle.com/datasets/ddosad/customer-behaviour-tourism-portal/data
먼저 데이터의 컬럼들을 살펴보자.
총 17개의 컬럼이 존재한다.
컬럼명 | 설명 |
UserID | 사용자의 고유 식별자 |
Taken_product | 사용자가 여행상품을 샀는지 여부 |
Yearly_avg_view_on_travel_page | 사용자가 연간 평균적으로 여행 관련 페이지를 조회한 횟수 |
preferred_device | 사용자가 로그인에 가장 선호하는 기기 유형 |
total_likes_on_outstation_checkin_given | 사용자가 지난 1년간 외부 지역 체크인에 대해 주는 총 좋아요 수 |
yearly_avg_Outstation_checkins | 사용자가 연간 평균적으로 외부 지역 체크인을 한 횟수 |
member_in_family | 사용자가 계정에 언급한 가족 구성원의 총 인원 수 |
preferred_location_type | 사용자가 여행에 가장 선호하는 위치 유형 |
Yearly_avg_comment_on_travel_page | 사용자가 연간 평균적으로 여행 관련 페이지에 남긴 댓글 수 |
total_likes_on_outofstation_checkin_received | 사용자가 지난 1년간 외부 지역 체크인에 대해 받은 총 좋아요 수 |
week_since_last_outstation_checkin | 사용자의 마지막 외부 지역 체크인 업데이트 이후 경과한 주 수 |
following_company_page | 고객이 회사 페이지를 팔로우하고 있는지 여부 |
montly_avg_comment_on_company_page | 사용자가 회사 페이지에 월간 평균적으로 남긴 댓글 수 |
working_flag | 고객이 현재 근무 중인지 여부 |
travelling_network_rating | 여행을 좋아하는 친구들과의 관계를 나타내는 등급. 1이 가장 높고, 4가 가장 낮은 등급 |
Adult_flag | 고객이 성인인지 여부 |
Daily_Avg_mins_spend_on_traveling_page | 사용자가 회사의 여행 페이지에 평균적으로 소비하는 시간 |
이제 이러한 데이터를 바탕으로 어떤 사용자가 여행을 많이 하는지, 어떤 사용자가 여행 상품을 구매할 가능성이 많은지를 알아볼 예정이다!
데이터 클리닝(Data Cleaning)
해당 사이트에서 제공해주는 csv 파일 데이터의 이름을 "Customer behaviour Tourism_ori.csv"로 정의하였다.
먼저, 기본적인 데이터 분석을 진행해보자.
첫번째로, csv 파일을 보면 결측치가 보이기에 제거하기로 하였다.
그 숫자가 많지 않기에 단순히 제거를 한다.
결측치 제거 전 데이터 개수 : 11760개
일부의 결측치는 단순히 빈 문자열이고, NULL인 결측치 값도 있으므로, 2가지 케이스를 모두 고려하여 결측치를 제거해보자.
-- 결측치 제거(빈 문자열)
DELETE FROM customer_behaviour_tourism_ori
WHERE 1=1
AND (TRIM(yearly_avg_view_on_travel_page) = '' OR
TRIM(total_likes_on_outstation_checkin_given) = '' OR
TRIM(yearly_avg_outstation_checkins) = '' OR
TRIM(preferred_location_type) = '' OR
TRIM(yearly_avg_comment_on_travel_page) = '' OR
TRIM(following_company_page) = '' OR
TRIM(working_flag) = '' OR
TRIM(preferred_device) = '');
-> 해당 데이터의 결측치가 Null 형태가 아닌 문자열이 비어있는 형태이므로, 위와 같이 결측치를 제거한다.
NULL로 채워진 결측치도 있다. 아래의 코드로 제거해보겠다.
-- 결측치 제거(NULL)
DELETE FROM customer_behaviour_tourism_ori
WHERE
yearly_avg_view_on_travel_page IS NULL OR
total_likes_on_outstation_checkin_given IS NULL OR
yearly_avg_outstation_checkins IS NULL OR
preferred_location_type IS NULL OR
yearly_avg_comment_on_travel_page IS NULL OR
following_company_page IS NULL OR
working_flag IS NULL OR
preferred_device IS NULL OR
Adult_flag IS NULL;
추가적으로, 'yearly_avg_Outstation_checkins' 컬럼이 모두 int 자료형이지만, *로 된 값이 있어 결측치로 판단을 하고 삭제하겠다.
-- yearly_avg_Outstation_checkins 컬럼의 *로 된 값 제거
DELETE FROM customer_behaviour_tourism_ori
WHERE yearly_avg_Outstation_checkins = "*";
모든 결측치를 제거한 결과 데이터의 개수는 10454개로 줄어들었다.
다음으로, 기본적인 데이터 정리를 해주겠다.
-- member_in_family 컬럼의 three를 3으로 대체
UPDATE customer_behaviour_tourism_ori
SET member_in_family = 3
WHERE member_in_family = 'three';
-- preferred_location_type 컬럼의 Tour Travel을 Tour and Travel로 대체
UPDATE customer_behaviour_tourism_ori
SET preferred_location_type = 'Tour and Travel'
WHERE preferred_location_type = 'Tour Travel';
-- preferred_location_type 컬럼의 Game, Movie, OTT를 Entertainment로 대체(수가 작기에 그룹화)
UPDATE customer_behaviour_tourism_ori
SET preferred_location_type = 'Entertainment'
WHERE preferred_location_type = 'Game'
OR preferred_location_type = 'Movie'
OR preferred_location_type = 'OTT';
-- preferred_device 컬럼의 ANDROID, Android OS를 Android로 대체
UPDATE customer_behaviour_tourism_ori
SET preferred_device = 'Android'
WHERE preferred_device = 'ANDROID'
OR preferred_device = 'Android OS';
-- preferred_device 컬럼의 Others를 Other로 대체
UPDATE customer_behaviour_tourism_ori
SET preferred_device = 'Other'
WHERE preferred_device = 'Others';
-- following_company_page 컬럼의 Yeso와 1을 Yes로 대체
UPDATE customer_behaviour_tourism_ori
SET following_company_page = 'Yes'
WHERE following_company_page = 'Yeso'
OR following_company_page = '1';
-- following_company_page 컬럼의 0을 No로 대체
UPDATE customer_behaviour_tourism_ori
SET following_company_page = 'No'
WHERE following_company_page = '0';
-- working_flag 컬럼의 0을 No로 대체
UPDATE customer_behaviour_tourism_ori
SET working_flag = 'No'
WHERE working_flag = '0';
기본적인 정리를 마친 데이터는 다음과 같다.
이를 Export하여 "Customer behaviour Tourism_basic.csv"로 저장하였고, 해당 csv 파일을 기준으로 새로운 테이블을 생성하였다. (테이블 명: customer_behaviour_tourism)
이제, 위의 데이터를 통해 간단한 데이터 분석을 해보자!
먼저, 앞서 기초 정리를 끝낸 후 데이터의 개수는 10454개이다.
컬럼별 분석
각 컬럼에 대한 상세 분석을 진행해보겠다.
일단 분석을 위해 Yes 값은 모두 1로, No 값을 모두 0으로 바꾸겠다.
-- Taken_product, following_company_page, working_flag 컬럼의 Yes는 1로, No는 0으로 바꾼다.
UPDATE customer_behaviour_tourism
SET Taken_product = CASE WHEN Taken_product = 'Yes' THEN 1 ELSE 0 END,
following_company_page = CASE WHEN following_company_page = 'Yes' THEN 1 ELSE 0 END,
working_flag = CASE WHEN working_flag = 'Yes' THEN 1 ELSE 0 END;
추가로, Adult_flag 변수는 성인인지 아닌지 여부를 나타내지만, 0, 1, 2, 3의 값을 갖는다. Q&A에 따르면,,,
0은 성인이 아니고, 나머지는 모두 성인이므로, 2와 3의 값을 1로 대체하도록 하겠다.
-- Adult_flag의 2, 3은 성인(1)을 의미
UPDATE customer_behaviour_tourism
SET Adult_flag = 1
WHERE Adult_flag IN (2, 3);
이를 바탕으로 각 컬럼의 평균값을 조회해보겠다. (문자열 값을 갖는 preferred_device와 preferred_location_type 제외)
- 궁극적으로 여행상품을 산 사람은 16%이다.
- 사용자가 연 평균 여행 관련 페이지를 조회한 횟수는 평균적으로 281회이다.
- 지난 1년간 외부 지역 체크인에 대해 주는 총 좋아요 수는 평균적으로 28158개이다.
- 연 평균 외부 지역에 체크인한 수는 평균적으로 8번이다. => 평균적으로 8번의 여행을 갔다고 생각할 수 있다.
- 사용자의 평균적인 가족 구성원 수는 약 3명이다.
- 사용자가 연 평균 여행 관련 페이지에 남긴 댓글 수의 평균은 75번이다.
- 사용자가 지난 1년간 외부 지역 체크인에 대해 받은 총 좋아요 수의 평균은 6535번이다.
- 마지막 체크인 이후 경과한 주는 평균 3주이다.
- 회사 페이지를 팔로우는 약 28%의 사람들만 하였다.
- 사용자가 회사 페이지에 남긴 월 평균 댓글 수의 평균은 약 29번이다.
- 사용자의 약 15%가 현재 근무 중이다.
- 여행을 좋아하는 친구들과의 관계는 약 2.7등급이다. -> 1등급은 사용자 주변에 여행을 좋아하는 친구들이 가장 많다는 의미이고, 4등급은 사용자 주변에 여행을 싫어하는 친구들이 가장 많다는 의미이다.
- 성인인 고객이 약 57%이다.
- 사용자가 해당 회사의 여행 페이지를 구경하는 시간은 평균적으로 13시간이다.
여행 상품을 구매한 사용자의 특징
Taken_product 컬럼은 사용자가 여행 상품을 샀는지 여부를 나타내는 컬럼이다.
몇 명이 샀는지, 몇 명이 안샀는지 알아보자.
-- Taken_product 컬럼의 Yes, No 개수 및 비율 분석
SELECT
SUM(CASE WHEN Taken_product = 1 THEN 1 ELSE 0 END) AS count_1,
SUM(CASE WHEN Taken_product = 0 THEN 1 ELSE 0 END) AS count_0,
SUM(CASE WHEN Taken_product = 1 THEN 1 ELSE 0 END) / COUNT(*) AS ratio_Yes,
SUM(CASE WHEN Taken_product = 0 THEN 1 ELSE 0 END) / COUNT(*) AS ratio_No
FROM customer_behaviour_tourism;
-> Yes의 비율이 16%, No의 비율이 84%로, 여행상품을 사지 않은 사람들이 훨씬 많다.
우리의 목표는 어떤 사람이 여행상품을 샀는지, 어떤 사람이 여행상품을 안샀는지 알아보는 것이기 때문에,
그 특성에 맞게 데이터를 분석해보자.
먼저, 여행 상품을 구매한 사람들의 평균 값들, 구매하지 않은 사람들의 평균 값들을 통합적인 컬럼 평균과 비교해보자.
-- 여행 상품을 구매한 사람들, 구매하지 않은 사람들, 모든 사람들에 대한 컬럼 평균
SELECT
'Yes' AS taken_product_status,
AVG(Yearly_avg_view_on_travel_page) AS avg_Yearly_avg_view_on_travel_page,
AVG(total_likes_on_outstation_checkin_given) AS avg_total_likes_on_outstation_checkin_given,
AVG(yearly_avg_Outstation_checkins) AS avg_yearly_avg_Outstation_checkins,
AVG(member_in_family) AS avg_member_in_family,
AVG(Yearly_avg_comment_on_travel_page) AS avg_Yearly_avg_comment_on_travel_page,
AVG(total_likes_on_outofstation_checkin_received) AS avg_total_likes_on_outofstation_checkin_received,
AVG(week_since_last_outstation_checkin) AS avg_week_since_last_outstation_checkin,
AVG(following_company_page) AS avg_following_company_page,
AVG(montly_avg_comment_on_company_page) AS avg_montly_avg_comment_on_company_page,
AVG(working_flag) AS avg_working_flag,
AVG(travelling_network_rating) AS avg_travelling_network_rating,
AVG(Adult_flag) AS avg_Adult_flag,
AVG(Daily_Avg_mins_spend_on_traveling_page) AS avg_Daily_Avg_mins_spend_on_traveling_page
FROM customer_behaviour_tourism
WHERE Taken_product = 1
UNION ALL
SELECT
'No' AS taken_product_status,
AVG(Yearly_avg_view_on_travel_page) AS avg_Yearly_avg_view_on_travel_page,
AVG(total_likes_on_outstation_checkin_given) AS avg_total_likes_on_outstation_checkin_given,
AVG(yearly_avg_Outstation_checkins) AS avg_yearly_avg_Outstation_checkins,
AVG(member_in_family) AS avg_member_in_family,
AVG(Yearly_avg_comment_on_travel_page) AS avg_Yearly_avg_comment_on_travel_page,
AVG(total_likes_on_outofstation_checkin_received) AS avg_total_likes_on_outofstation_checkin_received,
AVG(week_since_last_outstation_checkin) AS avg_week_since_last_outstation_checkin,
AVG(following_company_page) AS avg_following_company_page,
AVG(montly_avg_comment_on_company_page) AS avg_montly_avg_comment_on_company_page,
AVG(working_flag) AS avg_working_flag,
AVG(travelling_network_rating) AS avg_travelling_network_rating,
AVG(Adult_flag) AS avg_Adult_flag,
AVG(Daily_Avg_mins_spend_on_traveling_page) AS avg_Daily_Avg_mins_spend_on_traveling_page
FROM customer_behaviour_tourism
WHERE Taken_product = 0
UNION ALL
SELECT
'ALL' AS taken_product_status,
AVG(Yearly_avg_view_on_travel_page) AS avg_Yearly_avg_view_on_travel_page,
AVG(total_likes_on_outstation_checkin_given) AS avg_total_likes_on_outstation_checkin_given,
AVG(yearly_avg_Outstation_checkins) AS avg_yearly_avg_Outstation_checkins,
AVG(member_in_family) AS avg_member_in_family,
AVG(Yearly_avg_comment_on_travel_page) AS avg_Yearly_avg_comment_on_travel_page,
AVG(total_likes_on_outofstation_checkin_received) AS avg_total_likes_on_outofstation_checkin_received,
AVG(week_since_last_outstation_checkin) AS avg_week_since_last_outstation_checkin,
AVG(following_company_page) AS avg_following_company_page,
AVG(montly_avg_comment_on_company_page) AS avg_montly_avg_comment_on_company_page,
AVG(working_flag) AS avg_working_flag,
AVG(travelling_network_rating) AS avg_travelling_network_rating,
AVG(Adult_flag) AS avg_Adult_flag,
AVG(Daily_Avg_mins_spend_on_traveling_page) AS avg_Daily_Avg_mins_spend_on_traveling_page
FROM customer_behaviour_tourism;
- 여행 상품을 구매하지 않은 사람들의 여행 페이지 조회 횟수가 더 높다.
- 여행 상품을 구매하지 않은 사람들의 지난 1년간 외부 지역 체크인에 대해 주는 총 좋아요 수가 더 높다.
- 여행 상품을 구매하지 않은 사람들과 구매한 사람들의 여행 횟수 차이는 크지 않다.
- 사용자의 평균적인 가족 구성원 수는 여행 상품 구매 여부에 따른 큰 차이가 없다.
- 사용자가 연 평균 여행 관련 페이지에 남긴 댓글 수의 평균은 여행 상품 구매 여부에 따른 큰 차이가 없다.
- 사용자가 지난 1년간 외부 지역 체크인에 대해 받은 총 좋아요A 수는 여행 상품을 구매하지 않은 사람들이 더 높다.
- 사용자가 마지막 체크인 이후 경과한 주의 평균은 여행 상품 구매 여부에 따른 큰 차이가 없다.
- 여행 상품을 구매한 사람들의 53%는 회사 페이지를 팔로우했지만, 여행 상품을 구매하지 않은 사람들은 23%만 회사 페이지를 팔로우하였다.
- 사용자가 회사 페이지에 남긴 월 평균 댓글 수의 평균은 여행 상품 구매 여부에 따른 큰 차이가 없다.
- 사용자의 근무 여부 또한 여행 상품 구매 여부에 따른 큰 차이가 없다.
- 여행을 좋아하는 친구들과의 관계 또한 여행 상품 구매 여부에 따른 큰 차이가 없다.
- 여행 상품을 구매한 사람들 중 35%가 성인이고, 여행 상품을 구매하지 않은 사람들 중 61%가 성인이다. 전체 평균적으로는 57%의 사용자가 성인이다.
- 사용자가 해당 회사의 여행 페이지를 구경하는 시간은 여행 상품을 구매한 사람들이 더 적다.
==> 6개 정도의 핵심 특징을 발견하였다.
추가적인 분석을 해보자.
-- 가족 수에 따른 상품 구매자와 비구매자
SELECT
member_in_family,
COUNT(CASE WHEN Taken_product = 1 THEN 1 END) AS count_buyers,
COUNT(CASE WHEN Taken_product = 0 THEN 1 END) AS count_non_buyers
FROM customer_behaviour_tourism
GROUP BY member_in_family
ORDER BY member_in_family;
-- 전체 구매자 대비 가족 수에 따른 구매자의 비율
SELECT
member_in_family,
COUNT(CASE WHEN Taken_product = 1 THEN 1 END) AS count_buyers,
COUNT(CASE WHEN Taken_product = 1 THEN 1 END) / (SELECT COUNT(*) FROM customer_behaviour_tourism WHERE Taken_product = 1) * 100 AS buyer_percentage
FROM customer_behaviour_tourism
WHERE Taken_product = 1
GROUP BY member_in_family
ORDER BY member_in_family;
-- 전체 비구매자 대비 가족 수에 따른 비구매자의 비율
SELECT
member_in_family,
COUNT(CASE WHEN Taken_product = 0 THEN 1 END) AS count_buyers,
COUNT(CASE WHEN Taken_product = 0 THEN 1 END) / (SELECT COUNT(*) FROM customer_behaviour_tourism WHERE Taken_product = 0) * 100 AS buyer_percentage
FROM customer_behaviour_tourism
WHERE Taken_product = 0
GROUP BY member_in_family
ORDER BY member_in_family;
--> 가족이 3~4명인 사용자의 여행 상품 구매가 가장 많은 것을 확인할 수 있다.
그러나 이와 더불어 동일한 그룹에서의 비구매자 비율 또한 가장 높기에
가족 구성원 수는 여행 상품 구매 여부에 큰 관련이 없다.
-- 회사 페이지 팔로우 여부에 따른 구매자와 비구매자, 비율
SELECT
following_company_page,
COUNT(CASE WHEN Taken_product = 1 THEN 1 END) AS count_buyers,
COUNT(CASE WHEN Taken_product = 0 THEN 1 END) AS count_non_buyers,
COUNT(CASE WHEN Taken_product = 1 THEN 1 END) / (SELECT COUNT(*) FROM customer_behaviour_tourism WHERE Taken_product = 1) * 100 AS buyer_percentage,
COUNT(CASE WHEN Taken_product = 0 THEN 1 END) / (SELECT COUNT(*) FROM customer_behaviour_tourism WHERE Taken_product = 0) * 100 AS non_buyer_percentage
FROM customer_behaviour_tourism
GROUP BY following_company_page;
--> 회사 페이지 팔로우 여부에 따른 구매자와 비구매자 현황을 살펴본 결과,
여행 상품 구매자 내에서는 회사 페이지 팔로우 여부가 크게 차이나지 않는다.
그러나, 비구매자의 경우 회사 페이지를 팔로우 한 사람이 2033명, 회사 팔로우를 팔로우하지 않은 사람이 6728명으로,
차이가 매우 큼을 알 수 있다.
-- 여행 횟수(체크인 횟수)에 따른 구매자/비구매자
SELECT
yearly_avg_Outstation_checkins,
COUNT(CASE WHEN Taken_product = 1 THEN 1 END) AS count_buyers,
COUNT(CASE WHEN Taken_product = 0 THEN 1 END) AS count_non_buyers,
COUNT(CASE WHEN Taken_product = 1 THEN 1 END) / (SELECT COUNT(*) FROM customer_behaviour_tourism WHERE Taken_product = 1) * 100 AS buyer_percentage,
COUNT(CASE WHEN Taken_product = 0 THEN 1 END) / (SELECT COUNT(*) FROM customer_behaviour_tourism WHERE Taken_product = 0) * 100 AS non_buyer_percentage
FROM customer_behaviour_tourism
GROUP BY 1
ORDER BY 1;
--> 여행 횟수(체크인 횟수)가 1번일 때, 상품을 구매한 사람과 구매하지 않은 사람 모두 가장 많다.
따라서 여행상품을 구매한 사람들과 구매하지 않은 사람들의 차이는 크지 않다고 할 수 있다.
-- 성인 여부에 따른 구매자와 비구매자, 비율
SELECT
Adult_flag,
COUNT(CASE WHEN Taken_product = 1 THEN 1 END) AS count_buyers,
COUNT(CASE WHEN Taken_product = 0 THEN 1 END) AS count_non_buyers,
COUNT(CASE WHEN Taken_product = 1 THEN 1 END) / (SELECT COUNT(*) FROM customer_behaviour_tourism WHERE Taken_product = 1) * 100 AS buyer_percentage,
COUNT(CASE WHEN Taken_product = 0 THEN 1 END) / (SELECT COUNT(*) FROM customer_behaviour_tourism WHERE Taken_product = 0) * 100 AS non_buyer_percentage
FROM customer_behaviour_tourism
GROUP BY Adult_flag;
--> 여행 상품을 구매한 사람들 중 절반 이상(64%)은 성인이 아니고,
여행 상품을 구매하지 않은 사람들 중 절반 이상(61%)은 성인이다.
--> 즉, 성인은 여행 상품을 잘 구매하지 않는다고 추측할 수 있다.
==> 흔히 생각하는 고정관념과 다르기에 데이터의 불균형이 있는가 찾아보았다.
-- 성인/비성인자 몇 명인가
SELECT
Adult_flag,
COUNT(*) AS count
FROM customer_behaviour_tourism
GROUP BY Adult_flag;
==> 데이터의 불균형은 딱히 없어보인다.
그렇다면, 성인의 구매비율이 더 적은 이유는 2가지로 추측해볼 수 있다!
1. 성인은 미성년자에 비해 온라인 이용이 서툴러 온라인 여행 페이지에서 구매를 잘 하지 않은 것이다.
2. 성인은 돈이 많기에 여행 상품보다는 자유여행을 선호해 상품 구매가 적은 것이다.
상관관계 분석
-> 상관관계 분석을 진행해보았다. 모든 컬럼들의 여행 상품 구매와의 상관도가 크지는 않으며,
그나마 회사 페이지 팔로우 여부, 성인여부 등의 컬럼의 상관도가 커보인다.
'프로젝트' 카테고리의 다른 글
프로젝트 주제 선정 회고록 (1) | 2024.06.12 |
---|---|
관광회사 고객 행동 데이터 분석 (4) (0) | 2024.03.13 |
관광회사 고객 행동 데이터 분석 (3) (1) | 2024.03.13 |
관광회사 고객 행동 데이터 분석 (2) (0) | 2024.03.12 |