본문 바로가기
ML 인공지능

[Python] 파이썬을 이용한 공공 데이터 분석 및 활용(2)

by 딧피 2021. 11. 30.
728x90
반응형


**본 내용은 Alice 의 데이터 분석을 위한 라이브러리 과정을 수강하면서 , 직접 궁금한 것을 찾아보고 공부하며 정리한 내용임을 밝힙니다.


앞번 포스팅이 너무 지저분 하여서.. 출처를 명시했으니 좀더 깔끔하게 정리를 해보려한다.



프로젝트2. 지하철_승하차_인원_분석_프로젝트

jupyter 를 여세요. 시작합니다.

 

프로젝트 목표 :
- 승차 또는 하차 시 해당 시간, 해당 역의 승객 수를 확인하기 위해 개찰구 통과 승객 수 데이터와 지하철 위치좌표 데이터를 활용
- 탐색적 데이터 분석을 수행하기 위한 데이터 정제, 특성 엔지니어링, 시각화 방법 학습


[ 프로젝트 목차]


1. 데이터 읽기:

승하차 인원 정보 데이터를 불러오고 DataFrame 구조를 확인
1.1. 데이터 불러오기
1.2. 데이터 확인하기


2. 데이터 정제: 

데이터 확인 후 형 변환 및 이상치 데이터 처리
2.1. 2021년 6월 승하차 인원만 추출


3. 데이터 시각화:

 각 변수별로 추가적인 정제 또는 feature engineering 과정을 거치고 시각화를 총해 데이터 특성 파악
3.1. 호선 별 이용객 수 출력
3.2. 특정 호선에서 역별 평균 승하차 인원 데이터 추출
3.3. 평균 승하차 인원 수 내림차순으로 막대그래프 출력
3.4. 특정 호선의 혼잡 정도와 위치좌표 데이터 병합
3.5. 특정 호선의 혼잡 정도를 지도에 출력


데이터 출처

서울시 지하철 호선별 역별 승하차 인원 정보 데이터:
 http://data.seoul.go.kr/dataList/OA-12252/S/1/datasetView.do

여기서 데이터를 가져와서 설치합니다.

프로젝트 개요

코로나 시국에 익숙해졌다고는 하지만 가끔 밖으로 나갈 때 사람 많은 곳은 피하고 싶은 생각에 어떤 장소를 피해야 하는지 알아보고 싶을 때가 있을 겁니다. 지하철 이용 승객 수를 확인해보면 혼잡도가 높은 지역을 확인해볼 수 있을 것 같습니다.
이번 프로젝트에서는 서울 열린 데이터 광장에서 제공하는 서울시 지하철 호선별 역별 승하차 인원 정보 데이터를 분석하고 지하철 역 위치 좌표 데이터를 활용해 특정 호선에서 어떤 역이 가장 혼잡한지 직관적으로 확인해봅시다.


 

1. 데이터 읽기

 

mport numpy as np 
import pandas as pd 
import matplotlib.pyplot as plt

#서울시 지하철 호선별 역별 승하차 인원 정보 데이터를 불러와 metro_all에 저장
# pd.read_csv를 통하여 승하차 인원 정보 데이터를 데이터프레임 형태로 읽어옵니다.
metro_all = pd.read_csv("./data/서울시 지하철 호선별 역별 시간대별 승하차 인원 정보_20210705.csv", encoding = 'cp949')

# 승하차 인원 정보 상위 5개 데이터를 출력합니다.
metro_all.head()

# 승하차 인원 정보 데이터프레임 정보를 요약하여 출력합니다. 
metro_all.info()


#불러온 두 데이터프레임의 특정 컬럼 데이터를 중복없이 오름차순 정렬하여 확인

# metro_all DataFrame 사용월 데이터 확인
sorted(list(set(metro_all['사용월'])))

# metro_all DataFrame 호선명 데이터 확인
sorted(list(set(metro_all['호선명'])))

# DataFrame 지하철역 데이터 확인
sorted(list(set(metro_all['지하철역'])))

# DataFrame 지하철역 데이터 개수 확인
len(list(set(metro_all['지하철역'])))

 

 

2. 데이터 정제

 

앞서, 데이터를 확인해보니 2015년 1월부터 2021년 6월까지 수집된 데이터인 것을 확인
이번 프로젝트에서는 가장 최근 한달간 수집된 데이터를 기준으로 특정 호선에서 어떤 역이 가장 혼잡한지 확인하고자 함.

 

2.1. 2021년 6월 승하차 인원만 추출

집된 데이터 중 가장 최근인 6월에 수집한 데이터만 추출하고 불필요한 컬럼을 제거해봅시다.

# 2021년 6월 총 승객수만 추출
metro_recent = metro_all[metro_all['사용월']==202106]
metro_recent

# 불필요한 작업일자 컬럼 제거
metro_recent = metro_recent.drop(columns={'작업일자'})
metro_recent

 

 

3. 데이터 시각화

2021년 6월 데이터만 추출한 metro_recent를 활용하여 다양한 데이터 시각화 및 혼잡도 분석을 진행해봅시다.

3.1. 호선 별 이용객 수 출력

추출한 metro_recent 데이터를 활용해 이용객 수가 가장 많은 호선 순으로 막대그래프를 출력해 보겠습니다.

 

#groupby는 그룹화할것 선택

#mean은 평균값

#reset_index는 set_index와 반대로 초기화해 인덱스를 컬럼화 시킨다.

#set_index는 컬럼을 인덱스화. groupby하면 series형태로 되있는데, 그것을 어떻게 쓸건지에 따라서 사용.

#drop으로 필요없는 행/열 을 삭제해준다.

#sort_values는 정렬 방법중 하나인데 True면 오름차순 / False면 내림차순  

 

* 참고할 정렬의 4가지 방법

 

1. 데이터프레임 정렬(특정 컬럼 기준으로)

> df.sort_values('a')

2. 시리즈로 정렬하는 방법(하나의 열에 대해)

> df['a'].sort_values()

3. 내림차순 정렬 (True면 오름차순 / False면 내림차순)

df.sort_values('a', ascending=False)    

4. 여러 컬럼을 리스트로 묶는 방법 

> df.sort_values(['b','c'], ascending=False)

import matplotlib.font_manager as fm #공식적으로 알려진 한글 사용방법 , 폰트 관련용도

font_dirs = ['/usr/share/fonts/truetype/nanum', ]
font_files = fm.findSystemFonts(fontpaths=font_dirs)

for font_file in font_files:
    fm.fontManager.addfont(font_file)

metro_line = metro_recent.groupby(['호선명']).mean().reset_index()

metro_line = metro_line.drop(columns='사용월').set_index('호선명')#drop 선택한 행,열을 삭제한 새로운 객체 생ㅇ성
metro_line = metro_line.mean(axis=1).sort_values(ascending=False)

plt.figure(figsize=(20,10))
plt.rc('font', family="NanumBarunGothic")
plt.rcParams['axes.unicode_minus'] = False

metro_line.plot(kind=('bar'))
plt.show()

 

 

 

3.2. 특정 호선에서 역별 평균 승하차 인원 데이터 추출

다양한 호선에서 역별 평균 승하차 인원이 많은 역은 어디일까요? 이용객이 가장 많은 2호선 기준으로 확인해봅시다.

line = '2호선'
metro_st = metro_recent.groupby(['호선명','지하철역']).mean().reset_index()
metro_st_line2 = metro_st[metro_st['호선명']==line]
metro_st_line2

 

여기서 부터 쬐끔 생각해야한다!

 

승하차 인원은 홀/짝수를 반복하며 나와있다. 이것을 분리해야한다.

 

for문에서

len다음으로 오는 부분을보자.

왜 -3 이냐 하면, 맨앞의 호선명/지하철역/사용월 의 3개 칼럼을 제외한 갯수의 홀/짝의 각각의 수를 구해야한다.

그래서 ! 나누기 2를 해준것.

그리고 

3+2*i 는 3,5,7,9 식으로가고

4+2*i 는 4,6,8,10 식으로 간다.

# 승차 인원 컬럼만 추출
metro_get_on = pd.DataFrame()
metro_get_on['지하철역'] = metro_st_line2['지하철역']
for i in range(int((len(metro_recent.columns)-3)/2)):
    metro_get_on[metro_st_line2.columns[3+2*i]] = metro_st_line2[metro_st_line2.columns[3+2*i]]
metro_get_on = metro_get_on.set_index('지하철역')
metro_get_on

 

# 하차 인원 컬럼만 추출
metro_get_off = pd.DataFrame()
metro_get_off['지하철역'] = metro_st_line2['지하철역']
for i in range(int((len(metro_recent.columns)-3)/2)):
    metro_get_off[metro_st_line2.columns[4+2*i]] = metro_st_line2[metro_st_line2.columns[4+2*i]]
metro_get_off = metro_get_off.set_index('지하철역')
metro_get_off

# 역 별 평균 승하차 인원을 구한 후 정수로 형 변환하여 데이터프레임으로 저장
df = pd.DataFrame(index = metro_st_line2['지하철역'])
df['평균 승차 인원 수'] = metro_get_on.mean(axis=1).astype(int)
df['평균 하차 인원 수'] = metro_get_off.mean(axis=1).astype(int)
df

 

 

3.3. 평균 승하차 인원 수 내림차순으로 막대그래프 출력

2호선 기준 6월 한 달간 강남 > 잠실 > 신림 > 구로디지털단지 > 홍대입구 > 선릉 순으로 평균 승차 인원이 많았습니다.

# 승차 인원 수 Top10 
top10_on = df.sort_values(by='평균 승차 인원 수', ascending=False).head(10)

plt.figure(figsize=(20,10))
plt.rc('font', family="NanumBarunGothic")
plt.rcParams['axes.unicode_minus'] = False

plt.bar(top10_on.index, top10_on['평균 승차 인원 수'])
for x, y in enumerate(list(top10_on['평균 승차 인원 수'])):
    if x == 0:
        plt.annotate(y, (x-0.15, y), color = 'red')
    else:
        plt.annotate(y, (x-0.15, y))

plt.title('2021년 6월 평균 승차 인원 수 Top10')
plt.show()

 

평균 하차 인원은 거의 동일하게 강남 > 잠실 > 신림 > 구로디지털단지 > 홍대입구 > 역삼 순으로 많았습니다.

 

# 하차 인원 수 Top10
top10_off = df.sort_values(by='평균 하차 인원 수', ascending=False).head(10)

plt.figure(figsize=(20,10))
plt.rc('font', family="NanumBarunGothic")
plt.rcParams['axes.unicode_minus'] = False

plt.bar(top10_off.index, top10_off['평균 하차 인원 수'])
for x, y in enumerate(list(top10_off['평균 하차 인원 수'])):
    if x == 0:
        plt.annotate(y, (x-0.15, y), color = 'red')
    else:
        plt.annotate(y, (x-0.15, y))

plt.title('2021년 6월 평균 하차 인원 수 Top10')
plt.show()

 

 

 

퀴즈1.

6호선의 지하철 역 중에서 승차 인원수가 가장 많은 역명을 구하세요.

 

# 3.2.의 첫 번째 셀에서 line값만 수정한 후 
# 3.2.와 3.3. 코드를 순서대로 다시 실행해보면 답을 구할 수 있습니다.
line = '6호선'
metro_st = metro_recent.groupby(['호선명','지하철역']).mean().reset_index()
metro_st_line2 = metro_st[metro_st['호선명']==line]
metro_st_line2


# 승차 인원 컬럼만 추출
metro_get_on = pd.DataFrame()
metro_get_on['지하철역'] = metro_st_line2['지하철역']
for i in range(int((len(metro_recent.columns)-3)/2)):
    metro_get_on[metro_st_line2.columns[3+2*i]] = metro_st_line2[metro_st_line2.columns[3+2*i]]
metro_get_on = metro_get_on.set_index('지하철역')
metro_get_on

# 하차 인원 컬럼만 추출
metro_get_off = pd.DataFrame()
metro_get_off['지하철역'] = metro_st_line2['지하철역']
for i in range(int((len(metro_recent.columns)-3)/2)):
    metro_get_off[metro_st_line2.columns[4+2*i]] = metro_st_line2[metro_st_line2.columns[4+2*i]]
metro_get_off = metro_get_off.set_index('지하철역')
metro_get_off

# 역 별 평균 승하차 인원을 구한 후 정수로 형 변환하여 데이터프레임으로 저장
df = pd.DataFrame(index = metro_st_line2['지하철역'])
df['평균 승차 인원 수'] = metro_get_on.mean(axis=1).astype(int)
df['평균 하차 인원 수'] = metro_get_off.mean(axis=1).astype(int)
df

top10_on = df.sort_values(by='평균 승차 인원 수', ascending=False).head(1)
top10_on.index[0]

# 6호선 지하철 역 중 승차 인원 수가 가장 많은 역명을 quiz_1 변수에 저장합니다.
# '~~역'에서 역을 제외한 ~~을 문자형으로 저장합니다.
quiz_1 = top10_on.index[0]

3.4. 특정 호선의 혼잡 정도와 위치좌표 데이터 병합

특정 호선의 지하철 역 마다 지도에 정보를 출력하기 위해서는 각 위치의 좌표정보가 필요합니다.

이를 해결하기 위해 카카오 API를 활용하여 csv 파일로 만들어두었습니다.

출처:
https://developers.kakao.com/docs/latest/ko/local/dev-guide#search-by-keyword
https://developers.kakao.com/docs/latest/ko/local/dev-guide#address-coord

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

# 지하철 역별 위치좌표에 대한 데이터를 불러옵니다.
subway_location = pd.read_csv('./data/지하철 역 위치 좌표.csv')
subway_location

 

먼저 특정 호선의 역별 평균 승하차 인원 수와 지하철 역별 위치좌표 데이터를 병합하여 데이터프레임을 생성해봅시다.

 

# 특정 호선의 역별 평균 승하차 인원 수와 지하철 역 위치 좌표를 데이터프레임으로 반환하는 함수입니다.
def get_nums_and_location(line, metro_st):
    
    # 특정 호선의 데이터만 추출합니다.
    metro_line_n = metro_st[metro_st['호선명']==line]
    
    # 승차 인원 컬럼만 추출합니다.
    metro_get_on = pd.DataFrame()
    metro_get_on['지하철역'] = metro_line_n['지하철역']
    for i in range(int((len(metro_recent.columns)-3)/2)):
        metro_get_on[metro_line_n.columns[3+2*i]] = metro_line_n[metro_line_n.columns[3+2*i]]
    metro_get_on = metro_get_on.set_index('지하철역')
    
    # 하차 인원 컬럼만 추출합니다.
    metro_get_off = pd.DataFrame()
    metro_get_off['지하철역'] = metro_line_n['지하철역']
    for i in range(int((len(metro_recent.columns)-3)/2)):
        metro_get_off[metro_line_n.columns[4+2*i]] = metro_line_n[metro_line_n.columns[4+2*i]]
    metro_get_off = metro_get_off.set_index('지하철역')
    
    # 역 별 평균 승하차 인원을 구한 후 정수로 형 변환하여 데이터프레임으로 저장합니다.
    df = pd.DataFrame(index = metro_line_n['지하철역'])
    df['평균 승차 인원 수'] = metro_get_on.mean(axis=1).astype(int)
    df['평균 하차 인원 수'] = metro_get_off.mean(axis=1).astype(int)
    
    # 지하철역 명 동일하도록 설정합니다.
    temp = []
    df = df.reset_index()
    for name in df['지하철역']:
        temp.append(name.split('(')[0]+'역')
    df['지하철역'] = temp
    
    # 지하철역 명을 기준으로 두 데이터프레임 병합합니다.
    df = df.merge(subway_location, left_on='지하철역', right_on='지하철역')
    return df

3.5. 특정 호선의 혼잡 정도를 지도에 출력

지도를 출력하기 위한 라이브러리로 folium을 사용해 봅시다.

 

# 특정 호선의 역별 평균 승하차 인원 수와 지하철 역 위치 좌표를 데이터프레임으로 반환하는 함수입니다.
def get_nums_and_location(line, metro_st):
    
    # 특정 호선의 데이터만 추출합니다.
    metro_line_n = metro_st[metro_st['호선명']==line]
    
    # 승차 인원 컬럼만 추출합니다.
    metro_get_on = pd.DataFrame()
    metro_get_on['지하철역'] = metro_line_n['지하철역']
    for i in range(int((len(metro_recent.columns)-3)/2)):
        metro_get_on[metro_line_n.columns[3+2*i]] = metro_line_n[metro_line_n.columns[3+2*i]]
    metro_get_on = metro_get_on.set_index('지하철역')
    
    # 하차 인원 컬럼만 추출합니다.
    metro_get_off = pd.DataFrame()
    metro_get_off['지하철역'] = metro_line_n['지하철역']
    for i in range(int((len(metro_recent.columns)-3)/2)):
        metro_get_off[metro_line_n.columns[4+2*i]] = metro_line_n[metro_line_n.columns[4+2*i]]
    metro_get_off = metro_get_off.set_index('지하철역')
    
    # 역 별 평균 승하차 인원을 구한 후 정수로 형 변환하여 데이터프레임으로 저장합니다.
    df = pd.DataFrame(index = metro_line_n['지하철역'])
    df['평균 승차 인원 수'] = metro_get_on.mean(axis=1).astype(int)
    df['평균 하차 인원 수'] = metro_get_off.mean(axis=1).astype(int)
    
    # 지하철역 명 동일하도록 설정합니다.
    temp = []
    df = df.reset_index()
    for name in df['지하철역']:
        temp.append(name.split('(')[0]+'역')
    df['지하철역'] = temp
    
    # 지하철역 명을 기준으로 두 데이터프레임 병합합니다.
    df = df.merge(subway_location, left_on='지하철역', right_on='지하철역')
    return df

 

이제 특정 호선의 역별 평균 승차 인원 수를 원형마커를 통해 지도에 출력해봅시다

#color - 선색
#fill_color -면색

# 특정 호선의 역별 평균 승하차 인원 수와 위치좌표 데이터만 추출합니다.
rail = '6호선'
df = get_nums_and_location(rail, metro_st)

# 서울의 중심에 위치하는 명동역의 위도와 경도를 중심으로 지도 출력합니다.
latitude = subway_location[subway_location['지하철역']=='명동역']['x좌표'] #위도
longitude = subway_location[subway_location['지하철역']=='명동역']['y좌표']#경도
map_osm = folium.Map(location = [latitude, longitude], zoom_start = 12) #지도출력

# 각 지하철 역의 위치별로 원형마커를 지도에 추가합니다.
for i in df.index:
    marker = folium.CircleMarker([df['x좌표'][i],df['y좌표'][i]],
                        radius = (df['평균 승차 인원 수'][i]+1)/3000, # 인원 수가 0일 때 계산오류 보정
                        popup = [df['지하철역'][i],df['평균 승차 인원 수'][i]], 
                        color = 'blue', 
                        fill_color = 'blue')
    marker.add_to(map_osm)

map_osm

 

퀴즈2. 강남역의 x좌표(위도)를 구하세요.

 

 

# get_nums_and_location() 함수를 활용하면 쉽게 구할 수 있습니다.
# 강남역은 2호선이기 때문에 df = get_nums_and_location('2호선', metro_st)으로 데이터프레임을 추출합니다.
# df[df['지하철역']=='강남역']['x좌표']을 통해 컬럼 '지하철역'이 '강남역'인 행을 추출하고 'x좌표'값을 구해보세요.

df = get_nums_and_location('2호선', metro_st)

x = df[df['지하철역']=='강남역']['x좌표']
x[0]

# float형으로 좌표값만 저장합니다. 예시: 37.123456
quiz_2 = x[0]

 

728x90
반응형

댓글