In [2]:
import requests
import folium
import json
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
1-1. 데이터 요청하기¶
In [5]:
targetSite = 'https://www.bikeseoul.com/app/station/getStationRealtimeStatus.do'
request = requests.post(targetSite, data={'stationGrpSeq':'ALL'})
print(request)
# print(request.text)
<Response [200]>
1-2. json 데이터 처리하기¶
- json.loads(): json 타입의 문자열 데이터를 파이썬에서 처리할 수 있도록 변환(딕셔너리로 변환)
In [7]:
bike_json = json.loads(request.text)
print(bike_json)
print(type(bike_json))
{'stationImgPath': '/nas_link/spb/attachFiles/file_admin/basePath', 'appUserSessionVO': {'lang': 'LAG_001', 'regDttm': None, 'encPwd': None, 'usrClsCd': None, 'usrDeviceId': None, 'loginId': None, 'mbId': None, 'mpnLostYn': None, 'snsType': None, 'usrSeq': None, 'voucherEndDttm': None, 'voucherSeq': None, 'usrType': None, 'usrMpnNo': None, 'appOsType': None, 'orgType': None, 'snsId': None, 'viewFlg': 'list', 'usrBirthDate': None, 'sexCd': None, 'rentEncPwd': None, 'telecomClsCd': None, 'authCiVal': None, 'authClsCd': None, 'mbTelNo': None, 'mbEmailName': None, 'mbPostNo': None, 'mbAddr1': None, 'mbAddr2': None, 'parentSexCd': None, 'parentBirthDate': None, 'parentMpnNo': None, 'emailSendAgreeYn': None, 'lastLoginDttm': None, 'mbWgt': None, 'langClsCd': None, 'leaveYn': None, 'leaveReasonCd': None, 'leaveDttm': None, 'mbInfoColecAgreeDttm': None, 'mpnLostDttm': None, 'pagingYn': None, 'usrIp': None, 'partyVoucherSeq': None, 'elecVoucherSeq': None, 'requestSeq': None, 'usrDeviceType': None, 'authDiVal': None, 'snsEmail': None, 'tCardYn': None, 'mCardYn': None, 'mainType': None, 'pageSize': 0, 'currentPageNo': 1, 'recordCountPerPage': 0, 'totalRecordCount': 0, 'firstRecordIndex': 0, 'searchValue': None, 'searchParameter': None, 'searchDate': None, 'searchStartDate': None, 'searchEndDate': None, 'mode': None}, 'loginYn': 'N', 'realtimeList': [{'stationName': '102. 망원역 1번출구 앞', 'stationImgFileName': '', 'stationId': 'ST-4', 'stationLongitude': '126.91062927', 'stationLatitude': '37.55564880', 'rackTotCnt': '15', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '5', 'parkingELECBikeCnt': '11', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '103. 망원역 2번출구 앞', 'stationImgFileName': '', 'stationId': 'ST-5', 'stationLongitude': '126.91083527', 'stationLatitude': '37.55495071', 'rackTotCnt': '14', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '2', 'parkingELECBikeCnt': '0', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '104. 합정역 1번출구 앞', 'stationImgFileName': '', 'stationId': 'ST-6', 'stationLongitude': '126.91508484', 'stationLatitude': '37.55073929', 'rackTotCnt': '13', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '3', 'parkingELECBikeCnt': '0', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '105. 합정역 5번출구 앞', 'stationImgFileName': '', 'stationId': 'ST-7', 'stationLongitude': '126.91482544', 'stationLatitude': '37.55000687', 'rackTotCnt': '5', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '0', 'parkingELECBikeCnt': '0', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '106. 합정역 7번출구 앞', 'stationImgFileName': '', 'stationId': 'ST-8', 'stationLongitude': '126.91282654', 'stationLatitude': '37.54864502', 'rackTotCnt': '12', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '0', 'parkingELECBikeCnt': '0', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '107. 신한은행 서교동지점', 'stationImgFileName': '', 'stationId': 'ST-9', 'stationLongitude': '126.91850281', 'stationLatitude': '37.55751038', 'rackTotCnt': '5', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '18', 'parkingELECBikeCnt': '2', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '108. 서교동 사거리', 'stationImgFileName': '', 'stationId': 'ST-10', 'stationLongitude': '126.91861725', 'stationLatitude': '37.55274582', 'rackTotCnt': '12', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '16', 'parkingELECBikeCnt': '0', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '111. 상수역 2번출구 앞', 'stationImgFileName': '', 'stationId': 'ST-15', 'stationLongitude': '126.92353058', 'stationLatitude': '37.54787064', 'rackTotCnt': '10', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '0', 'parkingELECBikeCnt': '0', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '112. 극동방송국 앞', 'stationImgFileName': '', 'stationId': 'ST-16', 'stationLongitude': '126.92320251', 'stationLatitude': '37.54920197', 'rackTotCnt': '10', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '2', 'parkingELECBikeCnt': '0', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '113. 홍대입구역 2번출구 앞', 'stationImgFileName': '', 'stationId': 'ST-18', 'stationLongitude': '126.92382050', 'stationLatitude': '37.55743790', 'rackTotCnt': '25', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '51', 'parkingELECBikeCnt': '11', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '114. 홍대입구역 8번출구 앞', 'stationImgFileName': '', 'stationId': 'ST-20', 'stationLongitude': '126.92442322', 'stationLatitude': '37.55706024', 'rackTotCnt': '15', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '11', 'parkingELECBikeCnt': '1', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '115. 마스타 빌딩 앞', 'stationImgFileName': '', 'stationId': 'ST-12', 'stationLongitude': '126.92711639', 'stationLatitude': '37.55893326', 'rackTotCnt': '15', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '9', 'parkingELECBikeCnt': '3', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '117. 홍은사거리', 'stationImgFileName': '', 'stationId': 'ST-17', 'stationLongitude': '126.94132996', 'stationLatitude': '37.59115982', 'rackTotCnt': '23', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '8', 'parkingELECBikeCnt': '4', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '118. 광흥창역 2번출구 앞', 'stationImgFileName': '', 'stationId': 'ST-19', 'stationLongitude': '126.93176270', 'stationLatitude': '37.54773331', 'rackTotCnt': '9', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '0', 'parkingELECBikeCnt': '0', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '119. 서강나루 공원', 'stationImgFileName': '', 'stationId': 'ST-21', 'stationLongitude': '126.93146515', 'stationLatitude': '37.54520798', 'rackTotCnt': '10', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '0', 'parkingELECBikeCnt': '5', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '120. 신수동 사거리', 'stationImgFileName': '', 'stationId': 'ST-22', 'stationLongitude': '126.93411255', 'stationLatitude': '37.54524231', 'rackTotCnt': '5', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '1', 'parkingELECBikeCnt': '0', 'stationSeCd': 'RAK_002', 'mode': None}, {'stationName': '121. 마포소방서 앞', 'stationImgFileName': '', 'stationId': 'ST-23', 'stationLongitude': '126.93317413', 'stationLatitude': '37.54976654', 'rackTotCnt': '15', 'parkingBikeTotCnt': '0', 'parkingQRBikeCnt': '1', 'parkingELECBikeCnt': '0', 'stationSeCd': 'RAK_002', 'mode': None}
<class 'dict'>
1-3. 딕셔너리 타입의 데이터를 데이터프레임으로 변환하기¶
- json_normalize(): 딕셔너리 타입의 데이터를 판다스 데이터프레임으로 변환
In [9]:
bike_df = pd.json_normalize(bike_json, 'realtimeList')
bike_df
Out[9]:
stationName | stationImgFileName | stationId | stationLongitude | stationLatitude | rackTotCnt | parkingBikeTotCnt | parkingQRBikeCnt | parkingELECBikeCnt | stationSeCd | mode | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 102. 망원역 1번출구 앞 | ST-4 | 126.91062927 | 37.55564880 | 15 | 0 | 5 | 11 | RAK_002 | None | |
1 | 103. 망원역 2번출구 앞 | ST-5 | 126.91083527 | 37.55495071 | 14 | 0 | 2 | 0 | RAK_002 | None | |
2 | 104. 합정역 1번출구 앞 | ST-6 | 126.91508484 | 37.55073929 | 13 | 0 | 3 | 0 | RAK_002 | None | |
3 | 105. 합정역 5번출구 앞 | ST-7 | 126.91482544 | 37.55000687 | 5 | 0 | 0 | 0 | RAK_002 | None | |
4 | 106. 합정역 7번출구 앞 | ST-8 | 126.91282654 | 37.54864502 | 12 | 0 | 0 | 0 | RAK_002 | None | |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2730 | 6058. 서울도시건축전시관 옆 | ST-3297 | 126.97684479 | 37.56653976 | 10 | 0 | 0 | 0 | RAK_002 | None | |
2731 | 6058. 서울도시건축전시관 옆 | ST-3297 | 126.97684479 | 37.56653976 | 10 | 0 | 0 | 0 | RAK_002 | None | |
2732 | 6171. 월드빌딩 앞 | ST-3276 | 126.83743286 | 37.54098129 | 12 | 0 | 4 | 0 | RAK_002 | None | |
2733 | 6172. 가양5단지아파트 | ST-3281 | 126.85464478 | 37.56447983 | 10 | 0 | 12 | 0 | RAK_002 | None | |
2734 | 6173. 서울자동차운전전문학원 | ST-3284 | 126.82106018 | 37.54613495 | 10 | 0 | 18 | 0 | RAK_002 | None |
2735 rows × 11 columns
In [10]:
bike_df.columns
Out[10]:
Index(['stationName', 'stationImgFileName', 'stationId', 'stationLongitude',
'stationLatitude', 'rackTotCnt', 'parkingBikeTotCnt',
'parkingQRBikeCnt', 'parkingELECBikeCnt', 'stationSeCd', 'mode'],
dtype='object')
- stationName: 대여소 이름
- stationId: 고유한 대여소 번호
- stationLongitude: 대여소 경도
- stationLatitude: 대여소 위도
- rackTotCnt: 주차 가능한 전체 자전거 대수
- parkingBikeTotCnt: 주차된 따릉이 총 대수
- parkingQRBikeCnt: 주차된 따릉이 QR형 총 대수
- parkingELECBikeCnt: 주차된 새싹 따릉이 총 대수
In [11]:
bike_df_map = bike_df[['stationName', 'stationId', 'stationLongitude', 'stationLatitude',
'rackTotCnt', 'parkingBikeTotCnt', 'parkingQRBikeCnt', 'parkingELECBikeCnt']]
bike_df_map
Out[11]:
stationName | stationId | stationLongitude | stationLatitude | rackTotCnt | parkingBikeTotCnt | parkingQRBikeCnt | parkingELECBikeCnt | |
---|---|---|---|---|---|---|---|---|
0 | 102. 망원역 1번출구 앞 | ST-4 | 126.91062927 | 37.55564880 | 15 | 0 | 5 | 11 |
1 | 103. 망원역 2번출구 앞 | ST-5 | 126.91083527 | 37.55495071 | 14 | 0 | 2 | 0 |
2 | 104. 합정역 1번출구 앞 | ST-6 | 126.91508484 | 37.55073929 | 13 | 0 | 3 | 0 |
3 | 105. 합정역 5번출구 앞 | ST-7 | 126.91482544 | 37.55000687 | 5 | 0 | 0 | 0 |
4 | 106. 합정역 7번출구 앞 | ST-8 | 126.91282654 | 37.54864502 | 12 | 0 | 0 | 0 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
2730 | 6058. 서울도시건축전시관 옆 | ST-3297 | 126.97684479 | 37.56653976 | 10 | 0 | 0 | 0 |
2731 | 6058. 서울도시건축전시관 옆 | ST-3297 | 126.97684479 | 37.56653976 | 10 | 0 | 0 | 0 |
2732 | 6171. 월드빌딩 앞 | ST-3276 | 126.83743286 | 37.54098129 | 12 | 0 | 4 | 0 |
2733 | 6172. 가양5단지아파트 | ST-3281 | 126.85464478 | 37.56447983 | 10 | 0 | 12 | 0 |
2734 | 6173. 서울자동차운전전문학원 | ST-3284 | 126.82106018 | 37.54613495 | 10 | 0 | 18 | 0 |
2735 rows × 8 columns
In [12]:
# 위도, 경도 -> float 변환
bike_df_map['stationLongitude'] = bike_df_map['stationLongitude'].astype(float)
bike_df_map['stationLatitude'] = bike_df_map['stationLatitude'].astype(float)
# 주차할 수 있는 자전거 대수, 주차된 자전거 총 대수, 주차된 QR자전거 총 대수, 주차된 새싹 자전거 총 대수 -> int
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]
# 따릉이 + QR + 새싹
bike_df_map['total'] = bike_df_map['parkingBikeTotCnt'] + bike_df_map['parkingQRBikeCnt'] + bike_df_map['parkingELECBikeCnt']
In [16]:
bike_df_map.dtypes
Out[16]:
stationName object
stationId object
stationLongitude float64
stationLatitude float64
rackTotCnt int64
parkingBikeTotCnt int64
parkingQRBikeCnt int64
parkingELECBikeCnt int64
total int64
dtype: object
In [17]:
bike_df_map.head()
Out[17]:
stationName | stationId | stationLongitude | stationLatitude | rackTotCnt | parkingBikeTotCnt | parkingQRBikeCnt | parkingELECBikeCnt | total | |
---|---|---|---|---|---|---|---|---|---|
0 | 102. 망원역 1번출구 앞 | ST-4 | 126.910629 | 37.555649 | 15 | 0 | 5 | 11 | 16 |
1 | 103. 망원역 2번출구 앞 | ST-5 | 126.910835 | 37.554951 | 14 | 0 | 2 | 0 | 2 |
2 | 104. 합정역 1번출구 앞 | ST-6 | 126.915085 | 37.550739 | 13 | 0 | 3 | 0 | 3 |
3 | 105. 합정역 5번출구 앞 | ST-7 | 126.914825 | 37.550007 | 5 | 0 | 0 | 0 | 0 |
4 | 106. 합정역 7번출구 앞 | ST-8 | 126.912827 | 37.548645 | 12 | 0 | 0 | 0 | 0 |
In [18]:
bike_df_map.shape
Out[18]:
(2735, 9)
In [20]:
# {정류소명} 일반:{}대, QR:{}대, 새싹:{}대, 총:{}대
bike_map = folium.Map(location=[bike_df_map['stationLatitude'].mean(),
bike_df_map['stationLongitude'].mean()],
zoom_start=12)
for index, data in bike_df_map.iterrows():
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
'코딩 > 데이터 분석' 카테고리의 다른 글
떡볶이 프렌차이즈의 입점전략 (1) | 2024.06.07 |
---|---|
전국 도시공원 데이터 (0) | 2024.06.07 |
상권별 업종 밀집 통계 데이터 (0) | 2024.06.07 |
가상 온라인 쇼핑몰 데이터 (1) | 2024.06.07 |
Matplotlib (1) | 2024.06.07 |