티스토리 뷰

1단원 서울시 구별 CCTV현황 분석 -3

출처 : 파이썬으로 데이터 주무르기 by 민형기

1단원 서울시 구별 CCTV현황 분석

    1. CCTV 현황과 인구 현황 데이터 구하기
    1. 파이썬에서 텍스트 파일과 엑셀 파일을 읽기 -pandas
    1. pandas 기초 익히기
    1. pandas를 이용해서 CCTV와 인구 현황 데이터 파악하기
    1. pandas 고급기능 - 두 DataFrame 병합하기
    1. CCTV 데이터와 인구 현황 데이터를 합치고 분석하기
    1. 파이썬의 대표 시각화 도구 - Matplotlib
    1. CCTV 현황 그래프로 분석하기

지난시간 정리
1. ~ 3.(https://jfun.tistory.com/210)
4. ~ 5.(https://jfun.tistory.com/211)

오늘은 1단원을 마쳐보도록 하겠다.

1-6 CCTV 데이터와 인구 현황 데이터를 합치고 분석하기

In [71]:
# merge를 사용하여 병합시켜 보자.
data_result = pd.merge(CCTV_Seoul, pop_Seoul, on='구별')
data_result.head()
Out[71]:
구별 소계 2013년도 이전 2014년 2015년 2016년 최근증가율 인구수 한국인 외국인 고령자 외국인비율 고령자비율
0 강남구 2780 1292 430 584 932 150.619195 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217
1 강동구 773 379 99 155 377 166.490765 453233.0 449019.0 4214.0 54622.0 0.929765 12.051638
2 강북구 748 369 120 138 204 125.203252 330192.0 326686.0 3506.0 54813.0 1.061806 16.600342
3 강서구 884 388 258 184 81 134.793814 603772.0 597248.0 6524.0 72548.0 1.080540 12.015794
4 관악구 1496 846 260 390 613 149.290780 525515.0 507203.0 18312.0 68082.0 3.484582 12.955291
In [72]:
# 의미 없는 컬럼을 del 명령어를 이용하여 지우도록 하자.
# 일반적으로 행을 삭제할때는 drop을 열을 삭제할때는 del을 사용한다.
del data_result['2013년도 이전']
del data_result['2014년']
del data_result['2015년']
del data_result['2016년']
data_result.head()
Out[72]:
구별 소계 최근증가율 인구수 한국인 외국인 고령자 외국인비율 고령자비율
0 강남구 2780 150.619195 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217
1 강동구 773 166.490765 453233.0 449019.0 4214.0 54622.0 0.929765 12.051638
2 강북구 748 125.203252 330192.0 326686.0 3506.0 54813.0 1.061806 16.600342
3 강서구 884 134.793814 603772.0 597248.0 6524.0 72548.0 1.080540 12.015794
4 관악구 1496 149.290780 525515.0 507203.0 18312.0 68082.0 3.484582 12.955291
In [73]:
# 그래프 그릴 것을 고려하여 index를 구로 고치자.
data_result.set_index('구별', inplace=True)
data_result.head()
Out[73]:
소계 최근증가율 인구수 한국인 외국인 고령자 외국인비율 고령자비율
구별
강남구 2780 150.619195 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217
강동구 773 166.490765 453233.0 449019.0 4214.0 54622.0 0.929765 12.051638
강북구 748 125.203252 330192.0 326686.0 3506.0 54813.0 1.061806 16.600342
강서구 884 134.793814 603772.0 597248.0 6524.0 72548.0 1.080540 12.015794
관악구 1496 149.290780 525515.0 507203.0 18312.0 68082.0 3.484582 12.955291

다양한 접근은 개인적으로 해보고, 고령자비율, 외국인비율, 인구수 중에서 무슨 데이터와 CCTV를 비교할지 정해보겠다. 그렇게 하는 가장 단순한 작업이 상관계수를 조사하는 것이다. 상관계수의 절대값이 클수록 두 데이터는 관계가 있다고 볼 수 있다.
먼저 numpy의 corrcoef명령어 를 사용하여 상관계수를 구해보고 상관계수가 가장 큰 값인 데이터를 비교하겠다.

In [75]:
np.corrcoef(data_result['고령자비율'], data_result['소계'])
Out[75]:
array([[ 1.        , -0.28078554],
       [-0.28078554,  1.        ]])

CCTV 개수와 고령자 비율은 약한 음의 상관관계임을 알 수 있다.

In [76]:
np.corrcoef(data_result['외국인비율'], data_result['소계'])
Out[76]:
array([[ 1.        , -0.13607433],
       [-0.13607433,  1.        ]])

외국인의 비율과는 큰 의미가 없다고 할 수 있다.

In [77]:
np.corrcoef(data_result['인구수'], data_result['소계'])
Out[77]:
array([[1.        , 0.30634228],
       [0.30634228, 1.        ]])

인구수와는 약한 상관관계가 있다고 볼 수 있다.
이김에 CCTV와 인구수의 관계를 좀 더 들여다보자.

In [79]:
data_result.sort_values(by='소계', ascending=False).head()
Out[79]:
소계 최근증가율 인구수 한국인 외국인 고령자 외국인비율 고령자비율
구별
강남구 2780 150.619195 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217
양천구 2034 34.671731 479978.0 475949.0 4029.0 52975.0 0.839413 11.036964
서초구 1930 63.371266 450310.0 445994.0 4316.0 51733.0 0.958451 11.488308
은평구 1873 85.237258 494388.0 489943.0 4445.0 72334.0 0.899091 14.631019
용산구 1624 53.216374 244203.0 229456.0 14747.0 36231.0 6.038828 14.836427
In [80]:
data_result.sort_values(by='인구수', ascending=False).head()
Out[80]:
소계 최근증가율 인구수 한국인 외국인 고령자 외국인비율 고령자비율
구별
송파구 618 104.347826 667483.0 660584.0 6899.0 72506.0 1.033584 10.862599
강서구 884 134.793814 603772.0 597248.0 6524.0 72548.0 1.080540 12.015794
강남구 2780 150.619195 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217
노원구 1265 188.929889 569384.0 565565.0 3819.0 71941.0 0.670725 12.634883
관악구 1496 149.290780 525515.0 507203.0 18312.0 68082.0 3.484582 12.955291

CCTV가 많이 설치된 구와 인구수가 많은 구를 시각적으로 비교해보자.

1-7 파이썬의 대표 시각화 도구 - Matplotlib

In [84]:
import matplotlib.pyplot as plt
%matplotlib inline  
# 그래프의 결과를 출력세션에 나타나게 한다.

plot

In [85]:
plt.figure
plt.plot([1,2,3,4,5,6,7,8,9,8,7,6,5,4,3,2,1,0])
plt.show()
In [86]:
import numpy as np
# 0부터 12까지 0.01 간격으로 데이터를 만든다. 
# 값을 하나만 가진 변수가 아니다. 약 1200개 정도의 값을 가진 일종의 배열이다.
t = np.arange(0, 12, 0.01) 
y = np.sin(t)
In [87]:
plt.figure(figsize=(10,6)) # 그림 크기
plt.plot(t,y) # t와 y에 관계의 그래프
plt.show()
In [88]:
plt.figure(figsize=(10,6))
plt.plot(t,y)
plt.grid()
plt.xlabel('time')
plt.ylabel('Amplitude')
plt.title('Example of sinewave')
plt.show()
In [89]:
# 명령을 두 개 넣어서 한 화면에 그래프를 두 개 만들자
# 범례(legend)를 추가해보자.
plt.figure(figsize=(10,6))
plt.plot(t, np.sin(t), label='sin')
plt.plot(t, np.cos(t), label='cos')
plt.grid()
plt.legend()
plt.xlabel('time')
plt.ylabel('Amplitude')
plt.title('Example of sinewave')
plt.show()
In [90]:
# lw로 선의 굵기를 조정할 수 있으며, color 옵션으로 색상을 지정할 수 있다.
plt.figure(figsize=(10,6))
plt.plot(t, np.sin(t), lw=3, label='sin')
plt.plot(t, np.cos(t), 'r', label='cos')
plt.grid()
plt.legend()
plt.xlabel('time')
plt.ylabel('Amplitude')
plt.title('Example of sinewave')
plt.show()
In [91]:
t=[0, 1, 2, 3, 4, 5, 6]
y=[1, 4, 5, 8, 9, 5, 3]
plt.figure(figsize=(10,6))
plt.plot(t, y, color='green')
plt.show()
In [92]:
# linestyle을 이용하여 선 스타일을 지정할 수 있다.
plt.figure(figsize=(10,6))
plt.plot(t, y, color='green', linestyle='dashed')
plt.show()
In [93]:
# marker 옵션으로 데이터가 존재하는 곳에 마킹할 수 있다.
plt.figure(figsize=(10,6))
plt.plot(t, y, color='green', linestyle='dashed', marker='o')
plt.show()
In [95]:
# markerfacecolor옵션을 이용하여 색을, markersize 옵션을 이용하여 크기를 지정할 수 있다.
plt.figure(figsize=(10,6))
plt.plot(t, y, color='green', linestyle='dashed', marker='o',
         markerfacecolor = 'blue', markersize=12)
plt.xlim([-0.5, 6.5])
plt.ylim([0.5, 9.5])
plt.show()

scatter

In [96]:
t=np.array([0,1,2,3,4,5,6,7,8,9])
y=np.array([9,8,7,9,8,3,2,4,3,4])
In [97]:
plt.figure(figsize=(10,6))
plt.scatter(t,y)
plt.show()
In [98]:
# marker를 지정해보자.
plt.figure(figsize=(10,6))
plt.scatter(t,y,marker='>')
plt.show()
In [100]:
# x축 값에 따라 색상을 바꾸는 clor map 지정
colormap = t

plt.figure(figsize=(10,6))
plt.scatter(t,y, s=50, c = colormap, marker='>')
plt.colorbar()
plt.show()

numpy 랜덤변수 함수

In [101]:
# 랜덤 변수 함수를 이용해서 데이터 3개를 만들자.
# loc : 평균값, scale : 표준편차
s1 = np.random.normal(loc=0, scale=1, size=1000)
s2 = np.random.normal(loc=5, scale=0.5, size=1000)
s3 = np.random.normal(loc=10, scale=2, size=1000)
In [102]:
plt.figure(figsize=(10,6))
plt.plot(s1, label='s1')
plt.plot(s2, label='s2')
plt.plot(s3, label='s3')
plt.legend()
plt.show()
In [103]:
# boxplot으로 표현해보자.
plt.figure(figsize=(10,6))
plt.boxplot((s1, s2, s3))
plt.grid()
plt.show()

1-8 CCTV 현황 그래프로 분석하기

In [105]:
# 한글 폰트 지원
import platform

from matplotlib import font_manager, rc
plt.rcParams['axes.unicode_minus']=False

if platform.system() == 'Darwin':
    rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
    path = 'c:/Windows/Fonts/malgun.ttf'
    font_name = font_manager.FontProperties(fname=path).get_name()
    rc('font', family=font_name)
else:
    print('Unkown system... sorry~~~~')
In [106]:
# 결과 변수 다시 확인
data_result.head()
Out[106]:
소계 최근증가율 인구수 한국인 외국인 고령자 외국인비율 고령자비율
구별
강남구 2780 150.619195 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217
강동구 773 166.490765 453233.0 449019.0 4214.0 54622.0 0.929765 12.051638
강북구 748 125.203252 330192.0 326686.0 3506.0 54813.0 1.061806 16.600342
강서구 884 134.793814 603772.0 597248.0 6524.0 72548.0 1.080540 12.015794
관악구 1496 149.290780 525515.0 507203.0 18312.0 68082.0 3.484582 12.955291
In [107]:
# pandas 데이터 뒤에 plot 명령어를 붙인다
# kind='barh' 수평bar 그래프.
data_result['소계'].plot(kind='barh', grid=True, figsize=(10,10))
plt.show()
In [108]:
# 위 그림은 큰 의미를 찾기 어렵다. 정렬을 통해 좀 더 보기 좋게 바꿔보자.
data_result['소계'].sort_values().plot(kind='barh', grid=True, figsize=(10,10))

plt.show()

CCTV의 개수가 강남구가 월등히 많다는 것을 알 수 있다. 뒤를 이어 양천구, 서초구, 은평구가 꽤 많은 CCTV가 설치되어 있다. 그리고 하위 그룹이 얼마나 적은 수의 CCTV를 가지고 있는지도 확인할 수 있다.

In [109]:
# 인구 대비 CCTV 비율을 계산해서 정렬하고 그려보자.
data_result['CCTV비율'] = data_result['소계'] / data_result['인구수'] *100
data_result['CCTV비율'].sort_values().plot(kind='barh', grid=True, figsize=(10,10))

plt.show()

인구대비 CCTV 수를 보니 이번에는 용산구와 종로구가 월등히 높다. 그런데 송파구는 인구 대비로 봐도 CCTV 비율이 낮다.
조금 더 나아가 scatter 함수를 사용하여 보자.

In [110]:
# 마커 s =50
plt.figure(figsize=(6,6))
plt.scatter(data_result['인구수'], data_result['소계'], s = 50)
plt.xlabel('인구수')
plt.ylabel('CCTV')
plt.grid()
plt.show()
In [111]:
# 위 그래프를 대표하는 직선을 하나 그려보자. 
#아까 CCTV와 인구수는 양의 상관관계가 있다는 것을 보였었다.

#numpy의 polyfit 명령으로 손쉽게 직선을 만들 수 있다.

fp1 = np.polyfit(data_result['인구수'], data_result['소계'], 1)
fp1
Out[111]:
array([1.30916415e-03, 6.45066497e+02])
In [112]:
f1 = np.poly1d(fp1)                       # y축 데이터
fx = np.linspace(100000, 700000, 100)     # x축 데이터
In [113]:
plt.figure(figsize=(10,10))
plt.scatter(data_result['인구수'], data_result['소계'], s=50)
plt.plot(fx, f1(fx), ls='dashed', lw=3, color='g')
plt.xlabel('인구수')
plt.ylabel('CCTV')
plt.grid()
plt.show()

여기에 두 가지 방법을 넣고 싶다.
하나는 직선이 이 전체 데이터의 대표 값 역할을 한다면

  • 이 경향성에서 멀이 있는 구는 이름을 나타나도록 하고 싶다는 것
  • 직선에서 멀어질수록 다른 색을 내타내는 것
In [115]:
# 오차를 계산할 수 있는 코드를 만들고 오차가 큰 순으로 데이터를 정렬해서 다시 저장하자.
fp1 = np.polyfit(data_result['인구수'], data_result['소계'], 1)

f1 = np.poly1d(fp1)
fx = np.linspace(100000, 700000, 100)

data_result['오차'] = np.abs(data_result['소계'] - f1(data_result['인구수']))
                           
df_sort = data_result.sort_values(by='오차', ascending=False)
df_sort.head()
Out[115]:
소계 최근증가율 인구수 한국인 외국인 고령자 외국인비율 고령자비율 CCTV비율 오차
구별
강남구 2780 150.619195 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217 0.487292 1388.055355
송파구 618 104.347826 667483.0 660584.0 6899.0 72506.0 1.033584 10.862599 0.092587 900.911312
양천구 2034 34.671731 479978.0 475949.0 4029.0 52975.0 0.839413 11.036964 0.423769 760.563512
서초구 1930 63.371266 450310.0 445994.0 4316.0 51733.0 0.958451 11.488308 0.428594 695.403794
용산구 1624 53.216374 244203.0 229456.0 14747.0 36231.0 6.038828 14.836427 0.665020 659.231690
In [116]:
# 이제 텍스트와 colormap을 입히자.
plt.figure(figsize=(14, 10))
plt.scatter(data_result['인구수'], data_result['소계'],
            c=data_result['오차'], s=50)
plt.plot(fx, f1(fx), ls='dashed', lw=3, color='g')

for n in range(10):
    plt.text(df_sort['인구수'][n]*1.02, df_sort['소계'][n]*0.98,
            df_sort.index[n], fontsize=15)

plt.xlabel('인구수')
plt.ylabel('인구당비율')

plt.colorbar()
plt.grid()
plt.show()

직선을 기준으로 위에 있는 '강남구', '양천구', '서초구', '은평구', '용산구는 서울시 전체 지역의 일반적인 경향보다 CCTV가 많이 설치된 지역이다.
직선을 기준으로 아래 있는 '송파구', '강서구', '중랑구', '마포구', '도봉구'는 서울시 전체 지역의 일반적인 경향보다 CCTV가 적게 설치된 지역이다.
특히 강남구는 월등히 많은 CCTV가 설치되어 있지만, 송파구는 너무나도 적은 수의 CCTV를 가지고 있다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함