Project_Log

[ 빅데이터의 이해 ] 공공 데이터를 이용하여 지하철 이용객 데이터 분석 - 1

Jerry_JH 2022. 2. 2. 14:09
728x90

2021년 1학기에 진행한 프로젝트인데, 그동안 다사다난하여 이제야 프로젝트 로그를 적는다.

이 프로젝트는 학교 기말과제로 제출하였고, 제목에도 있듯이 '빅데이터의 이해'라는 과목이었다.

 

해당 기말과제는 자유로운 주제로 데이터를 분석하는 것이었다. 

단, 공공데이터를 이용해야 된다.

 

이 과목은 프로그래밍 언어를 가르치는 것은 아니다.

주로 빅데이터 이론에 대해서 배웠고, 분석 방법도 이론만 배웠다. 

 

교양 과목이었지만, python 언어를 활용할 수 있기 때문에

다른 수강생들과 차이점을 두기 위해 python을 이용해서 분석하기로 마음을 먹었다.

 

참고문헌 포함하여 10페이지 안으로 보고서를 작성해야 되기 때문에 

많은 내용을 담지는 못하지만, 대충 하는 성격은 못되어서 보고서에 담지 못한 내용까지 포함하여

블로그에 정리를 하려고 한다.

 

결과부터 말하자면 기말과제는 만점을 받았고, 학점은 A+을 받았다. 


보고서에 적은 순서로 포스팅을 할 예정이다. 

 

1. Project 목적

2. 배경 및 필요성

3. 데이터 수집 및 전처리

4. 데이터 분석

5. 결론

 

언어 : Python

사용 라이브러리 : pandas, folium, googlemaps

# 필요 라이브러리 import 
import pandas as pd
import folium
import folium.plugins as plugins
import googlemaps

 

참고로 해당 프로젝트는 2021년 6~7월에 진행한 것이라서 지금이랑 코로나 상황이 많이 다르다.

500~1500명 정도로 지금보다는 확연히 적은 수이지만, 물론 이때도 심각하였고 거리두기를 강화해서 저녁 10시 제한이 걸려있는 상황이다. 


[ Project 목적 ] 

중학생 때부터 지겹도록 서울 지하철을 많이 타고 다녔다. 물론 지금도 지겹도록 타고 있다.

아침 출근시간, 저녁 퇴근시간을 보면 유동인구가 많은 역에는 역무원들이 추가로 배치되어 있는 것을 볼 수 있다.

 

구토나 음식물로 인하여 전철이 오염되거나 갑작스러운 상황을 미리 대비하기 위해 적은 직원들을 효율적으로 배치하고 집중 분배를 시킬 필요가 있다. 

집중분배를 하기 위해 승·하차 인원 정보 데이터를 이용하여 언제, 어디에 사람들이 제일 많이 모이는지 확인한다.

특히 거리두기 강화로 저녁 10시에 승·하차인원이 급증하게 되는데 이때 어느 지하철역의 사람이 제일 많이 모이는지 확인한다.

 

이 프로젝트를 통해서 서울 지하철의 직원을 효율적으로 배치하기 위해 데이터 분석을 통하여 언제, 어디에 승객들이 가장 많이 모이는지 미리 예측할 수 있도록 도움을 주고자 한다. 

(물론, 이미 데이터 분석을 통해서 효율적으로 배치하고 있을 것이다.)


[ Project 배경 및 필요성 ] 

옛날에도 자주 겪었고, 최근에 또 겪었던 일이 있다.

학교를 다닐 때 지하철 마지막 차를 많이 탔었는데 술을 먹고 타는 사람들이 굉장히 많았다. 

그래서 마지막 차를 타면 높은 확률로 구토를 자주 본다.🤮🤮

 

이제는 사회적 거리두기 강화로 인하여 저녁 10시가 되면 식당 문을 닫아서 저녁 10시까지 빠르게 먹고 지하철을 타는 사람들이 많다.  (이때는 저녁 10시였다.)

마지막 차처럼 술에 취한 사람도 많지만, 사람도 많아서 구토를 발견하면 너무 큰 피해를 준다.

 

지하철 안에서 구토를 하거나 음식물을 흘린 사람들은 휴지 같은 닦을 것이 없어서 못 치워서 주변 사람들에게 휴지가 있는지 물어봐서 치우는 게 정상이지만, 대부분은 다른 칸으로 가던가 그냥 나가버린다. 

 

객실 내부의 청소는 보통 종착역에 도착했을 때 하기 때문에, 종착역 도착하기 전에 오염이 되면 좌석에 앉지도 못하고 냄새로 인하여 주변에 여러모로 피해가 많기 때문에 신속한 처리가 필요하다고 본다.

 

목적에도 말하였듯이 출퇴근 시간에 사람들이 많이 몰리는 지하철역에는 직원이 앞뒤로 1명씩 배치가 되어있는 것을 종종 본다. 하지만, 그렇지 않은 역이 대부분이고 지하철 운행하는 기관사분이 마이크를 통해 말을 하여도 통제가 전혀 되지 않는다. 이러면 다음 열차부터 계속 지연되어서 몇 백에서 몇 천이 피해를 보는 것이다. 

 

이런 피해를 자주 당해서 언제 어디에 승객들이 많이 몰리는지 알려주어야겠다는 필요성을 느꼈다.

 

해결하기 위해서 직원을 더 뽑는 방안도 있다.

하지만 2021년 코로나19와 우대권 등의 관한 문제로 인하여 서울교통공사의 예상 적자가 1조 넘게 발생하였고, 적자는 점점 늘어나고 있다.

관련 뉴스 : https://www.news1.kr/articles/?4332941

 

[단독] '1조 적자' 서울교통공사 "1539명 감축"…구조조정 공식화

사실 앞에 겸손한 민영 종합 뉴스통신사 뉴스1

www.news1.kr

큰 폭으로 적자가 증가하고 있다.

덩달이 직원도 감축하기 때문에 더 채용하거나 근무시간을 늘리는 것은 불가능하다.

그래서 남은 직원을 이용하여 효율적으로 운영시키는 것이 필요하다.

 

이것에 대해서 여러 조사를 하다가 서울교통공사가 적자라는 것에 대해 크게 와닿은 영상이 있었다.

https://www.youtube.com/watch?v=0vlrWm8ebtk 

인형을 팔았다는 사실을 이 영상 보고 알았지만, 적자가 심각하다는 것을 각인시킨 영상이었다.

 


[ 데이터 수집 및 전처리 ]

데이터 수집

데이터는 [서울시 지하철 호선별 역별 시간대별 승·하차 인원 정보]를 이용하였고, [서울 열린 데이터 광장]에서 수집하였다.

이 데이터는 티머니로부터 제공받았다고 한다.

http://data.seoul.go.kr/dataList/OA-12252/S/1/datasetView.do

 

열린데이터광장 메인

데이터분류,데이터검색,데이터활용

data.seoul.go.kr

2015.01부터 2021.05까지의 승·하차 인원 수가 적혀 있는 데이터이다.

데이터는 정형 데이터로 되어있고, 속성은 [사용 월, 호선명, 지하철역, 시간별 승·하차인원]으로 총 52개로 구성되어있다.

# 승하차 인원정보 (2021.05~2015.01)
station_people = pd.read_csv('서울시 지하철 호선별 역별 시간대별 승하차 인원 정보.csv',encoding='EUC-KR')

# info
station_people.info()

컬럼이 너무 많아서 짤렸지만 03시~04시까지 있다.

# size
station_people.shape

행은 44730개가 있고 총 52개의 열로 구성되어있다.

 

 


데이터 전처리 1 - 지하철역 위치

역 위치를 파악하여 지도를 통해 시각화를 하기 위해 folium라이브러리를 사용하였고, 지하철역 위경도를 뽑기 위해 googlemaps 라이브러리를 사용했다.

후에 설명을 하겠지만, 이런 식으로 시각화를 도와주는 라이브러리들이다. 

 

시각화를 위해서는 우선적으로 지하철역의 위경도를 알아야 한다. 

해당 데이터셋에 위경도 관련 정보를 없기 때문에 위경도가 있는 데이터셋을 찾아보려고 했으나, 마땅한 데이터가 없어서 포기하고 googlemaps 라이브러리를 이용해 위경도를 추가하였다.

※ 관련 내용은 밑 블로그 게시글을 참고

https://eunjin3786.tistory.com/304

 

[Python] 구글 Geocoding API 사용해보기

[1] 개념 - 지오코딩 (Geocoding) 주소 (ex. '1600 Amphitheatre Parkway, Mountain View, CA') 를 지리적 좌표 (위도 37.423021, 경도 -122.083739) 로 변환하는 것을 말합니다. - 역지오코딩 (Reverse geocoding..

eunjin3786.tistory.com

 

# data read
address_station = pd.read_csv('서울시 지하철 호선별 역별 시간대별 승하차 인원 정보.csv',encoding='EUC-KR')

# 호선명이랑 지하철 역 정보만 추출
address_station=address_station.loc[address_station['사용월']==202105,:]
address_station=address_station[['호선명','지하철역']]

서울 지하철역이 새로 생기는 것도 있고, 없어지는 것도 있기 때문에 제일 최근 값인 21년 5월에 승·하차 데이터가 발생한 지하철역을 가지고 왔다.  

호선명은 역 이름이 같은 경우 구분하기 위해서 가져왔다. (양평 - 중앙선, 5호선)

 

 

 

# 정확한 위도와 경도를 얻기위해 역 추가
for i in address_station.index:
    station=''.join(list(address_station.loc[i,['지하철역']]))
    if station[-1] != '역':
        address_station.loc[i,['지하철역']] = station+'역'

구글맵에서 위경도 값을 가져오기 때문에 검색을 위해서 정확한 지하철역 이름으로 했다.

my_key = "******************************************"
maps = googlemaps.Client(key=my_key)
lat = []  #위도
lng = []  #경도

# 위치를 찾을 장소나 주소를 넣어준다.
places = list(address_station['지하철역'])

i=0
for place in places:   
    i = i + 1
    try:
        geo_location = maps.geocode(place)[0].get('geometry')
        lat.append(geo_location['location']['lat'])
        lng.append(geo_location['location']['lng'])
        

    except:
        lat.append('')
        lng.append('')
        print("%d번 인덱스 위치를 찾는데 실패했습니다."%(i))


# 데이터프레임만들어 출력하기
df = pd.DataFrame({'위도':lat, '경도':lng}, index=places)
print(df)

위 코드 결과

208번 인덱스를 제외하고 나머지의 위·경도는 잘 찾은 모습이다.

address_station['위도']=lat
address_station['경도']=lng

# 동일한 역 처리
address_station.loc[(address_station['지하철역']=='양평역')&(address_station['호선명']=='5호선'),['위도']]= 37.526226
address_station.loc[(address_station['지하철역']=='양평역')&(address_station['호선명']=='5호선'),['경도']]= 126.8844202

address_station.loc[(address_station['지하철역']=='양평역')&(address_station['호선명']=='중앙선'),['위도']]= 37.4927357
address_station.loc[(address_station['지하철역']=='양평역')&(address_station['호선명']=='중앙선'),['경도']]= 127.4896358

# 위도 경도 못찾는 역 삽입
address_station.loc[(address_station['지하철역']=='증산(명지대앞)역'),['위도']]= 37.5819884
address_station.loc[(address_station['지하철역']=='증산(명지대앞)역'),['경도']]= 126.9101305

이름이 동일한 역의 위·경도를 수정하고 208번 인덱스('증산(명지대앞)역') 위·경도를 추가했다.

 

# 서울시 중심부의 위도, 경도 입니다.
center = [37.541, 126.986]

# 맵이 center 에 위치하고, zoom 레벨은 11로 시작하는 맵 m을 만듭니다.
m = folium.Map(location=center, zoom_start=10)
# 컬러 딕셔너리 (6호선 색깔이 없어서 검정으로 대체)
c_dic = {'1호선':'darkblue','2호선':'green','3호선':'orange','4호선':'lightblue','5호선':'darkpurple','6호선':'black','7호선':'darkgreen','8호선':'pink','9호선':'beige','중앙선':'blue',
        '9호선2~3단계':'beige','경강선':'cadetblue','경부선':'cadetblue','경원선':'cadetblue','경의선':'cadetblue','경인선':'cadetblue','경춘선':'blue','공항철도 1호선':'cadetblue','과천선':'cadetblue','분당선':'lightred'
         ,'수인선':'lightred','안산선':'red','우이신설선':'cadetblue','일산선':'red','장항선':'cadetblue'}

# Choropleth 레이어를 만들고, 맵 m에 추가합니다.
for i in address_station.index:
    folium.Marker(
        location = list(address_station.loc[i,['위도', '경도']]),
        popup = address_station.loc[i, '지하철역'],
        icon=folium.Icon(color=c_dic[address_station.loc[i, '호선명']],icon='star')
    ).add_to(m)

# 맵 m을 저장
m.save('map.html')

folium 라이브러리를 이용해서 지하철역마다 위·경도가 제대로 들어갔는지 확인했다.

호선 색깔을 최대한 현실 반영해서 만들었다.

지하철역위치.html
0.61MB

 

결괏값은 이런 식으로 나오고 확대·축소도 가능하다.

서울 지하철이 얼마나 많은지 한눈에 확인이 가능하다. 

 

앞으로 위·경도 정보는 시각화할 때마다 사용하기 때문에 저장

# csv 저장
address_station.to_csv("서울교통공사_역주소_위경도.csv",index=False)

데이터 전처리 2 - 날짜 지정

해당 데이터는 2015.01부터 2021.05까지의 승하차 인원수가 있다. 

그래서 코로나 상황이랑 그전에 있었던 상황이 많이 다르기 때문에,

코로나가 급격히 유행이 되면서 사회적 거리두기가 2단계로 격상된 2020년 8월부터 2021년 5월까지의 데이터만 가지고 왔다.

# 2020.08 그 전 데이터는 제외
for i in station_people.index:
    if int(station_people.loc[i,['사용월']])==202007:
        break

station_people = station_people.loc[:6041,:]
station_people.shape

# csv 저장
station_people.to_csv("서울시 지하철 호선별 역별 시간대별 승하차 인원 정보_202008까지.csv",index=False)

 

 


공공데이터라서 null값도 없고, 정형이기 때문에 전처리는 여기까지 했다.

이제 승차인원이 많은 곳은 어디인지, 하차인원이 많은 곳은 어디인지, 시각화를 통해서 분석을 할 예정이다.

 

다음 포스팅에서 이어짐..

 

728x90