일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 시각화
- 트위먼의법칙
- 주가데이터
- 글또
- 전환분석
- 데이터분석가
- 데이터디스커버리플랫폼
- retentioneering
- 분석한스푼
- 신기효과
- 야구
- 프롬프트엔지니어링
- 벅슨의역설
- n8n
- 데이터
- data
- 성장
- PyGWalker
- aha-moment
- 아하모먼트
- 프롬프트
- productanalysis
- DataAnalysis
- pandasai
- DataAnalyst
- 데이터분석
- gapminder
- data-analysis
- 인과추론
- EDA
데이터 생존 로그
3000번 버스, 탈 수 있을까? - 데이터 기반으로 퇴근시간 정하기 본문
배경
나는 수원 - 강남을 통근하는 통근러이다.
매주 출근일마다 편도 100분 가량 걸리는 거리를 3000번 버스와 함께 통근한다.
아주 춥던 어느 날, 퇴근 버스를 놓치고 말았다.
요즘 광역 버스는 입석이 안되고, 내 앞앞에서 잔여 좌석이 0석이 되어 강제로 타지 못하고 말았다,,,
그래서 시작했다.
언제 퇴근을 해야 내가 안전하게 버스를 타고 집에 갈 수 있을 지를 데이터 기반으로 찾아보기로!
데이터 수집
내가 모으고자 하는 데이터는 깊게 생각치 않았다.
여러 지도 플랫폼에서 제공하는 버스 위치/잔여 좌석 데이터의 스냅샷을
최대한 '짧은 주기'로 모으면 만사 OK라고 생각했다.
내가 얻고자 하는 버스 데이터는 '공공 데이터 포털'의 OPEN API와
요즘 내가 요리조리 써 먹고 있는 'N8N'이라는 자동화 툴을 활용해 스프레드시트에 적재했다. (아래 게시글 참고)
https://analyst-ggom-chi-kim.tistory.com/27
간단히 파이프라인을 소개하면,
매 3분 마다 trigger가 실행된다.
공공 데이터 포털의 일일 api 수를 고려하여 최대한 촘촘하게(자주) 데이터를 수집하려 했고, 그 기준이 대략 3분 정도 였다.
만약 시간대가 2~5시 사이라면, 적재하지 않는다. (어차피 그 때 시간의 정보는 필요 없으니까)
api를 통해 호출한 후, 간단한 전처리를 하면 다음과 같은 컬럼 명세를 갖는 데이터가 쌓인다.
컬럼명 | description | example |
plateNo | 버스 번호판 | 경기70사1642 |
remainSeatCnt | 잔여 좌석 | 35 |
stationId | 정류장 번호 | 220000137 |
stationSeq | 정류장 순서 | 52 |
timestamp | 데이터 수집 시간 | 2025-02-08 16:12:36 |
위 데이터를 약 2주 간 적재했다.
추가로, 정류장 이름을 매핑시켜주기 위해 다음 데이터도 찾아서 저장해 두었다.
컬럼명 | description | example |
stationId | 정류장 번호 | 220000137 |
stationName | 정류장 이름 | 선바위역2번출구(광역) |
stationSeq | 정류장 순서 | 52 |
데이터 전처리
간단한 과정(pandas merge)을 통해 수집된 스냅샷 데이터에 정류장 이름을 매핑해 줄 수 있었다.
하지만 그 이후 문제가 하나 발생했다.
'각 버스의 고유한 운행 정보를 모른다는 것!'
예를 들어, 경기70사1642 버스는 3분 마다 정류장과 잔여 좌석 정보가 찍힐텐데, 만약 같은 정류장에 두 번 찍혔다면 그걸 구분할 방법이 없다는 것이었다.
단순히 날짜와 버스 번호판(경기70사1642)을 concat시켜서 unique한 개수를 센다고 해서 해결될 문제가 아니었다.
(왜냐면 경기70사1642 버스는 하루에도 여러 번 운행할 수 있기 때문..)
그래서 다음과 같이 각 row별로 trip_id를 달아주기로 했다.
1. 재시작(restart) 정의: 시간은 더 큰 값을 갖는데, stationSeq가 더 작다면, 버스가 종점 도착 후 재시작했다고 판단할 수 있다.
2. 운행 id(trip_id) 정의: 해당 날짜와 앞서 정의한 재시작의 '누적값'을 concat하면 unique한 운행을 정의할 수 있다!
trip_id는 하나의 고유한 운행으로 정의할 수 있다.
이제 원하는 시간대별로 aggregation한 다음, 원하는 조건에 따라 unique한 trip_id를 집계만 하면 된다!
분석 & 시각화
시각화는 간단히 해낼 수 있다.
- 특정 정류장으로 필터링 한 후
- 5분 단위로 aggregation 한다.
- unique한 trip_id의 수는 해당 시간대에 운행한 버스 수를 의미한다.
- 잔여좌석이 5건 이하인 unique한 trip_id의 수는 해당 시간대에 놓칠 위험이 있는 버스 수를 의미한다.
실제로 데이터를 보면 다음과 같다.
당연하겠지만, 퇴근시간인 오후5~7시 사이에 놓칠 위험이 있는 버스가 많이 운행된 것을 볼 수 있다.
조금 더 zoom-in 하여 살펴보면,
18:35분(그림 상 1)과 19:00(그림 상 2)가 위험해 보인다.
특히, 18:35분에 타면 100% 확률로 잔여좌석 5석 이하가 남아버린다.
위 간단한 집계를 통해 다음 결론에 다다를 수 있겠다!
- 엥간하면 18:35에는 집에 가지 말자..
- 19:00도 마찬가지
- 그 언저리에 집에 가려면 18:40 쯤이 적당해 보인다!
아! 시각화 한 게 아까우니 streamlit에 올려두도록 하겠다. 😉
https://can-i-take-bus.streamlit.app/
🚌 3000번 버스 탈 수 있을까?
This app was built in Streamlit! Check it out and visit https://streamlit.io for more awesome community apps. 🎈
can-i-take-bus.streamlit.app
'📊 분석 한 스푼 🥄' 카테고리의 다른 글
[야구] 타율이 높으면 득점을 잘한다? (with. 상관관계 분석) (0) | 2023.06.18 |
---|---|
01. 세상은 개발도상국과 선진국으로 나뉠까? (0) | 2023.02.22 |
00. 분석으로 진수성찬을 만들어보자🍚🍖 (0) | 2023.02.21 |