import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('seaborn-whitegrid')
import folium
import googlemaps
import warnings
warnings.filterwarnings('ignore')
plt.rc('font', size=14)
plt.rc('font', family='NanumGothic')
# 파일 불러오기
df_rent1 = pd.read_excel('source/Seoulbike/공공자전거 대여소별 이용정보_201906_201911.xlsx', sheet_name='대여')
df_rent2 = pd.read_excel('source/Seoulbike/공공자전거 대여소별 이용정보_201812_201905.xlsx', sheet_name='대여')
df_return1 = pd.read_excel('source/Seoulbike/공공자전거 대여소별 이용정보_201906_201911.xlsx', sheet_name='반납')
df_return2 = pd.read_excel('source/Seoulbike/공공자전거 대여소별 이용정보_201812_201905.xlsx', sheet_name='반납')
df_station = pd.read_excel('source/Seoulbike/서울특별시 공공자전거 대여소 정보(19.12.9).xlsx')
df_rent1.head(3)
대여소 그룹 | 대여소 명 | 대여 일자 / 월 | 대여 건수 | |
---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201906 | 3909 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201906 | 2432 |
2 | 강남구 | 2303. 논현역 7번출구 | 201906 | 1567 |
df_rent1.tail(3)
대여소 그룹 | 대여소 명 | 대여 일자 / 월 | 대여 건수 | |
---|---|---|---|---|
9269 | 중랑구 | 1457. 동원사거리 | 201911 | 577 |
9270 | 중랑구 | 1458. 상봉터미널2 | 201911 | 1243 |
9271 | 중랑구 | 1459. 용마한신아파트사거리 | 201911 | 339 |
df_rent2.head(3)
구분 | 대여소명 | 대여일자 | 대여건수 | |
---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201812.0 | 364.0 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201812.0 | 500.0 |
2 | 강남구 | 2303. 논현역 7번출구 | 201812.0 | 286.0 |
df_rent2.tail(3)
구분 | 대여소명 | 대여일자 | 대여건수 | |
---|---|---|---|---|
9186 | 중랑구 | 1457. 동원사거리 | 201905.0 | 827.0 |
9187 | 중랑구 | 1458. 상봉터미널2 | 201905.0 | 1421.0 |
9188 | 중랑구 | 1459. 용마한신아파트사거리 | 201905.0 | 447.0 |
df_return1.head(3)
대여소 그룹 | 대여소 명 | 반납 일자 / 월 | 반납 건수 | |
---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201906 | 4072 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201906 | 2382 |
2 | 강남구 | 2303. 논현역 7번출구 | 201906 | 1402 |
df_return1.tail(3)
대여소 그룹 | 대여소 명 | 반납 일자 / 월 | 반납 건수 | |
---|---|---|---|---|
9270 | 중랑구 | 1457. 동원사거리 | 201911 | 572 |
9271 | 중랑구 | 1458. 상봉터미널2 | 201911 | 1305 |
9272 | 중랑구 | 1459. 용마한신아파트사거리 | 201911 | 316 |
df_return2.head(3)
구분 | 대여소명 | 반납일자 | 반납건수 | |
---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201812.0 | 437.0 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201812.0 | 556.0 |
2 | 강남구 | 2303. 논현역 7번출구 | 201812.0 | 273.0 |
df_return2.tail(3)
구분 | 대여소명 | 반납일자 | 반납건수 | |
---|---|---|---|---|
9186 | 중랑구 | 1457. 동원사거리 | 201905.0 | 749.0 |
9187 | 중랑구 | 1458. 상봉터미널2 | 201905.0 | 1492.0 |
9188 | 중랑구 | 1459. 용마한신아파트사거리 | 201905.0 | 320.0 |
df_station.head(3)
대여소_구 | 대여소ID | 대여소명 | 대여소주소 | 위도 | 경도 | 기준시작일자 | 거치대수 | |
---|---|---|---|---|---|---|---|---|
0 | 마포구 | 101.0 | 101. (구)합정동 주민센터 | 서울특별시 마포구 동교로8길 58 | 37.549561 | 126.905754 | 2015-09-06 23:40:56 | 5 |
1 | 마포구 | 102.0 | 102. 망원역 1번출구 앞 | 서울특별시 마포구 월드컵로 72 | 37.555649 | 126.910629 | 2015-09-06 23:42:06 | 20 |
2 | 마포구 | 103.0 | 103. 망원역 2번출구 앞 | 서울특별시 마포구 월드컵로 79 | 37.554951 | 126.910835 | 2015-09-06 23:43:13 | 14 |
df_station.tail(3)
대여소_구 | 대여소ID | 대여소명 | 대여소주소 | 위도 | 경도 | 기준시작일자 | 거치대수 | |
---|---|---|---|---|---|---|---|---|
1538 | 종로구 | 465.0 | 465. 삼청공원 앞 | 서울특별시 종로구 삼청동 25-32 | 37.587605 | 126.983597 | 2019.11.20 | 5 |
1539 | 종로구 | 664.0 | 서울시립대 대학본부 | 동대문구 서울시립대로 163 서울시립대학교 | 37.584129 | 127.057938 | 2019.11.20 | 10 |
1540 | 합계 | NaN | 1540 | NaN | NaN | NaN | NaN | 19545 |
df_station.drop(1540, axis=0, inplace=True)
# 데이터 형태 출력
print(df_rent1.shape,'\n',df_rent2.shape)
(9272, 4) (9189, 4)
# 컬럼명 변경, 데이터 합치기
df_rent1.columns=['district','station','date','count']
df_rent2.columns=['district','station','date','count']
df_rent = pd.concat([df_rent1, df_rent2])
print(df_rent.shape)
df_rent.head()
(18461, 4)
district | station | date | count | |
---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201906.0 | 3909.0 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201906.0 | 2432.0 |
2 | 강남구 | 2303. 논현역 7번출구 | 201906.0 | 1567.0 |
3 | 강남구 | 2304. 신영 ROYAL PALACE 앞 | 201906.0 | 559.0 |
4 | 강남구 | 2305. MCM 본사 직영점 앞 | 201906.0 | 730.0 |
df_return1.head()
대여소 그룹 | 대여소 명 | 반납 일자 / 월 | 반납 건수 | |
---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201906 | 4072 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201906 | 2382 |
2 | 강남구 | 2303. 논현역 7번출구 | 201906 | 1402 |
3 | 강남구 | 2304. 신영 ROYAL PALACE 앞 | 201906 | 207 |
4 | 강남구 | 2305. MCM 본사 직영점 앞 | 201906 | 905 |
df_return2.head()
구분 | 대여소명 | 반납일자 | 반납건수 | |
---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201812.0 | 437.0 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201812.0 | 556.0 |
2 | 강남구 | 2303. 논현역 7번출구 | 201812.0 | 273.0 |
3 | 강남구 | 2304. 신영 ROYAL PALACE 앞 | 201812.0 | 62.0 |
4 | 강남구 | 2305. MCM 본사 직영점 앞 | 201812.0 | 218.0 |
# 컬럼명 통일, 데이터 합치기
df_return1.columns = ['district', 'station', 'date', 'count']
df_return2.columns = ['district', 'station', 'date', 'count']
df_return = pd.concat([df_return1, df_return2])
# 제대로 합쳐졌는지 확인하기!
print(df_return1.shape, df_return2.shape)
print('총 레코드 수: {}'.format(df_return1.shape[0] + df_return2.shape[0]))
print(df_return.shape)
df_return.head()
(9273, 4) (9189, 4) 총 레코드 수: 18462 (18462, 4)
district | station | date | count | |
---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201906.0 | 4072.0 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201906.0 | 2382.0 |
2 | 강남구 | 2303. 논현역 7번출구 | 201906.0 | 1402.0 |
3 | 강남구 | 2304. 신영 ROYAL PALACE 앞 | 201906.0 | 207.0 |
4 | 강남구 | 2305. MCM 본사 직영점 앞 | 201906.0 | 905.0 |
df_bike = df_rent.merge(df_return[['station', 'date', 'count']],
how='left', on=['station', 'date'])
print(df_bike.shape)
df_bike.head()
(18485, 5)
district | station | date | count_x | count_y | |
---|---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201906.0 | 3909.0 | 4072.0 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201906.0 | 2432.0 | 2382.0 |
2 | 강남구 | 2303. 논현역 7번출구 | 201906.0 | 1567.0 | 1402.0 |
3 | 강남구 | 2304. 신영 ROYAL PALACE 앞 | 201906.0 | 559.0 | 207.0 |
4 | 강남구 | 2305. MCM 본사 직영점 앞 | 201906.0 | 730.0 | 905.0 |
df_bike.columns = ['district', 'station', 'date', 'rent', 'return']
df_bike.head()
district | station | date | rent | return | |
---|---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201906.0 | 3909.0 | 4072.0 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201906.0 | 2432.0 | 2382.0 |
2 | 강남구 | 2303. 논현역 7번출구 | 201906.0 | 1567.0 | 1402.0 |
3 | 강남구 | 2304. 신영 ROYAL PALACE 앞 | 201906.0 | 559.0 | 207.0 |
4 | 강남구 | 2305. MCM 본사 직영점 앞 | 201906.0 | 730.0 | 905.0 |
import missingno as msno
f, ax = plt.subplots(2, 1, figsize=(12, 12))
msno.bar(df_bike, ax=ax[0])
msno.bar(df_station, ax=ax[1])
<matplotlib.axes._subplots.AxesSubplot at 0x257a1f69848>
pd.set_option('display.max_rows', 30)
df_bike[df_bike['district'].isnull()]
district | station | date | rent | return | |
---|---|---|---|---|---|
10799 | NaN | NaN | NaN | NaN | NaN |
10800 | NaN | NaN | NaN | NaN | NaN |
10801 | NaN | NaN | NaN | NaN | NaN |
10802 | NaN | NaN | NaN | NaN | NaN |
10803 | NaN | NaN | NaN | NaN | NaN |
12332 | NaN | NaN | NaN | NaN | NaN |
12333 | NaN | NaN | NaN | NaN | NaN |
12334 | NaN | NaN | NaN | NaN | NaN |
12335 | NaN | NaN | NaN | NaN | NaN |
12336 | NaN | NaN | NaN | NaN | NaN |
13863 | NaN | NaN | NaN | NaN | NaN |
13864 | NaN | NaN | NaN | NaN | NaN |
13865 | NaN | NaN | NaN | NaN | NaN |
13866 | NaN | NaN | NaN | NaN | NaN |
13867 | NaN | NaN | NaN | NaN | NaN |
15404 | NaN | NaN | NaN | NaN | NaN |
15405 | NaN | NaN | NaN | NaN | NaN |
15406 | NaN | NaN | NaN | NaN | NaN |
15407 | NaN | NaN | NaN | NaN | NaN |
15408 | NaN | NaN | NaN | NaN | NaN |
16944 | NaN | NaN | NaN | NaN | NaN |
16945 | NaN | NaN | NaN | NaN | NaN |
16946 | NaN | NaN | NaN | NaN | NaN |
16947 | NaN | NaN | NaN | NaN | NaN |
16948 | NaN | NaN | NaN | NaN | NaN |
df_bike.dropna(inplace=True)
print(df_bike.shape)
df_bike.tail()
(18460, 5)
district | station | date | rent | return | |
---|---|---|---|---|---|
18480 | 중랑구 | 1455. 상봉역 2번 출구 | 201905.0 | 1362.0 | 1300.0 |
18481 | 중랑구 | 1456. 상아빌딩(우림시장 교차로) | 201905.0 | 826.0 | 867.0 |
18482 | 중랑구 | 1457. 동원사거리 | 201905.0 | 827.0 | 749.0 |
18483 | 중랑구 | 1458. 상봉터미널2 | 201905.0 | 1421.0 | 1492.0 |
18484 | 중랑구 | 1459. 용마한신아파트사거리 | 201905.0 | 447.0 | 320.0 |
df_bike.reset_index(drop=True, inplace=True)
df_bike.tail(3)
district | station | date | rent | return | |
---|---|---|---|---|---|
18457 | 중랑구 | 1457. 동원사거리 | 201905.0 | 827.0 | 749.0 |
18458 | 중랑구 | 1458. 상봉터미널2 | 201905.0 | 1421.0 | 1492.0 |
18459 | 중랑구 | 1459. 용마한신아파트사거리 | 201905.0 | 447.0 | 320.0 |
df_station.head()
대여소_구 | 대여소ID | 대여소명 | 대여소주소 | 위도 | 경도 | 기준시작일자 | 거치대수 | |
---|---|---|---|---|---|---|---|---|
0 | 마포구 | 101.0 | 101. (구)합정동 주민센터 | 서울특별시 마포구 동교로8길 58 | 37.549561 | 126.905754 | 2015-09-06 23:40:56 | 5 |
1 | 마포구 | 102.0 | 102. 망원역 1번출구 앞 | 서울특별시 마포구 월드컵로 72 | 37.555649 | 126.910629 | 2015-09-06 23:42:06 | 20 |
2 | 마포구 | 103.0 | 103. 망원역 2번출구 앞 | 서울특별시 마포구 월드컵로 79 | 37.554951 | 126.910835 | 2015-09-06 23:43:13 | 14 |
3 | 마포구 | 104.0 | 104. 합정역 1번출구 앞 | 서울특별시 마포구 양화로 59 | 37.550629 | 126.914986 | 2015-09-06 23:44:31 | 13 |
4 | 마포구 | 105.0 | 105. 합정역 5번출구 앞 | 서울특별시 마포구 양화로 48 | 37.550007 | 126.914825 | 2015-09-06 23:45:30 | 5 |
# 컬럼명 영어로 변경!
df_station.columns = ['district', 'id', 'station',
'address', 'lat', 'lng', 'date', 'count']
df_station.head(3)
district | id | station | address | lat | lng | date | count | |
---|---|---|---|---|---|---|---|---|
0 | 마포구 | 101.0 | 101. (구)합정동 주민센터 | 서울특별시 마포구 동교로8길 58 | 37.549561 | 126.905754 | 2015-09-06 23:40:56 | 5 |
1 | 마포구 | 102.0 | 102. 망원역 1번출구 앞 | 서울특별시 마포구 월드컵로 72 | 37.555649 | 126.910629 | 2015-09-06 23:42:06 | 20 |
2 | 마포구 | 103.0 | 103. 망원역 2번출구 앞 | 서울특별시 마포구 월드컵로 79 | 37.554951 | 126.910835 | 2015-09-06 23:43:13 | 14 |
df_bike.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 18460 entries, 0 to 18459 Data columns (total 5 columns): district 18460 non-null object station 18460 non-null object date 18460 non-null float64 rent 18460 non-null float64 return 18460 non-null float64 dtypes: float64(3), object(2) memory usage: 721.2+ KB
df_bike.head(3)
district | station | date | rent | return | |
---|---|---|---|---|---|
0 | 강남구 | 2301. 현대고등학교 건너편 | 201906.0 | 3909.0 | 4072.0 |
1 | 강남구 | 2302. 교보타워 버스정류장(신논현역 3번출구 후면) | 201906.0 | 2432.0 | 2382.0 |
2 | 강남구 | 2303. 논현역 7번출구 | 201906.0 | 1567.0 | 1402.0 |
import re
from tqdm import tqdm_notebook
p1 = re.compile('\d+')
p2 = re.compile('\d+[. ]')
error_row = []
for row in tqdm_notebook(df_bike.index):
try:
m = p1.match(df_bike.loc[row, 'station'])
df_bike.loc[row, 'id'] = m.group()
except:
df_bike.loc[row, 'id'] = 'None'
error_row.append(row) # 에러행 저장해놓기
try:
df_bike.loc[row, 'station'] = p2.sub('', df_bike.loc[row, 'station'])
except:
error_row.append(row) # 에러행 저장해놓기
HBox(children=(IntProgress(value=0, max=18460), HTML(value='')))
df_bike.head()
district | station | date | rent | return | id | |
---|---|---|---|---|---|---|
0 | 강남구 | 현대고등학교 건너편 | 201906.0 | 3909.0 | 4072.0 | 2301 |
1 | 강남구 | 교보타워 버스정류장(신논현역 3번출구 후면) | 201906.0 | 2432.0 | 2382.0 | 2302 |
2 | 강남구 | 논현역 7번출구 | 201906.0 | 1567.0 | 1402.0 | 2303 |
3 | 강남구 | 신영 ROYAL PALACE 앞 | 201906.0 | 559.0 | 207.0 | 2304 |
4 | 강남구 | MCM 본사 직영점 앞 | 201906.0 | 730.0 | 905.0 | 2305 |
print('에러행 수: {}개'.format(len(error_row)))
print('\n에러행의 대여소명: \n{}'.format(df_bike.loc[error_row,:].station.value_counts()))
df_bike.loc[error_row,:]
에러행 수: 25개 에러행의 대여소명: 대여소명 없음 11 중랑센터 6 상암센터 정비실 6 시스템관리팀 2 Name: station, dtype: int64
district | station | date | rent | return | id | |
---|---|---|---|---|---|---|
1381 | 정비센터 | 상암센터 정비실 | 201906.0 | 2.0 | 9.0 | None |
1382 | 정비센터 | 중랑센터 | 201906.0 | 36.0 | 24.0 | None |
1543 | 그룹명 없음 | 대여소명 없음 | 201907.0 | 0.0 | 1.0 | None |
1544 | 그룹명 없음 | 대여소명 없음 | 201907.0 | 0.0 | 12537.0 | None |
1545 | 그룹명 없음 | 대여소명 없음 | 201907.0 | 0.0 | 1.0 | None |
1546 | 그룹명 없음 | 대여소명 없음 | 201907.0 | 0.0 | 12537.0 | None |
2928 | 정비센터 | 상암센터 정비실 | 201907.0 | 1.0 | 11.0 | None |
2929 | 정비센터 | 중랑센터 | 201907.0 | 42.0 | 34.0 | None |
3090 | 그룹명 없음 | 대여소명 없음 | 201908.0 | 0.0 | 12188.0 | None |
4468 | 정비센터 | 상암센터 정비실 | 201908.0 | 4.0 | 13.0 | None |
4469 | 정비센터 | 시스템관리팀 | 201908.0 | 2.0 | 2.0 | None |
4470 | 정비센터 | 중랑센터 | 201908.0 | 36.0 | 28.0 | None |
4633 | 그룹명 없음 | 대여소명 없음 | 201909.0 | 0.0 | 10902.0 | None |
6015 | 정비센터 | 상암센터 정비실 | 201909.0 | 0.0 | 2.0 | None |
6016 | 정비센터 | 시스템관리팀 | 201909.0 | 1.0 | 1.0 | None |
6017 | 정비센터 | 중랑센터 | 201909.0 | 28.0 | 33.0 | None |
6180 | 그룹명 없음 | 대여소명 없음 | 201910.0 | 0.0 | 11726.0 | None |
6181 | 그룹명 없음 | 대여소명 없음 | 201910.0 | 0.0 | 1.0 | None |
6182 | 그룹명 없음 | 대여소명 없음 | 201910.0 | 0.0 | 11726.0 | None |
6183 | 그룹명 없음 | 대여소명 없음 | 201910.0 | 0.0 | 1.0 | None |
7567 | 정비센터 | 상암센터 정비실 | 201910.0 | 1.0 | 2.0 | None |
7568 | 정비센터 | 중랑센터 | 201910.0 | 25.0 | 31.0 | None |
7729 | 그룹명 없음 | 대여소명 없음 | 201911.0 | 0.0 | 8799.0 | None |
9113 | 정비센터 | 상암센터 정비실 | 201911.0 | 6.0 | 8.0 | None |
9114 | 정비센터 | 중랑센터 | 201911.0 | 9.0 | 30.0 | None |
df_bike.drop(error_row, inplace=True)
df_bike.reset_index(drop=True, inplace=True)
df_bike.drop(df_bike[df_bike.district=='정비센터'].index, axis=0, inplace=True)
df_station.head()
district | id | station | address | lat | lng | date | count | |
---|---|---|---|---|---|---|---|---|
0 | 마포구 | 101.0 | 101. (구)합정동 주민센터 | 서울특별시 마포구 동교로8길 58 | 37.549561 | 126.905754 | 2015-09-06 23:40:56 | 5 |
1 | 마포구 | 102.0 | 102. 망원역 1번출구 앞 | 서울특별시 마포구 월드컵로 72 | 37.555649 | 126.910629 | 2015-09-06 23:42:06 | 20 |
2 | 마포구 | 103.0 | 103. 망원역 2번출구 앞 | 서울특별시 마포구 월드컵로 79 | 37.554951 | 126.910835 | 2015-09-06 23:43:13 | 14 |
3 | 마포구 | 104.0 | 104. 합정역 1번출구 앞 | 서울특별시 마포구 양화로 59 | 37.550629 | 126.914986 | 2015-09-06 23:44:31 | 13 |
4 | 마포구 | 105.0 | 105. 합정역 5번출구 앞 | 서울특별시 마포구 양화로 48 | 37.550007 | 126.914825 | 2015-09-06 23:45:30 | 5 |
p = re.compile('\d+[. ]')
for row in df_station.index:
try:
df_station.loc[row, 'station'] = p2.sub('', df_station.loc[row, 'station'])
except:
print(row)
df_station.head()
district | id | station | address | lat | lng | date | count | |
---|---|---|---|---|---|---|---|---|
0 | 마포구 | 101.0 | (구)합정동 주민센터 | 서울특별시 마포구 동교로8길 58 | 37.549561 | 126.905754 | 2015-09-06 23:40:56 | 5 |
1 | 마포구 | 102.0 | 망원역 1번출구 앞 | 서울특별시 마포구 월드컵로 72 | 37.555649 | 126.910629 | 2015-09-06 23:42:06 | 20 |
2 | 마포구 | 103.0 | 망원역 2번출구 앞 | 서울특별시 마포구 월드컵로 79 | 37.554951 | 126.910835 | 2015-09-06 23:43:13 | 14 |
3 | 마포구 | 104.0 | 합정역 1번출구 앞 | 서울특별시 마포구 양화로 59 | 37.550629 | 126.914986 | 2015-09-06 23:44:31 | 13 |
4 | 마포구 | 105.0 | 합정역 5번출구 앞 | 서울특별시 마포구 양화로 48 | 37.550007 | 126.914825 | 2015-09-06 23:45:30 | 5 |
df_bike.head()
district | station | date | rent | return | id | |
---|---|---|---|---|---|---|
0 | 강남구 | 현대고등학교 건너편 | 201906.0 | 3909.0 | 4072.0 | 2301 |
1 | 강남구 | 교보타워 버스정류장(신논현역 3번출구 후면) | 201906.0 | 2432.0 | 2382.0 | 2302 |
2 | 강남구 | 논현역 7번출구 | 201906.0 | 1567.0 | 1402.0 | 2303 |
3 | 강남구 | 신영 ROYAL PALACE 앞 | 201906.0 | 559.0 | 207.0 | 2304 |
4 | 강남구 | MCM 본사 직영점 앞 | 201906.0 | 730.0 | 905.0 | 2305 |
df_bike.columns = ['district', 'station', 'date', 'rent', 'return', 'id']
df_bike.head()
district | station | date | rent | return | id | |
---|---|---|---|---|---|---|
0 | 강남구 | 현대고등학교 건너편 | 201906.0 | 3909.0 | 4072.0 | 2301 |
1 | 강남구 | 교보타워 버스정류장(신논현역 3번출구 후면) | 201906.0 | 2432.0 | 2382.0 | 2302 |
2 | 강남구 | 논현역 7번출구 | 201906.0 | 1567.0 | 1402.0 | 2303 |
3 | 강남구 | 신영 ROYAL PALACE 앞 | 201906.0 | 559.0 | 207.0 | 2304 |
4 | 강남구 | MCM 본사 직영점 앞 | 201906.0 | 730.0 | 905.0 | 2305 |
df_bike.info()
<class 'pandas.core.frame.DataFrame'> Int64Index: 18408 entries, 0 to 18434 Data columns (total 6 columns): district 18408 non-null object station 18408 non-null object date 18408 non-null float64 rent 18408 non-null float64 return 18408 non-null float64 id 18408 non-null object dtypes: float64(3), object(3) memory usage: 1006.7+ KB
df_bike['date'] = df_bike['date'] * 100 + 1 # date 내 월까지만 기재되있으므로 이를 모두 1일로 통일
df_bike['date'] = pd.to_datetime(df_bike['date'], format='%Y%m%d')
df_bike['return'] = df_bike['return'].astype('int')
df_bike['rent'] = df_bike['rent'].astype('int')
df_bike['id'] = df_bike['id'].astype('int')
df_bike.info()
<class 'pandas.core.frame.DataFrame'> Int64Index: 18408 entries, 0 to 18434 Data columns (total 6 columns): district 18408 non-null object station 18408 non-null object date 18408 non-null datetime64[ns] rent 18408 non-null int32 return 18408 non-null int32 id 18408 non-null int32 dtypes: datetime64[ns](1), int32(3), object(2) memory usage: 791.0+ KB
df_bike.head(3)
district | station | date | rent | return | id | |
---|---|---|---|---|---|---|
0 | 강남구 | 현대고등학교 건너편 | 2019-06-01 | 3909 | 4072 | 2301 |
1 | 강남구 | 교보타워 버스정류장(신논현역 3번출구 후면) | 2019-06-01 | 2432 | 2382 | 2302 |
2 | 강남구 | 논현역 7번출구 | 2019-06-01 | 1567 | 1402 | 2303 |
df_station.info()
<class 'pandas.core.frame.DataFrame'> Int64Index: 1540 entries, 0 to 1539 Data columns (total 8 columns): district 1540 non-null object id 1540 non-null float64 station 1540 non-null object address 1540 non-null object lat 1540 non-null float64 lng 1540 non-null float64 date 1540 non-null object count 1540 non-null int64 dtypes: float64(3), int64(1), object(4) memory usage: 148.3+ KB
df_station['id'] = df_station['id'].astype('int')
df_station['date'] = pd.to_datetime(df_station['date'])
df_station
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) D:\Program Files\Anaconda3\lib\site-packages\pandas\core\arrays\datetimes.py in objects_to_datetime64ns(data, dayfirst, yearfirst, utc, errors, require_iso8601, allow_object) 1978 try: -> 1979 values, tz_parsed = conversion.datetime_to_datetime64(data) 1980 # If tzaware, these values represent unix timestamps, so we pandas\_libs\tslibs\conversion.pyx in pandas._libs.tslibs.conversion.datetime_to_datetime64() TypeError: Unrecognized value type: <class 'str'> During handling of the above exception, another exception occurred: ValueError Traceback (most recent call last) <ipython-input-47-9855be6b4f14> in <module> 1 df_station['id'] = df_station['id'].astype('int') ----> 2 df_station['date'] = pd.to_datetime(df_station['date']) 3 df_station D:\Program Files\Anaconda3\lib\site-packages\pandas\util\_decorators.py in wrapper(*args, **kwargs) 206 else: 207 kwargs[new_arg_name] = new_arg_value --> 208 return func(*args, **kwargs) 209 210 return wrapper D:\Program Files\Anaconda3\lib\site-packages\pandas\core\tools\datetimes.py in to_datetime(arg, errors, dayfirst, yearfirst, utc, box, format, exact, unit, infer_datetime_format, origin, cache) 772 result = result.tz_localize(tz) 773 elif isinstance(arg, ABCSeries): --> 774 cache_array = _maybe_cache(arg, format, cache, convert_listlike) 775 if not cache_array.empty: 776 result = arg.map(cache_array) D:\Program Files\Anaconda3\lib\site-packages\pandas\core\tools\datetimes.py in _maybe_cache(arg, format, cache, convert_listlike) 154 unique_dates = unique(arg) 155 if len(unique_dates) < len(arg): --> 156 cache_dates = convert_listlike(unique_dates, True, format) 157 cache_array = Series(cache_dates, index=unique_dates) 158 return cache_array D:\Program Files\Anaconda3\lib\site-packages\pandas\core\tools\datetimes.py in _convert_listlike_datetimes(arg, box, format, name, tz, unit, errors, infer_datetime_format, dayfirst, yearfirst, exact) 461 errors=errors, 462 require_iso8601=require_iso8601, --> 463 allow_object=True, 464 ) 465 D:\Program Files\Anaconda3\lib\site-packages\pandas\core\arrays\datetimes.py in objects_to_datetime64ns(data, dayfirst, yearfirst, utc, errors, require_iso8601, allow_object) 1982 return values.view("i8"), tz_parsed 1983 except (ValueError, TypeError): -> 1984 raise e 1985 1986 if tz_parsed is not None: D:\Program Files\Anaconda3\lib\site-packages\pandas\core\arrays\datetimes.py in objects_to_datetime64ns(data, dayfirst, yearfirst, utc, errors, require_iso8601, allow_object) 1973 dayfirst=dayfirst, 1974 yearfirst=yearfirst, -> 1975 require_iso8601=require_iso8601, 1976 ) 1977 except ValueError as e: pandas\_libs\tslib.pyx in pandas._libs.tslib.array_to_datetime() pandas\_libs\tslib.pyx in pandas._libs.tslib.array_to_datetime() pandas\_libs\tslib.pyx in pandas._libs.tslib.array_to_datetime_object() pandas\_libs\tslib.pyx in pandas._libs.tslib.array_to_datetime_object() pandas\_libs\tslibs\parsing.pyx in pandas._libs.tslibs.parsing.parse_datetime_string() D:\Program Files\Anaconda3\lib\site-packages\dateutil\parser\_parser.py in parse(timestr, parserinfo, **kwargs) 1356 return parser(parserinfo).parse(timestr, **kwargs) 1357 else: -> 1358 return DEFAULTPARSER.parse(timestr, **kwargs) 1359 1360 D:\Program Files\Anaconda3\lib\site-packages\dateutil\parser\_parser.py in parse(self, timestr, default, ignoretz, tzinfos, **kwargs) 647 648 if res is None: --> 649 raise ValueError("Unknown string format:", timestr) 650 651 if len(res) == 0: ValueError: ('Unknown string format:', '2018.7.4개통')
# 개통이라는 단어가 포함되어있으면, 그 단어를 제외하여 저장
for row in df_station.index:
try:
if df_station.loc[row, 'date'][-2:] == '개통':
df_station.loc[row, 'date'] = df_station.loc[row, 'date'][:-2]
except:
pass
df_station['date'] = pd.to_datetime(df_station['date'])
df_station.head()
district | id | station | address | lat | lng | date | count | |
---|---|---|---|---|---|---|---|---|
0 | 마포구 | 101 | (구)합정동 주민센터 | 서울특별시 마포구 동교로8길 58 | 37.549561 | 126.905754 | 2015-09-06 23:40:56 | 5 |
1 | 마포구 | 102 | 망원역 1번출구 앞 | 서울특별시 마포구 월드컵로 72 | 37.555649 | 126.910629 | 2015-09-06 23:42:06 | 20 |
2 | 마포구 | 103 | 망원역 2번출구 앞 | 서울특별시 마포구 월드컵로 79 | 37.554951 | 126.910835 | 2015-09-06 23:43:13 | 14 |
3 | 마포구 | 104 | 합정역 1번출구 앞 | 서울특별시 마포구 양화로 59 | 37.550629 | 126.914986 | 2015-09-06 23:44:31 | 13 |
4 | 마포구 | 105 | 합정역 5번출구 앞 | 서울특별시 마포구 양화로 48 | 37.550007 | 126.914825 | 2015-09-06 23:45:30 | 5 |
df_station.info()
<class 'pandas.core.frame.DataFrame'> Int64Index: 1540 entries, 0 to 1539 Data columns (total 8 columns): district 1540 non-null object id 1540 non-null int32 station 1540 non-null object address 1540 non-null object lat 1540 non-null float64 lng 1540 non-null float64 date 1540 non-null datetime64[ns] count 1540 non-null int64 dtypes: datetime64[ns](1), float64(2), int32(1), int64(1), object(3) memory usage: 142.3+ KB
df_bike.head(3)
district | station | date | rent | return | id | |
---|---|---|---|---|---|---|
0 | 강남구 | 현대고등학교 건너편 | 2019-06-01 | 3909 | 4072 | 2301 |
1 | 강남구 | 교보타워 버스정류장(신논현역 3번출구 후면) | 2019-06-01 | 2432 | 2382 | 2302 |
2 | 강남구 | 논현역 7번출구 | 2019-06-01 | 1567 | 1402 | 2303 |
df_bike = df_bike[['district', 'id', 'station', 'date', 'rent', 'return']]
df_bike.head(3)
district | id | station | date | rent | return | |
---|---|---|---|---|---|---|
0 | 강남구 | 2301 | 현대고등학교 건너편 | 2019-06-01 | 3909 | 4072 |
1 | 강남구 | 2302 | 교보타워 버스정류장(신논현역 3번출구 후면) | 2019-06-01 | 2432 | 2382 |
2 | 강남구 | 2303 | 논현역 7번출구 | 2019-06-01 | 1567 | 1402 |
print(df_station['count'].value_counts().sort_index(ascending=False))
plt.figure(figsize=(12, 4))
plt.hist(df_station['count'], bins=15)
plt.xlim(0, 45)
plt.show()
40 5 39 1 35 3 30 12 27 1 26 2 25 8 23 1 22 1 21 3 20 199 19 6 18 6 17 5 16 9 15 283 14 14 13 28 12 47 11 11 10 714 9 37 8 87 7 37 6 5 5 15 Name: count, dtype: int64
mt35_station = df_station[df_station['count']>=35].sort_values('count', ascending=False).reset_index(drop=True)
mt35_station
district | id | station | address | lat | lng | date | count | |
---|---|---|---|---|---|---|---|---|
0 | 마포구 | 186 | 월드컵공원 | 서울특별시 마포구 하늘공원로 108-1 | 37.563965 | 126.898209 | 2016-07-06 12:00:00 | 40 |
1 | 영등포구 | 207 | 여의나루역 1번출구 앞 | 서울특별시 영등포구 여의동로 지하343 | 37.526989 | 126.932098 | 2015-09-17 15:33:18 | 40 |
2 | 마포구 | 420 | 서울시 공공자전거 상암센터 | 서울특별시 마포구 월드컵북로47길 10 | 37.566246 | 126.896179 | 2015-10-07 11:39:12 | 40 |
3 | 광진구 | 574 | 아차산역4번출구 | 서울특별시 광진구 능동로 216 | 37.551849 | 127.088982 | 2016-07-06 12:00:00 | 40 |
4 | 용산구 | 829 | 베르가모앞 | 서울특별시 용산구 한강대로 23 | 37.522930 | 126.961693 | 2017-11-28 11:57:57 | 40 |
5 | 광진구 | 3507 | 어린이회관 | 서울특별시 광진구 능동 465-7 | 37.545952 | 127.078003 | 2017-11-01 16:00:00 | 39 |
6 | 영등포구 | 206 | KBS 앞 | 서울특별시 영등포구 여의공원로 13 | 37.524666 | 126.918022 | 2015-09-17 15:09:17 | 35 |
7 | 영등포구 | 212 | 여의도역 1번출구 옆 | 서울특별시 영등포구 의사당대로 88 | 37.521362 | 126.923462 | 2015-09-17 15:12:54 | 35 |
8 | 중구 | 311 | 서울광장 옆 | 서울특별시 중구 세종대로 지하 101 | 37.566612 | 126.977470 | 2015-10-07 12:11:56 | 35 |
import folium
map = folium.Map([mt35_station.lat.median(), mt35_station.lng.median()], zoom_start=13)
for row in mt35_station.index:
folium.Marker([mt35_station.loc[row, 'lat'], mt35_station.loc[row, 'lng']]).add_to(map)
map
district_count = df_station.groupby('district').sum()
district_count.head()
id | lat | lng | count | |
---|---|---|---|---|
district | ||||
강남구 | 233051 | 3712.498423 | 12578.440221 | 1218 |
강동구 | 61258 | 2140.213577 | 7247.300705 | 763 |
강북구 | 59525 | 1467.706114 | 4953.973380 | 451 |
강서구 | 101004 | 3192.395109 | 10781.119844 | 1002 |
관악구 | 109301 | 1911.471931 | 6473.794822 | 640 |
import json
geo_data = json.load(open('source/Seoul_district_geo.json', encoding='utf-8'))
map = folium.Map([df_station['lat'].median(),
df_station['lng'].median()], zoom_start=11)
map.choropleth(geo_data=geo_data,
data=district_count['count'],
columns=[district_count.index, district_count['count']],
fill_color = 'YlGnBu', #PuRd, YlGnBu
key_on = 'feature.id')
map
df_station
district | id | station | address | lat | lng | date | count | |
---|---|---|---|---|---|---|---|---|
0 | 마포구 | 101 | (구)합정동 주민센터 | 서울특별시 마포구 동교로8길 58 | 37.549561 | 126.905754 | 2015-09-06 23:40:56 | 5 |
1 | 마포구 | 102 | 망원역 1번출구 앞 | 서울특별시 마포구 월드컵로 72 | 37.555649 | 126.910629 | 2015-09-06 23:42:06 | 20 |
2 | 마포구 | 103 | 망원역 2번출구 앞 | 서울특별시 마포구 월드컵로 79 | 37.554951 | 126.910835 | 2015-09-06 23:43:13 | 14 |
3 | 마포구 | 104 | 합정역 1번출구 앞 | 서울특별시 마포구 양화로 59 | 37.550629 | 126.914986 | 2015-09-06 23:44:31 | 13 |
4 | 마포구 | 105 | 합정역 5번출구 앞 | 서울특별시 마포구 양화로 48 | 37.550007 | 126.914825 | 2015-09-06 23:45:30 | 5 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
1535 | 종로구 | 464 | 삼청동 골목 | 종로구 팔판길 46 | 37.584190 | 126.981697 | 2019-08-16 00:00:00 | 10 |
1536 | 관악구 | 2185 | 대학동 고시촌 | 서울특별시 관악구 신림로 97 밀라트 | 37.470467 | 126.938652 | 2019-09-26 00:00:00 | 10 |
1537 | 서초구 | 2265 | 이수고가차도 남단 | 서울특별시 서초구 동작대로 204 청남빌딩 | 37.494743 | 126.983063 | 2017-08-09 11:16:28 | 10 |
1538 | 종로구 | 465 | 삼청공원 앞 | 서울특별시 종로구 삼청동 25-32 | 37.587605 | 126.983597 | 2019-11-20 00:00:00 | 5 |
1539 | 종로구 | 664 | 서울시립대 대학본부 | 동대문구 서울시립대로 163 서울시립대학교 | 37.584129 | 127.057938 | 2019-11-20 00:00:00 | 10 |
1540 rows × 8 columns
df_station.groupby('district').sum()['count'].sort_values(ascending=False).plot('bar', figsize=(12, 5))
<matplotlib.axes._subplots.AxesSubplot at 0x257a58f4708>
seongdong = df_station[df_station['district']=='성동구']
seongdong.reset_index(drop=True, inplace=True)
seongdong.head()
district | id | station | address | lat | lng | date | count | |
---|---|---|---|---|---|---|---|---|
0 | 성동구 | 506 | 금호 어울림 아파트 앞 | 서울특별시 성동구 광나루로 249 | 37.549061 | 127.057793 | 2015-10-07 11:50:10 | 7 |
1 | 성동구 | 507 | 성수아이에스비즈타워 앞 | 서울특별시 성동구 성수이로 147 | 37.548203 | 127.057114 | 2015-10-07 11:50:53 | 7 |
2 | 성동구 | 508 | 성수아카데미타워 앞 | 서울특별시 성동구 성수이로 118 | 37.545166 | 127.057510 | 2015-10-07 11:51:33 | 10 |
3 | 성동구 | 509 | 이마트 버스정류소 옆 | 서울특별시 성동구 뚝섬로 379 | 37.539654 | 127.052589 | 2015-10-07 11:52:07 | 20 |
4 | 성동구 | 510 | 서울숲 남문 버스정류소 옆 | 서울특별시 성동구 왕십리로11길 9 | 37.541222 | 127.043800 | 2015-10-07 11:55:30 | 10 |
seongdong.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 63 entries, 0 to 62 Data columns (total 8 columns): district 63 non-null object id 63 non-null int32 station 63 non-null object address 63 non-null object lat 63 non-null float64 lng 63 non-null float64 date 63 non-null datetime64[ns] count 63 non-null int64 dtypes: datetime64[ns](1), float64(2), int32(1), int64(1), object(3) memory usage: 3.8+ KB
from folium.plugins import HeatMap
from folium.plugins import MarkerCluster
# 성동구 맵 만들기
map = folium.Map([seongdong['lat'].median(),
seongdong['lng'].median()],
tiles='Stamen Watercolor', zoom_start=14)
# 클러스터링 생성
MarkerCluster(seongdong[['lat', 'lng']]).add_to(map)
# 히트맵 생성
HeatMap(seongdong[['lat', 'lng', 'count']]).add_to(map)
# 자전거 수가 많은 지역 10군데 표시
for row in seongdong.sort_values('count', ascending=False).index[:10]:
lat = seongdong.loc[row, 'lat']
lng = seongdong.loc[row, 'lng']
folium.Marker([lat, lng], icon=folium.Icon(color='black',icon="bicycle", prefix='fa')).add_to(map)
# 서울숲 근처 녹색 원 표시
folium.CircleMarker([37.544796, 127.039266], radius=90,
color='#008024', fill_color='#06EB51', fill_opacity=.2).add_to(map)
map
*히트맵: 어느 곳에 자전거수가 많은지 확인 가능
클러스터링(지도 내 숫자): 구역 당 대여소의 수를 확인 가능*
df_bike.head()
district | id | station | date | rent | return | |
---|---|---|---|---|---|---|
0 | 강남구 | 2301 | 현대고등학교 건너편 | 2019-06-01 | 3909 | 4072 |
1 | 강남구 | 2302 | 교보타워 버스정류장(신논현역 3번출구 후면) | 2019-06-01 | 2432 | 2382 |
2 | 강남구 | 2303 | 논현역 7번출구 | 2019-06-01 | 1567 | 1402 |
3 | 강남구 | 2304 | 신영 ROYAL PALACE 앞 | 2019-06-01 | 559 | 207 |
4 | 강남구 | 2305 | MCM 본사 직영점 앞 | 2019-06-01 | 730 | 905 |
df_bike.groupby('id').sum().merge(df_bike[['district', 'station', 'id']], on='id')
id | rent | return | district | station | |
---|---|---|---|---|---|
0 | 101 | 8552 | 8842 | 마포구 | (구)합정동 주민센터 |
1 | 101 | 8552 | 8842 | 마포구 | (구)합정동 주민센터 |
2 | 101 | 8552 | 8842 | 마포구 | (구)합정동 주민센터 |
3 | 101 | 8552 | 8842 | 마포구 | (구)합정동 주민센터 |
4 | 101 | 8552 | 8842 | 마포구 | (구)합정동 주민센터 |
... | ... | ... | ... | ... | ... |
18403 | 3542 | 15793 | 15533 | 광진구 | 래미안 구의파크 스위트 |
18404 | 3542 | 15793 | 15533 | 광진구 | 래미안 구의파크 스위트 |
18405 | 3542 | 15793 | 15533 | 광진구 | 래미안 구의파크 스위트 |
18406 | 9996 | 4 | 4 | 성동구 | 시설2 |
18407 | 9996 | 4 | 4 | 성동구 | 시설2 |
18408 rows × 5 columns
df_group = pd.merge(df_bike.groupby('id').sum(), df_bike[[
'id', 'district', 'station']].drop_duplicates(), on='id', how='left')
df_group = df_group[['id', 'district', 'station', 'rent', 'return']]
df_group.head()
id | district | station | rent | return | |
---|---|---|---|---|---|
0 | 101 | 마포구 | (구)합정동 주민센터 | 8552 | 8842 |
1 | 102 | 마포구 | 망원역 1번출구 앞 | 34333 | 32134 |
2 | 103 | 마포구 | 망원역 2번출구 앞 | 23096 | 22441 |
3 | 104 | 마포구 | 합정역 1번출구 앞 | 20665 | 18804 |
4 | 105 | 마포구 | 합정역 5번출구 앞 | 11085 | 9874 |
print(df_group.shape)
dup_index = df_group[df_group['id'].duplicated()].index
df_group.drop(dup_index, axis=0, inplace=True)
(1566, 5)
# 구역으로 groupby
sum_district = df_group.groupby('district').sum()[['rent', 'return']]
sum_district
rent | return | |
---|---|---|
district | ||
강남구 | 790737 | 732815 |
강동구 | 652896 | 671662 |
강북구 | 327191 | 328382 |
강서구 | 1128785 | 1146665 |
관악구 | 667287 | 666599 |
광진구 | 1169242 | 1161111 |
구로구 | 664399 | 662321 |
금천구 | 285370 | 281703 |
노원구 | 915608 | 915941 |
도봉구 | 306459 | 315583 |
동대문구 | 648020 | 658814 |
동작구 | 466406 | 476038 |
마포구 | 1323691 | 1328013 |
서대문구 | 560931 | 514052 |
서초구 | 836244 | 820487 |
성동구 | 881792 | 883816 |
성북구 | 604375 | 594378 |
송파구 | 1550841 | 1555244 |
양천구 | 537121 | 547477 |
영등포구 | 1521902 | 1504839 |
용산구 | 381281 | 381442 |
은평구 | 544344 | 565783 |
종로구 | 776034 | 738580 |
중구 | 444378 | 417963 |
중랑구 | 473049 | 490641 |
sum_district.sort_values('rent', ascending=False).head()
rent | return | |
---|---|---|
district | ||
송파구 | 1550841 | 1555244 |
영등포구 | 1521902 | 1504839 |
마포구 | 1323691 | 1328013 |
광진구 | 1169242 | 1161111 |
강서구 | 1128785 | 1146665 |
sum_district.sort_values('rent', ascending=False).tail()
rent | return | |
---|---|---|
district | ||
중구 | 444378 | 417963 |
용산구 | 381281 | 381442 |
강북구 | 327191 | 328382 |
도봉구 | 306459 | 315583 |
금천구 | 285370 | 281703 |
plt.figure(figsize=(7, 7))
sns.scatterplot('rent', 'return', s=100, alpha=.8, data=sum_district.sort_index())
plt.title('r={:.2f}'.format(sum_district['rent'].corr(sum_district['return'])))
Text(0.5, 1.0, 'r=1.00')
plt.figure(figsize=(7, 7))
sns.scatterplot('rent', 'return', data=df_group, alpha=.6)
plt.title('r={:.2f}'.format(df_group['rent'].corr(df_group['return'])))
Text(0.5, 1.0, 'r=0.99')
df_group['rent_return_ratio'] = df_group['rent'] / df_group['return']
df_group.head()
id | district | station | rent | return | rent_return_ratio | |
---|---|---|---|---|---|---|
0 | 101 | 마포구 | (구)합정동 주민센터 | 8552 | 8842 | 0.967202 |
1 | 102 | 마포구 | 망원역 1번출구 앞 | 34333 | 32134 | 1.068432 |
2 | 103 | 마포구 | 망원역 2번출구 앞 | 23096 | 22441 | 1.029188 |
3 | 104 | 마포구 | 합정역 1번출구 앞 | 20665 | 18804 | 1.098968 |
4 | 105 | 마포구 | 합정역 5번출구 앞 | 11085 | 9874 | 1.122645 |
df_group.sort_values('rent_return_ratio', ascending=False, inplace=True)
df_group.reset_index(drop=True, inplace=True)
df_group.tail()
id | district | station | rent | return | rent_return_ratio | |
---|---|---|---|---|---|---|
1551 | 1004 | 강동구 | 삼성광나루아파트 버스정류장 | 12288 | 16917 | 0.726370 |
1552 | 1146 | 강서구 | 곰달래사거리 | 8969 | 12373 | 0.724885 |
1553 | 2060 | 동작구 | 남성역3번출구 뒤 | 10945 | 15193 | 0.720398 |
1554 | 1444 | 중랑구 | 면목4치안센터 | 7161 | 10340 | 0.692553 |
1555 | 1141 | 강서구 | 곰달래 문화복지센터 1-1 | 11938 | 17377 | 0.687000 |
df_twotimes = df_group[df_group.rent_return_ratio >= 2]
df_twotimes
id | district | station | rent | return | rent_return_ratio | |
---|---|---|---|---|---|---|
0 | 434 | 중구 | 신당 래미안 버스정류장 | 2616 | 471 | 5.554140 |
1 | 167 | 서대문구 | 연가초등학교 옆 | 7075 | 1396 | 5.068052 |
2 | 2286 | 서초구 | 탑성마을입구 | 821 | 168 | 4.886905 |
3 | 3527 | 성동구 | 왕십리 자이아파트 | 1194 | 258 | 4.627907 |
4 | 1304 | 성북구 | 만해공원 | 3310 | 754 | 4.389920 |
... | ... | ... | ... | ... | ... | ... |
45 | 1545 | 강북구 | 솔샘역 2번 출구 | 3980 | 1935 | 2.056848 |
46 | 159 | 서대문구 | 이대역 4번 출구 | 6626 | 3248 | 2.040025 |
47 | 139 | 서대문구 | 연세대 정문 건너편 | 7836 | 3849 | 2.035853 |
48 | 572 | 광진구 | 국립정신 건강센터 앞 | 5500 | 2721 | 2.021316 |
49 | 2392 | 강남구 | 구룡산 입구 (구룡산 서울둘레길 입구) | 1457 | 721 | 2.020804 |
50 rows × 6 columns
df_twotimes['district'].value_counts().sort_values().plot('barh', figsize=(12, 6))
<matplotlib.axes._subplots.AxesSubplot at 0x257a1eafe48>
df_group.head()
id | district | station | rent | return | rent_return_ratio | |
---|---|---|---|---|---|---|
0 | 434 | 중구 | 신당 래미안 버스정류장 | 2616 | 471 | 5.554140 |
1 | 167 | 서대문구 | 연가초등학교 옆 | 7075 | 1396 | 5.068052 |
2 | 2286 | 서초구 | 탑성마을입구 | 821 | 168 | 4.886905 |
3 | 3527 | 성동구 | 왕십리 자이아파트 | 1194 | 258 | 4.627907 |
4 | 1304 | 성북구 | 만해공원 | 3310 | 754 | 4.389920 |
df_bike = df_group.merge(df_station[['id', 'lat', 'lng', 'count']], how='left', on='id')
df_bike.head()
id | district | station | rent | return | rent_return_ratio | lat | lng | count | |
---|---|---|---|---|---|---|---|---|---|
0 | 434 | 중구 | 신당 래미안 버스정류장 | 2616 | 471 | 5.554140 | 37.561489 | 127.023933 | 10.0 |
1 | 167 | 서대문구 | 연가초등학교 옆 | 7075 | 1396 | 5.068052 | 37.579460 | 126.917130 | 15.0 |
2 | 2286 | 서초구 | 탑성마을입구 | 821 | 168 | 4.886905 | 37.458549 | 127.055885 | 10.0 |
3 | 3527 | 성동구 | 왕십리 자이아파트 | 1194 | 258 | 4.627907 | 37.561790 | 127.024391 | 8.0 |
4 | 1304 | 성북구 | 만해공원 | 3310 | 754 | 4.389920 | 37.594402 | 126.992310 | 15.0 |
df_bike[df_bike['lat'].isnull()].head()
id | district | station | rent | return | rent_return_ratio | lat | lng | count | |
---|---|---|---|---|---|---|---|---|---|
12 | 1317 | 성북구 | 정릉동 교통광장 | 130 | 42 | 3.095238 | NaN | NaN | NaN |
44 | 2386 | 강남구 | sk 동우주유소 앞 | 189 | 91 | 2.076923 | NaN | NaN | NaN |
60 | 174 | 서대문구 | 명지대학교 학생회관 | 162 | 91 | 1.780220 | NaN | NaN | NaN |
141 | 172 | 서대문구 | 서대문소방서 | 2303 | 1681 | 1.370018 | NaN | NaN | NaN |
203 | 1687 | 마포구 | 서울월드컵경기장 테스트 | 20 | 16 | 1.250000 | NaN | NaN | NaN |
error_station = df_bike[df_bike['lat'].isnull()]['station'].unique()
error_station
array([' 정릉동 교통광장', ' sk 동우주유소 앞', ' 명지대학교 학생회관', ' 서대문소방서', ' 서울월드컵경기장 테스트', ' 더샵스타시티 C동 앞', ' 창동역공영주차장앞', ' 창천문화공원', ' 삼청동 주민센터', ' 난곡 사거리', ' 시설2', ' 서울역 5번출구 앞', ' 서울남부초등학교 옆', ' 정릉교회 앞', ' 남성역 2번출구 뒷편', ' 창동한신', ' 강일동 에너지 마루'], dtype=object)
# 구글에서 찾아서 직접 수치 입력하기
# googlemaps 라이브러리를 활용할 수도 있지만, 주소명이 정확하게 나와있지 않기 때문에 수기로 보정
row = df_bike[df_bike['station'] == error_station[0]].index
df_bike.loc[row, 'lat'] = 37.608491
df_bike.loc[row, 'lng'] = 127.006892
row = df_bike[df_bike['station'] == error_station[1]].index
df_bike.loc[row, 'lat'] = 37.509497
df_bike.loc[row, 'lng'] = 127.040466
row = df_bike[df_bike['station'] == error_station[2]].index
df_bike.loc[row, 'lat'] = 37.580213
df_bike.loc[row, 'lng'] = 126.923509
row = df_bike[df_bike['station'] == error_station[3]].index
df_bike.loc[row, 'lat'] = 37.5731167
df_bike.loc[row, 'lng'] = 126.9340639
row = df_bike[df_bike['station'] == error_station[4]].index
df_bike.loc[row, 'lat'] = 37.5682588
df_bike.loc[row, 'lng'] = 126.8950887
row = df_bike[df_bike['station'] == error_station[5]].index
df_bike.loc[row, 'lat'] = 37.5380488
df_bike.loc[row, 'lng'] = 127.0705414
row = df_bike[df_bike['station'] == error_station[6]].index
df_bike.loc[row, 'lat'] = 37.6544976
df_bike.loc[row, 'lng'] = 127.0474658
row = df_bike[df_bike['station'] == error_station[7]].index
df_bike.loc[row, 'lat'] = 37.5567852
df_bike.loc[row, 'lng'] = 126.933313
row = df_bike[df_bike['station'] == error_station[8]].index
df_bike.loc[row, 'lat'] = 37.5845386
df_bike.loc[row, 'lng'] = 126.979615
row = df_bike[df_bike['station'] == error_station[9]].index
df_bike.loc[row, 'lat'] = 37.481794
df_bike.loc[row, 'lng'] = 126.9123172
row = df_bike[df_bike['station'] == error_station[10]].index
df_bike.drop(row, axis=0, inplace=True)
row = df_bike[df_bike['station'] == error_station[11]].index
df_bike.loc[row, 'lat'] = 37.4817888
df_bike.loc[row, 'lng'] = 126.8794864
row = df_bike[df_bike['station'] == error_station[12]].index
df_bike.loc[row, 'lat'] = 37.4848216
df_bike.loc[row, 'lng'] = 126.9199275
row = df_bike[df_bike['station'] == error_station[13]].index
df_bike.loc[row, 'lat'] = 37.6053723
df_bike.loc[row, 'lng'] = 127.0106539
row = df_bike[df_bike['station'] == error_station[14]].index
df_bike.loc[row, 'lat'] = 37.4902357
df_bike.loc[row, 'lng'] = 126.9652447
row = df_bike[df_bike['station'] == error_station[15]].index
df_bike.loc[row, 'lat'] = 37.638916
df_bike.loc[row, 'lng'] = 127.0388004
row = df_bike[df_bike['station'] == error_station[16]].index
df_bike.loc[row, 'lat'] = 37.563288
df_bike.loc[row, 'lng'] = 127.174808
error_district = df_bike[df_bike['count'].isnull()]['district'].unique()
error_district
array(['성북구', '강남구', '서대문구', '마포구', '광진구', '도봉구', '종로구', '관악구', '중구', '동작구', '강동구'], dtype=object)
# count값이 없는 대여소의 count값을 해당 구의 평균값으로 대체
for dis in error_district:
mean_tmp = int(df_bike[df_bike.district==dis]['count'].mean())
df_bike.loc[df_bike.district==dis, 'count'] = mean_tmp
df_bike[df_bike['count'].isnull()].sum()
id 0.0 district 0.0 station 0.0 rent 0.0 return 0.0 rent_return_ratio 0.0 lat 0.0 lng 0.0 count 0.0 dtype: float64
# 서울 지도 그리기
map = folium.Map([df_bike.lat.median(), df_bike.lng.median()], zoom_start=12)
# 구별 대여량을 색으로 표현
map.choropleth(geo_data=geo_data,
data=df_bike.groupby('district').sum()['rent'],
columns=[df_bike.groupby('district').sum().index, df_bike.groupby('district').sum()['rent']],
fill_color='YlGnBu', # PuRd, YlGnBu
key_on='feature.id')
# 반납 대비 대여가 2.0 이상인 대여소 저장
df_twotimes = df_bike[df_bike.rent_return_ratio >= 2]
# 위에서 저장한 대여소를 클러스터로 표현
MarkerCluster(df_twotimes[['lat', 'lng']]).add_to(map)
# 가장 반납 대비 대여가 높은 대여소 10개는 자전거 모양으로 따로 마커 표시
for row in df_twotimes[:10].index:
lat = df_twotimes.lat[row]
lng = df_twotimes.lng[row]
folium.Marker([lat, lng], icon=folium.Icon(color='black',icon="bicycle", prefix='fa')).add_to(map)
map
*이 분석은 서울숲에서 쌍문동까지 따릉이를 타고갔을때,
'성수동엔 따릉이 대여소가 많은데 왜 쌍문동엔 별로 없을까?'라는 질문에서 시작됐다.*
끝!!