실시간으로 서울시에 있는 역에 따릉이가 몇 대 대여됐는지 잔여 자전거 대수를 확인해보려고 합니다.
1. 따릉이 api
(https://www.bikeseoul.com/app/station/getStationRealtimeStatus.do)
형태는 JSON형태로 되어있습니다.
필요한것들을 임포트 하겠습니다.
import requests
import folium
import json
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
- warnings.filterwarnings('ignore') == warnings을 안뜨게하는 명령어입니다.
데이터 값 | 내용 |
stationName | 대여소 이름 |
stationId | 고유한 대여소 번호 |
stationLongitude | 대여소 경도 |
stationLatitude | 대여소 위도 |
rackTotCnt | 주차 가능한 전체 자전거 대수 |
parkingBikeTotCnt | 주차된 따릉이 총 대수 |
parkingQRBikeCnt | 주차된 따릉이 qr형 총 대수 |
parkingELECBikeCnt | 주차된 새싹 따릉이 총 대수 |
1-1. 데이터 요청하기
targetSite = 'https://www.bikeseoul.com/app/station/getStationRealtimeStatus.do'
#역데이터 정보 모두 가져오기
request =requests.post(targetSite, data={'stationGrpSeq':'ALL'})
# print(request)
print(request.text)
{"stationImgPath":"/nas_link/spb/attachFiles/file_admin/basePath","appUserSessionVO":{"encPwd":null,"usrClsCd":null,"usrDeviceId":null,"usrSeq":null,"voucherEndDttm":null,"voucherSeq":null,"usrType":null,"loginId":null,"usrMpnNo":null,"snsType":null,"mbId":null,"mpnLostYn":null,"appOsType":null,"regDttm":null,"lang":"LAG_001","orgType":null,"snsId":null,"viewFlg":"list","usrBirthDate":null,"sexCd":null,"rentEncPwd":null,"telecomClsCd":null,"authCiVal":null,"authClsCd":null,"mbTelNo":null,"mbEmailName":null,"mbPostNo":null,"mbAddr1":null,"mbAddr2":null,"parentSexCd":null,"parentBirthDate":null,"parentMpnNo":null,"emailSendAgreeYn":null,"lastLoginDttm":null,"mbWgt":null,"langClsCd":null,"leaveYn":null,"leaveReasonCd":null,"leaveDttm":null,"mbInfoColecAgreeDttm":null,"mpnLostDttm":null,"pagingYn":null,"usrIp":null,"partyVoucherSeq":null,"elecVoucherSeq":null,"requestSeq":null,"usrDeviceType":null,"authDiVal":null,"snsEmail":null,"tCardYn":null,"mCardYn":null,"mainType":null,"firstRecordIndex":0,"totalRecordCount":0,"recordCountPerPage":0,"pageSize":0,"currentPageNo":1,"searchValue":null,"searchParameter":null,"searchDate":null,"searchStartDate":null,"searchEndDate":null,"mode":null},"loginYn":"N","realtimeList":[{"stationId":"ST-4","stationName":"102. 망원역 1번출구 앞","stationImgFileName":"","stationLongitude":"126.91062927","stationLatitude":"37.55564880","rackTotCnt":"15","parkingBikeTotCnt":"0","parkingQRBikeCnt":"9","parkingELECBikeCnt":"2","stationSeCd":"RAK_002","mode":null},{"stationId":"ST-5","stationName":"103. 망원역 2번출구 앞","stationImgFileName":"","stationLongitude":"126.91083527","stationLatitude":"37.55495071","rackTotCnt":"14","parkingBikeTotCnt":"0","parkingQRBikeCnt":"18","parkingELECBikeCnt":"1","stationSeCd":"RAK_002","mode":null},{"stationId":"ST-6","stationName":"104. 합정역 1번출구 앞","stationImgFileName":"","stationLongitude":"126.91508484","stationLatitude":"37.55073929","rackTotCnt":"13","parkingBikeTotCnt":"0","parkingQRBikeCnt":"0","parkingELECBikeCnt":"0","stationSeCd":"RAK_002","mode":null},{"stationId":"ST-7","stationName":"105. 합정역 5번출구 앞","stationImgFileName":"","stationLongitude":"126.91482544","stationLatitude":"37.55000687","rackTotCnt":"5","parkingBikeTotCnt":"0","parkingQRBikeCnt":"1","parkingELECBikeCnt":"0","stationSeCd":"RAK_002","mode":null},{"stationId":"ST-8","stationName":"106. 합정역 7번출구 앞","stationImgFileName":"","stationLongitude":"126.91282654","stationLatitude":"37.54864502","rackTotCnt":"12","parkingBikeTotCnt":"0","parkingQRBikeCnt":"3","parkingELECBikeCnt":"1","stationSeCd":"RAK_002","mode":null},{"stationId":"ST-9","stationName":"107. 신한은행 서교동지점","stationImgFileName":"","stationLongitude":"126.91850281","stationLatitude":"37.55751038","rackTotCnt":"5","parkingBikeTotCnt":"0","parkingQRBikeCnt":"2","parkingELECBikeCnt":"2","stationSeCd":"RAK_002","mode":null},{"stationId":"ST-10","stationName":"108. 서교동 사거리","stationImgFileName":"","stationLongitude":"126.91861725","stationLatitude":"37.55274582","rackTotCnt":"12","parkingBikeTotCnt":"0","parkingQRBikeCnt":"1","parkingELECBikeCnt":"0","stationSeCd":"RAK_002","mode":null},{"stationId":"ST-15","stationName":"111. 상수역 2번출구 앞","stationImgFileName":"","stationLongitude":"126.92353058","stationLatitude":"37.54787064","rackTotCnt":"10","parkingBikeTotCnt":"0","parkingQRBikeCnt":"2","parkingELECBikeCnt":"0","stationSeCd":"RAK_002","mode":null},{"stationId":"ST-16","stationName":"112. 극동방송국 앞","stationImgFileName":"","stationLongitude":"126.92320251","stationLatitude":"37.54920197","rackTotCnt":"10","parkingBikeTotCnt":"0","parkingQRBikeCnt":"0","parkingELECBikeCnt":"1","stationSeCd":"RAK_002","mode":null},{"stationId":"ST-18","stationName":"113. 홍대입구역 2번출구 앞","stationImgFileName":"","stationLongitude":"126.92382050","stationLatitude":"37.55743790","rackTotCnt":"25","parkingBikeTotCnt":"0","parkingQRBikeCnt":"1","parkingELECBikeCnt":"1","stationSeCd":"RAK_002","mode":null},{"stationId":"ST-20","stationName":..............더보기 |
가 나오게됩니다. 모든 역의 데이터를 가져오니 확실히엄청 많다는것을 확인할 수 있습니다.
앞서 말씀드렸듯이 json형태로 되어있기떄문에 json데이터를 처리하기로 합니다.
requests.post(targetSite, data={'stationGrpSeq':'ALL'})
을 사용하게되면 모든 로그인을 하지않아도 1,000개정도의 데이터를 가져올 수 있습니다.
1-2. json 데이터 처리하기
- json.load() : json타입의 문자열 데이터를 파이썬에서 처리할 수있도록 변환(딕셔너리로변환해줌)
bike_json = json.loads(request.text)
print(bike_json)
print(type(bike_json))
당연히 json형태도 위 값처럼 엄청 많이 나오게 되어있을테고
type은 dict로 변경했으니 잘 변경 되어있는걸 확인할 수 있습니다.
1-3. 딕셔너리 타입의 데이터를 데이터프레임으로 변환하기
- json_normalize(): 딕셔너리 자료구조의 타입의 데이터를 판다스 데이터프레임으로 변환_(판다스에있는 매소드)
지금 bike_json을 가지고 바로 df를 만드려고 하면 있는값들이있고 없는값들이 있어서 애매합니다.
그렇지만 realtimeList는 반복되는 배열이기때문에 df할 수 있습니다.
bike_df = pd.json_normalize(bike_json, 'realtimeList')
bike_df
여기서 이해가 가지않았던 부분은 보통 bike_json안의 realtimeList리스트를 가져오는것이기에 , 가 아닌 . 으로 불어와야한다고 생각했는데 여기는 함수의 인자들을 구분하기 위해서 사용됩니다.
pd.json_normalize는 함수이고 함수 호출 시 여러개의 인자를 전달 할 수 있습니다.
bike_json는 데이터 전체를 나타내는 첫번째 인자이고 realtimeList는 JSON데이터안에서 평탄화할 리스트의 키를 나타내는 두번째 인자가 됩니다.
pd.json_normalize는 JSON 데이터 구조에서 특정 키('realtimeList')를 찾아 그 안의 리스트를 평탄화하여 데이터프레임으로 만드는 함수입니다. 이 코드에서 pd.json_normalize 함수가 정확히 그 역할을 수행하고 있습니다.
즉! bike_josn안에있는 tealtimeList리스트의 인자값을을 가져오는거고 그 값들을 df로 만든 결과물이 바로 아래입니다.
( 휴 이해하는데 좀 걸림)
bike_df.columns
그럼 컬럼들을 가져오게되면 총 11개가 나타나게되고 필요한것들만 뽑아오겠습니다.
총 8개이고 목록은 아래와 같습니다.
* stationName : 대여소 이름
* stationId : 고유한 대여소 번호
* stationLongitude : 대여소 경도
* stationLatitude : 대여소 위도
* rackTotCnt : 주차 가능한 전체 자전거 대수
* parkingBikeTotCnt : 주차된 따릉이 총 대수
* parkingQRBikeCnt : 주차된 따릉이 qr형 총 대수
* parkingELECBikeCnt : 주차된 새싹 따릉이 총 대수
|
1-4. 쓸 데이터 추리기
bike_df_map = bike_df[['stationName',
'stationId',
'stationLongitude',
'stationLatitude',
'rackTotCnt',
'parkingBikeTotCnt',
'parkingQRBikeCnt',
'parkingELECBikeCnt']]
bike_df_map
여기서 우리가 보면 위도는 folat, 총 대수는 int64, 이름이나 고유한 대여소 번호는 object로 변경해야 맞을것 같습니다.
그렇지만 지금 dtypes를 찍어보면
bike_df_map.dtypes
로 모두 object로 표현됩니다. 그래서 type을 변경해야합니다.
타입 변경은 .astype(바꿀 형)을 사용합니다.
1-5. 데이터타입 변경
#형 변환하기
bike_df_map['stationLongitude'] = bike_df_map['stationLongitude'].astype(float)
bike_df_map['stationLatitude'] = bike_df_map['stationLatitude'].astype(float)
bike_df_map['rackTotCnt'] = bike_df_map['rackTotCnt'].astype(int)
bike_df_map['parkingBikeTotCnt'] = bike_df_map['parkingBikeTotCnt'].astype(int)
bike_df_map['parkingQRBikeCnt'] = bike_df_map['parkingQRBikeCnt'].astype(int)
bike_df_map['parkingELECBikeCnt'] = bike_df_map['parkingELECBikeCnt'].astype(int)
그리고 파생변수로 현재 역에 있는 따릉이의 자전거를 모두 더한 total 파생변수를 만들어줍니다.
vike_df_map['total'] = bike_df_map['parkingBikeTotCnt'] + bike_df_map['parkingQRBikeCnt'] + bike_df_map['parkingELECBikeCnt']
아직 print를 하지 않았으니 결과값은 나오지 않습니다.
여기서 타입이잘 바뀌었는지 확인해보겠습니다.
bike_df_map.dtypes
잘 변경됐고, 파생변수도 잘 들어갔는지 확인하겠습니다.
bike_df_map.head()
잘 들어갔고, row가 얼마나있는지 확인해보겠습니다.
bike_df_map.shape
#(2733, 9)
1-6. folium을 이용한 지도표시
이제 folium을 이용해서 지도에 표시를 해주겠습니다. 경도 위도는 위에 나와있는 값의 평균을 냈고 zoom_start는 12로 맞췄습니다.
bike_map = folium.Map(location=[bike_df_map['stationLatitude'].mean(),
bike_df_map['stationLongitude'].mean()],
zoom_start=12)
for문을 이용하여 데이터 표시하기
▶ popup_str 을 이용하여 일반, qr, 새싹, 총 몇대인지를 넣겠습니다.
.format을 이용하면 뒤에있는 데이터 값이 대체됩니다.
예를들어
- 첫 번째 {}는 data['stationName'] 값으로 대체됩니다.
- 두 번째 {}는 data['parkingBikeTotCnt'] 값으로 대체됩니다.
- 세 번째 {}는 data['parkingQRBikeCnt'] 값으로 대체됩니다.
- 네 번째 {}는 data['parkingELECBikeCnt'] 값으로 대체됩니다.
- 다섯 번째 {}는 data['total'] 값으로 대체됩니다.
for index, data in bike_df_map.iterrows():
# print(index, data)
popup_str = '{} 일반:{}대, QR:{}대, 세싹:{}대, 총:{}대'.format(
data['stationName'], data['parkingBikeTotCnt'], data['parkingQRBikeCnt'],
data['parkingELECBikeCnt'],data['total']
)
popup = folium.Popup(popup_str, max_width=600)
folium.Marker(location=[data['stationLatitude'], data['stationLongitude']],
popup=popup).add_to(bike_map)
bike_map
매소드 리뷰
매소드 | 설명 |
warnings.filterwarnings('ignore') | warnings을 안뜨게하는 명령어입니다. |
json.load() | son타입의 문자열 데이터를 파이썬에서 처리할 수있도록 변환(딕셔너리로변환해줌) |
.astype(바꿀 형) | dtype을 원하는 형으로 변경해줌. |
.format | 문자열 포맷팅을 위해 사용됩니다. |
'데이터 분석 및 시각화' 카테고리의 다른 글
[데이터 시각화] 떡볶이 프렌차이즈의 입점전략은 바로 이것. (0) | 2024.06.29 |
---|---|
[ML] 머신러닝(Machine Learning) (0) | 2024.06.28 |
[데이터 시각화] 전국 도시공원 데이터 활용 (0) | 2024.06.23 |
[seaborn] 상권별 업종 밀집 통계 데이터(2) (0) | 2024.06.22 |
[Matplotlib] 상권별 업종 밀집 통계 데이터 (0) | 2024.06.21 |