본문 바로가기

데이터 분석/Python

[데이터 분석] 따릉이가 가장 많은 동네는 어디일까?

따릉이 데이터로 가장 많은 대여소가 있는 지역은 어디인지,

따릉이를 가장 많이 소유하고 있는 지역은 어디인지 알아보자!

 

1. 라이브러리 및 한글 폰트 설정

import pandas as pd
import seaborn as sns

 

import matplotlib
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
font_name = fm.FontProperties(fname = '../NanumBarunGothic.ttf').get_name()
matplotlib.rc('font', family = font_name)
matplotlib.rcParams['axes.unicode_minus'] = False

 

2. 데이터

http://data.seoul.go.kr/dataList/OA-13252/F/1/datasetView.do

 

  • 위에 공공데이터 포털에서 따릉이 데이터를 가져왔다. 
bike_06 = pd.read_csv('data/공공자전거 대여소 정보(21.06월 기준)_1행수정.csv', encoding='cp949')
bike_06

 

 

3. 결측치 확인 및 채우기

bike_06.info()

 

 

  • row = 2467, column = 10
  • LCD, QR 컬럼에 NULL값이 존재한다.
  • 이 데이터에는 각 대여소에 LCD 따릉이와 QR 따릉이가 없으면 NULL값으로 되어있으므로
  • NULL값을 0으로 채웠다. 
bike_06.fillna(0, inplace=True)
bike_06['LCD'] = bike_06['LCD'].astype(int) # 데이터 타입 변환
bike_06['QR'] = bike_06['QR'].astype(int)
bike_06.info()

 

 

  • LCD, QR 컬럼의 NULL값에 0으로 채우고 float 타입을 int 타입으로 변환해주었다.

4. 자치구별 따릉이 대여소 수

bike_06['자치구'].value_counts()

 

 

  • DataFrame.value_counts()를 이용하여 자치구별 대여소 개수를 알아보면 위와 같다.
Seoul_gu = pd.value_counts(bike_06['자치구'].values, sort = True).head(10)
x = Seoul_gu.plot.bar(grid = True, figsize = (10,8), fontsize = 15, color = '#1BCF1C')
plt.title('<자치구별 따릉이 대여 장소 수>', fontsize = 20)
plt.xlabel('자치구', fontsize = 15)
plt.ylabel('Count', fontsize = 15)
plt.xticks(rotation=0)
plt.annotate('최댓값', xy = (0,184), xytext = (0,160), 
             fontsize = 14, ha = 'center', color ='red',
             bbox=dict(boxstyle='square', color='yellow'), # 상자안에 글자
             arrowprops =  dict(facecolor='black', width = 1, headwidth=10))
# (문자, xy = 화살표 방향, xytext = 문자, 화살표 위치, arrowprops = 화살표 성격)
for p in x.patches: # bar에 수치 표현
    left, bottom, width, height = p.get_bbox().bounds
    plt.annotate(f"{int(height)}",(left+width/2, height+3), ha = 'center', size =14, color = 'black')
plt.show()

 

 

  • Seoul_gu는 자치구별 따릉이 대여소 수 중 Top10을 의미한다.
  • 그래프는 plot.bar()를 이용하여 간단하게 그리고 plt.xticks(rotation = 0)을 통해 x축 눈금 레이블을 수정했다.
  • plt.annotation()을 통해 최댓값을 표시해주었다. 
    • plt.annotation(문자, xy = 화살표 방향, xytext = 문자, 화살표 위치, arrowprops = 화살표 성격, 그 외 설정값)
  • for문을 통해 각 막대에 수치를 표현해주었다.
  • 자치구별로 보면 송파구, 강서구, 강남구가 가장 많은 따릉이 대여소를 가지고 있다.

5. 총 따릉이 수 컬럼 추가

bike_06['총 따릉이 수'] = bike_06['LCD'] + bike_06['QR']
bike_06.iloc[417:427]

 

 

  • 총 따릉이 수 = LCD + QR
  • 총 따릉이 수 컬럼을 추가하면 위와 같은 결과가 나온다.

6. 자치구별 총 따릉이 수 비교

bike_06_total = bike_06.groupby(bike_06['자치구'])[['총 따릉이 수']].sum().sort_values(by='총 따릉이 수' ,ascending=False)
bike_06_total_top10 = bike_06_total.head(n=10)
bike_06_total_top10

 

x = bike_06_total_top10.plot.bar(grid = True, figsize = (10, 8), fontsize = 15, color = '#1BCF1C')
plt.xticks(rotation = 0)
plt.title('<자치구별 총 따릉이 수>', fontsize = 20)
plt.xlabel('자치구', fontsize = 15)
plt.ylabel('Count', fontsize = 15)
for p in x.patches: # bar에 수치 표현
    left, bottom, width, height = p.get_bbox().bounds
    plt.annotate(f"{int(height)}",(left+width/2, height+10), ha = 'center', size =14, color = 'black')
plt.show()

 

 

  • 송파구가 자치구별로 가장 따릉이 대여소가 많은 만큼 따릉이 수도 많다는 것을 확인할 수 있다.
  • 따릉이 대여소 Top3에는 송파구, 강서구, 강남구 이였으나
  • 따릉이 수 Top3에는 송파구, 강서구, 서초구를 나타낸다.

7. 자치구별 LCD, QR 따릉이수

7-1. LCD, QR 비교설명

  • 기존 LCD방식
  • 신규 QR방식
  • 따릉이 타입에 따라 두가지 대여소가 있다.
  • 신규 QR방식 따릉이는 모든 대여소에서 대여와 반납이 가능하다.
  • 기존 LCD방식 따릉이는 신규 QR방식 따릉이 대여소에 반납이 불가능하여 기존 대여소에서만 사용가능하다.
  • 기존 LCD방식 따릉이는 대여번호 입력 -> 단말기 우측 잠금장치 분리
  • 신규 QR방식 따릉이는 QR코드 스캔 -> 잠금 해제
  • 2022년까지 'QR형 뉴따릉이'로 100% 교체될 예정이라고 한다.

7-2. 자치구별 LCD, QR 따릉이 수 비교 (groupby)

bike_06_type = bike_06.groupby(['자치구'])[['LCD', 'QR']].sum()
bike_06_type_top10 = bike_06_type.sort_values(by='LCD', ascending=False).head(n=10)
bike_06_type_top10

 

 

  • groupby를 사용하여 자치구별 LCD, QR의 따릉이 수를 나타내면 위와 같다.

7-3. 각 자치구별 운영방식에 따른 따릉이 수

bike_06_type_top10.plot.bar(grid = True, figsize = (10, 8), fontsize = 15, color = ['#1BCF1C', '#FEC32D'])
plt.xticks(rotation = 0)
plt.title('<각 자치구별 운영방식에 따른 따릉이 수>', fontsize = 20)
plt.xlabel('자치구', fontsize = 15)
plt.ylabel('Count', fontsize = 15)
plt.annotate('기존 LCD 방식 최댓값', xy = (0.7,1252), xytext = (0.7,1252), 
             fontsize = 14, ha = 'center', color ='red',
             bbox=dict(boxstyle='square', color='yellow')) # 상자안에 글자
plt.annotate('신규 QR 방식 최댓값', xy = (5,1196), xytext = (5,1196), 
             fontsize = 14, ha = 'center', color ='red',
             bbox=dict(boxstyle='square', color='yellow'), # 상자안에 글자
             arrowprops =  dict(facecolor='black', width = 1, headwidth=10))
# (문자, xy = 화살표 방향, xytext = 문자, 화살표 위치, arrowprops = 화살표 성격)

 

 

  • 강서구가 신형 QR방식의 따릉이를 많이 보유하고 있고
  • 그 다음으로 따릉이 수, 대여장소 수를 가장 많이 보유하고 있는 송파구가 그 뒤를 잇고 있다.
  • 물론 기존 LCD방식의 따릉이는 송파구가 가장 많이 보유하고 있다.

8. 따릉이 보관소(대여소)명 분석

bike_06['보관소(대여소)명'].value_counts()

 

 

  • bike_06 데이터프레임에서 보관소(대여소)명 빈도를 살펴보기엔 종류가 너무 많아 따로 태깅작업을 하였다.

8-1. 태깅작업

bike_06_copy = bike_06.copy() # 데이터프레임 복사
bike_06_copy['보관소'] = 0
for i in range(len(bike_06_copy['보관소(대여소)명'])):
    if '정류' in bike_06_copy['보관소(대여소)명'].iloc[i]:
        bike_06_copy['보관소'].iloc[i]= '정류장'
    elif ('역' in bike_06_copy['보관소(대여소)명'].iloc[i]) or ('출구' in bike_06_copy['보관소(대여소)명'].iloc[i]):
        bike_06_copy['보관소'].iloc[i]= '지하철역'
    elif '초등학교' in bike_06_copy['보관소(대여소)명'].iloc[i]:
        bike_06_copy['보관소'].iloc[i]= '초등학교'
    elif '중학교' in bike_06_copy['보관소(대여소)명'].iloc[i]:
        bike_06_copy['보관소'].iloc[i]= '중학교'
    elif '고등학교' in bike_06_copy['보관소(대여소)명'].iloc[i]:
        bike_06_copy['보관소'].iloc[i]= '고등학교'
    elif '대학교' in bike_06_copy['보관소(대여소)명'].iloc[i]:
        bike_06_copy['보관소'].iloc[i]= '대학교'
    elif ('아파트' in bike_06_copy['보관소(대여소)명'].iloc[i]) or ('단지' in bike_06_copy['보관소(대여소)명'].iloc[i]) or ('편한세상' in bike_06_copy['보관소(대여소)명'].iloc[i]):
        bike_06_copy['보관소'].iloc[i]= '아파트앞'
    elif '공원' in bike_06_copy['보관소(대여소)명'].iloc[i]:
        bike_06_copy['보관소'].iloc[i]= '공원'
    elif '주민센터' in bike_06_copy['보관소(대여소)명'].iloc[i]:
        bike_06_copy['보관소'].iloc[i]= '주민센터'
    elif ('은행' in bike_06_copy['보관소(대여소)명'].iloc[i]) or ('금융' in bike_06_copy['보관소(대여소)명'].iloc[i]) or ('농협' in bike_06_copy['보관소(대여소)명'].iloc[i]):
        bike_06_copy['보관소'].iloc[i]= '은행'
    elif '병원' in bike_06_copy['보관소(대여소)명'].iloc[i]:
        bike_06_copy['보관소'].iloc[i]= '병원'
    elif ('타워' in bike_06_copy['보관소(대여소)명'].iloc[i]) or ('빌딩' in bike_06_copy['보관소(대여소)명'].iloc[i]):
        bike_06_copy['보관소'].iloc[i]= '빌딩/타워'
    elif ('박물관' in bike_06_copy['보관소(대여소)명'].iloc[i]) or ('전시관' in bike_06_copy['보관소(대여소)명'].iloc[i]):
        bike_06_copy['보관소'].iloc[i]= '박물관/전시관'
    elif '구청' in bike_06_copy['보관소(대여소)명'].iloc[i]:
        bike_06_copy['보관소'].iloc[i]= '구청'
    else:
        bike_06_copy['보관소'].iloc[i]= '기타'
bike_06_copy.to_csv('bike_06_copy.csv', index = False, encoding='cp949')
  • '보관소' 컬럼 추가하여 태깅작업을 하였다.
  • 위에 코드로 하기에는 정리가 부족하여 csv 파일 다운받아서 수기로 정리하였다.
  • 예를 들어, 보관소(대여소)명 컬럼에 '역'으로 되어있는 데이터는 지하철역으로 변경하라는 코드에 '역촌점', '역촌', '역촌역' 등 지역이름에 '역'이 들어간 경우가 있었다.
bike_06_copy_1 = pd.read_csv('data/bike_06_copy_1.csv', encoding='cp949')
bike_06_copy_1

 

 

8-2. 보관소 컬럼 데이터 빈도 확인

bike_06_copy_1['보관소'].value_counts()

 

bike_06_copy_1[bike_06_copy_1['보관소'] == '기타'][['보관소(대여소)명']]

 

 

  • 기타에는 위와 같이 oo사거리, 기업빌딩 앞 등 너무 다양해서 분류하지 큰 덩어리만 분류하였다.

8-3. 따릉이 대여소가 가장 많았던 Top1 송파구의 대여소는 어디가 가장 많을까?

bike_06_copy_1_songpa = bike_06_copy_1[bike_06_copy_1['자치구']=='송파구']['보관소'].value_counts()
bike_06_copy_1_songpa

 

 

colors = sns.color_palette('hls',len(bike_06_copy_1_songpa.index))
x = bike_06_copy_1_songpa.plot.bar(grid = True, figsize = (15,8), fontsize = 15, color = colors)
plt.xticks(rotation = 20)
plt.title('<송파구 따릉이 대여소 위치>', fontsize = 20)
plt.xlabel('대여소', fontsize = 15)
plt.ylabel('Count', fontsize = 15)
for p in x.patches:
    left, bottom, width, height = p.get_bbox().bounds
    plt.annotate(f'{int(height)}', (left+width/2, height+1), ha = 'center', size = 14, color = 'black')
plt.show()

 

 

  • 송파구는 기타를 제외하면 지하철역과 아파트앞이 비슷한 수치로 가장 많다.

8-4. 따릉이 대여소가 가장 많았던 Top2 강서구의 대여소는 어디가 가장 많을까?

bike_06_copy_gangseo = bike_06_copy_1[bike_06_copy_1['자치구'] == '강서구']['보관소'].value_counts().head(n=10)
bike_06_copy_gangseo

 

 

colors = sns.color_palette('hls',len(bike_06_copy_gangseo.index))
x = bike_06_copy_gangseo.plot.bar(grid = True, figsize = (10, 8), fontsize = 15, color = colors)
plt.xticks(rotation = 20)
plt.title('<강서구 따릉이 대여소 위치>', fontsize = 20)
plt.xlabel('대여소', fontsize = 15)
plt.ylabel('Count', fontsize = 15)
for p in x.patches:
    left, bottom, width, height = p.get_bbox().bounds
    plt.annotate(f'{int(height)}', (left+width/2, height+1), ha = 'center', size = 14, color = 'black')
plt.show()

 

 

  • 강서구는 기타를 제외하면 과 아파트앞과 지하철역이 비슷한 수치로 가장 많지만 송파구와 비교했을 때 지하철역보다 아파트앞에 대여소가 2개 더 많다.

8-5. 따릉이 대여소가 가장 많았던 Top3 강남구의 대여소는 어디가 가장 많을까?

bike_06_copy_gangnam = bike_06_copy_1[bike_06_copy_1['자치구'] == '강남구']['보관소'].value_counts()
bike_06_copy_gangnam

 

 

colors = sns.color_palette('hls', len(bike_06_copy_gangseo.index))
x = bike_06_copy_gangnam.plot.bar(grid = True, figsize = (12, 8), fontsize = 15, color = colors)
plt.xticks(rotation = 20)
plt.title('<강남구 따릉이 대여소 위치>', fontsize = 20)
plt.xlabel('대여소', fontsize = 15)
plt.ylabel('Count', fontsize = 15)
for p in x.patches:
    left, bottom, width, height = p.get_bbox().bounds
    plt.annotate(f'{int(height)}', (left+width/2, height+1), ha = 'center', size = 14, color = 'black')
plt.show()

 

 

  • 강남구는 지하철역에 가장 많은 대여소가 있으며 top1, top2와 다르게 아파트앞의 대여소 개수는 지하철역의 대여소 개수의 1/3정도 밖에 되지 않는다. 

9. 서울특별시 자치구별 인구 수 비교

https://data.seoul.go.kr/dataList/419/S/2/datasetView.do

 

seoul_population = pd.read_excel('/content/서울특별시_자치구별_인구수_2021.2분기.xlsx', 
                                 names = ['SIG_KOR_NM', 'POPULATION'])
seoul_population = seoul_population.sort_values(by = 'POPULATION', ascending = False)
seoul_population.head(n=10)

 

 

  • 공공데이터 포털에서 서울특별시 자치구별 인구수 데이터를 다운받아 자치구와 인구수 컬럼만 따로 떼어냈다.

9-1. 지도에 표현하기

9-1-1. geopandas 설치 및 데이터 가져오기

pip install geopandas
import geopandas as gpd
file_path = 'https://raw.githubusercontent.com/southkorea/seoul-maps/master/juso/2015/json/seoul_municipalities_geo_simple.json'
seoul=gpd.read_file(file_path)
seoul.head()

 

 

  • 위에 seoul 데이터는 서울특별시 자치구별 경도와 위도가 있는 데이터이다.

9-1-2. 데이터 merge

seoul_population_merge = pd.merge(left=seoul, right = seoul_population, on='SIG_KOR_NM')
seoul_population_merge.head(n=10)

 

 

  • 자치구별 인구수 데이터(seoul_population)와 위도와 경도가 있는 데이터(seoul)를 merge하여 seoul_population_merge 데이터프레임에 저장한다.

9-1-3. 지도 시각화

final_pic=seoul_population_merge.plot(figsize=(18,15),linewidth=0.25, edgecolor='black', column='POPULATION',cmap='YlGn')
enter = '\n' # F-string 문법에서는 \를 사용할 수 없기때문에 변수에 \n을 저장한 후 사용
for index,row in seoul_population_merge.iterrows():
    xy=row['geometry'].centroid.coords[:]
    xytext=row['geometry'].centroid.coords[:]
    if (index == 19) or (index == 15) or (index == 10):
      plt.annotate(f"{row['SIG_KOR_NM']}{enter}{row['POPULATION']}",xy=xy[0], xytext=xytext[0],  horizontalalignment='center',verticalalignment='center',color='yellow', size=13)
    else:
      plt.annotate(f"{row['SIG_KOR_NM']}{enter}{row['POPULATION']}",xy=xy[0], xytext=xytext[0],  horizontalalignment='center',verticalalignment='center',color='black', size=13)
    plt.axis('off')
plt.show()

 

 

  • 인구수를 확인해보니 대여소가 많은 지역인 송파구와 강서구가 인구도 가장 많은 것을 알 수 있다...!