본문 바로가기

스파르타 코딩클럽/[프로젝트] 내일배움캠프 데이터분석 1기

[기초 프로젝트] 데이팅 앱 지하철 광고 전략 (1) - 데이터 수집 및 가공

1. 주제 선정

  • 2030 타깃으로 한 데이팅 앱 지하철 PSD 광고 진행 시 최적의 역사 선정
  • 데이팅 앱 타깃층 특성에 기반해 광고 효과를 효율적으로 낼 수 있는 역사 분석
  • 상황 설정
    B07팀은 데이팅 앱을 개발한 스타트업 기업의 마케팅 팀
    해당 앱은 2030 청년층을 타깃으로 제작
    '위피' 성공사례를 기반으로 여성과 남성 유저의 성비를 맞추는 것이 목표

2. 가설 설정

  • 목표 : 2030 여성에게 최대 광고 노출
  • 승하차 수가 많을수록 광고 효과가 높을 것이다.
  • 청년 인구 비중이 높은 지역일수록 광고 효과가 높을 것이다.
  • 청년 중 여성 인구 비중이 높은 지역이 목표 달성에 효과적일 것이다.
  • 유동인구가 많은 홍대역, 강남역의 승하차 수가 많을 것이다.
  • 신림역, 서울대입구역의 청년 인구 비중이 높을 것이다.
  • 여대 인근 역(이대역, 숙명여대)의 여성 청년 인구 비중이 높을 것이다.
더보기

필자는 해당 프로젝트에서 지하철 승하차 수 분석을 담당하여 다음 과정을 진행했다.

3. 데이터 수집

4. 데이터 가공 (SQL 활용)

 

1) 2023 역별 하루 평균 승객수 순위

 

월마다 테이블이 나눠져 있어서 12개의 데이터를 불러온 뒤 UNION을 사용해 1년 치 데이터를 하나의 테이블로 만들었다.

with total_subway as (
select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_jan
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_feb
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_mar
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_apr
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_may
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_jun
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_jul
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_aug
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_sep
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_oct
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_nov
	union
	select 사용일자, 노선명, 역명, 승차총승객수, 하차총승객수
	from card_subway_dec)
select DATE_FORMAT(사용일자, '%Y') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "평균 승객수 총합", ROUND(avg(승차총승객수)) "평균 승차승객수", ROUND(avg(하차총승객수)) "평균 하차승객수",
	   RANK() OVER(order by ROUND(avg(승차총승객수)) DESC) "승차승객수 순위",
	   RANK() OVER(order by ROUND(avg(승차총승객수)+avg(하차총승객수)) DESC) "총승객수 순위"
from total_subway
where 승차총승객수 is not NULL
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not NULL;

 

2) 2023 역별 월별 하루 평균 총 승객수

select a.노선명, a.역명, 1월평균총승객수, 2월평균총승객수, 3월평균총승객수, 4월평균총승객수, 5월평균총승객수, 6월평균총승객수, 7월평균총승객수, 8월평균총승객수, 9월평균총승객수, 10월평균총승객수, 11월평균총승객수, 12월평균총승객수
from
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "1월평균총승객수"
from card_subway_jan
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not NULL) a left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "2월평균총승객수"
from card_subway_feb
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) b on a.노선명=b.노선명 and a.역명=b.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "3월평균총승객수"
from card_subway_mar
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) c on b.노선명=c.노선명 and b.역명=c.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "4월평균총승객수"
from card_subway_apr
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) d on c.노선명=d.노선명 and c.역명=d.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "5월평균총승객수"
from card_subway_may
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) e on d.노선명=e.노선명 and d.역명=e.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "6월평균총승객수"
from card_subway_jun
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) f on e.노선명=f.노선명 and f.역명=e.역명 left join 
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "7월평균총승객수"
from card_subway_jul
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) g on f.노선명=g.노선명 and f.역명=g.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "8월평균총승객수"
from card_subway_aug
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) h on h.노선명=g.노선명 and h.역명=g.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "9월평균총승객수"
from card_subway_sep
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) i on h.노선명=i.노선명 and h.역명=i.역명 left join 
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "10월평균총승객수"
from card_subway_oct
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) j on j.노선명=i.노선명 and j.역명=i.역명 left join 
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "11월평균총승객수"
from card_subway_nov
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) k on j.노선명=k.노선명 and j.역명=k.역명 left join 
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, ROUND(avg(승차총승객수)+avg(하차총승객수)) "12월평균총승객수"
from card_subway_dec
group by 1, 2, 3
having ROUND(avg(승차총승객수)+avg(하차총승객수)) is not null) l on l.노선명=k.노선명 and l.역명=k.역명
order by 1, 2

 

3) 2023 역별 월별 하루 총 승객수 합계

select a.노선명, a.역명, 1월총승객수합계, 2월총승객수합계, 3월총승객수합계, 4월총승객수합계, 5월총승객수합계, 6월총승객수합계, 7월총승객수합계, 8월총승객수합계, 9월총승객수합계, 10월총승객수합계, 11월총승객수합계, 12월총승객수합계
from
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "1월총승객수합계"
from card_subway_jan
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not NULL) a left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "2월총승객수합계"
from card_subway_feb
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) b on a.노선명=b.노선명 and a.역명=b.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "3월총승객수합계"
from card_subway_mar
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) c on b.노선명=c.노선명 and b.역명=c.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "4월총승객수합계"
from card_subway_apr
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) d on c.노선명=d.노선명 and c.역명=d.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "5월총승객수합계"
from card_subway_may
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) e on d.노선명=e.노선명 and d.역명=e.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "6월총승객수합계"
from card_subway_jun
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) f on e.노선명=f.노선명 and f.역명=e.역명 left join 
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "7월총승객수합계"
from card_subway_jul
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) g on f.노선명=g.노선명 and f.역명=g.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "8월총승객수합계"
from card_subway_aug
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) h on h.노선명=g.노선명 and h.역명=g.역명 left join
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "9월총승객수합계"
from card_subway_sep
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) i on h.노선명=i.노선명 and h.역명=i.역명 left join 
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "10월총승객수합계"
from card_subway_oct
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) j on j.노선명=i.노선명 and j.역명=i.역명 left join 
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "11월총승객수합계"
from card_subway_nov
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) k on j.노선명=k.노선명 and j.역명=k.역명 left join 
(select DATE_FORMAT(사용일자, '%Y-%m') "사용일자", 노선명, 역명, SUM(승차총승객수)+SUM(하차총승객수) "12월총승객수합계"
from card_subway_dec
group by 1, 2, 3
having SUM(승차총승객수)+SUM(하차총승객수) is not null) l on l.노선명=k.노선명 and l.역명=k.역명
order by 1, 2

 

4) 2023 요금별(연령대별) 승객 비율

 

➡️연령대 기준은 지하철 요금 종류로 파악

  • 어린이 : 만 6세 ~ 만 12세
  • 청소년 : 만 13세 ~ 만 18세
  • 경로 : 만 65세 이상

➡️ 로우데이터에는 대학생 구분이 있었으나 데이터 값이 모두 0이라서 제외함

➡️ 원본 데이터 값이 한 달마다 하루 값밖에 없어서 사용할 수 없는 데이터지만 분석은 시도해 봄

with total_subway_users as (
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_jan
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_feb
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_mar
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_apr
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_may
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_jun
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_jul
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_aug
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_sep
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_oct
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_nov
	group by 1, 2, 3
	union
	select DATE_FORMAT(기준일자, '%Y-%m-%d') "기준일자", 승차_호선, 승차_역, sum(총_승객수) "총승객수", SUM(일반_승객수) "일반승객수", SUM(어린이_승객수) "어린이승객수", SUM(청소년_승객수) "청소년승객수", SUM(경로_승객수) "경로승객수", SUM(대학생_승객수+장애인_승객수+국가유공자_승객수+직원_승객수+외국인경로_승객수) "기타승객수"
	from 지하철_역별od_dec
	group by 1, 2, 3)
select DATE_FORMAT(기준일자, '%Y') "기준일자", 승차_호선, 승차_역, 
	   ROUND(AVG(총승객수)) "총승객수 평균", 
	   ROUND((AVG(일반승객수)/AVG(총승객수))*100,1) "일반승객수 비율", 
	   ROUND((AVG(어린이승객수)/AVG(총승객수))*100,1) "어린이승객수 비율", 
	   ROUND((AVG(청소년승객수)/AVG(총승객수))*100,1) "청소년승객수 비율", 
	   ROUND((AVG(경로승객수)/AVG(총승객수))*100,1) "경로승객수 비율", 
	   ROUND((AVG(기타승객수)/AVG(총승객수))*100,1) "기타승객수 비율"
from total_subway_users
group by 1, 2, 3
order by 4 DESC;

 

>> 지하철 승하차 수 데이터만으론 연령대와 성별에 대한 정보를 얻기 어려우므로 다른 팀원이 분석한 동별 청년(여성) 비중 데이터와 함께 각 데이터를 점수화하여 통합 점수를 바탕으로 최종 역사 후보지를 선정했다.

 

더보기

+ 프로젝트가 끝난 시점에서 느낀 부족함/아쉬움

  • 승하차수 하루 평균값 외에 한 달 평균값 계산도 있었으면 좋았을 것 같다.
  • 광고 단가를 평균값으로 나눠서 계산해 보면 새로운 결과가 도출되었을 것 같다