Python

서울특별시 구별 CCTV 현황 분석

이부일 2018. 2. 10. 22:14

01서울시 구별 CCTV 현황 분석.ipynb


[출처] 파이썬으로 데이터 주무르기, 민형기 지음, BJPublic, p23 ~ 72

In [70]:
# 패키지 로딩하기
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import font_manager, rc
%matplotlib inline
In [3]:
# csv 데이터 불러오기
cctv_seoul = pd.read_csv("01. CCTV_in_Seoul.csv", encoding = "UTF-8")
In [5]:
# 데이터의 일부 보기
cctv_seoul.head()
Out[5]:
기관명 소계 2013년도 이전 2014년 2015년 2016년
0 강남구 2780 1292 430 584 932
1 강동구 773 379 99 155 377
2 강북구 748 369 120 138 204
3 강서구 884 388 258 184 81
4 관악구 1496 846 260 390 613
In [6]:
# 데이터의 변수명 보기
cctv_seoul.columns
Out[6]:
Index(['기관명', '소계', '2013년도 이전', '2014년', '2015년', '2016년'], dtype='object')
In [7]:
# 첫 번째 변수명 보기
cctv_seoul.columns[0]
Out[7]:
'기관명'
In [10]:
# 변수명 변경하기
cctv_seoul.rename(columns = {cctv_seoul.columns[0] : "구별"}, inplace = True)
cctv_seoul.head()
Out[10]:
구별 소계 2013년도 이전 2014년 2015년 2016년
0 강남구 2780 1292 430 584 932
1 강동구 773 379 99 155 377
2 강북구 748 369 120 138 204
3 강서구 884 388 258 184 81
4 관악구 1496 846 260 390 613
In [52]:
# excel 데이터 불러오기
pop_seoul = pd.read_excel("01. population_in_Seoul.xls", encoding="UTF-8")
pop_seoul.head()
Out[52]:
기간 자치구 세대 인구 인구.1 인구.2 인구.3 인구.4 인구.5 인구.6 인구.7 인구.8 세대당인구 65세이상고령자
0 기간 자치구 세대 합계 합계 합계 한국인 한국인 한국인 등록외국인 등록외국인 등록외국인 세대당인구 65세이상고령자
1 기간 자치구 세대 남자 여자 남자 여자 남자 여자 세대당인구 65세이상고령자
2 2017.1/4 합계 4202888 10197604 5000005 5197599 9926968 4871560 5055408 270636 128445 142191 2.36 1321458
3 2017.1/4 종로구 72654 162820 79675 83145 153589 75611 77978 9231 4064 5167 2.11 25425
4 2017.1/4 중구 59481 133240 65790 67450 124312 61656 62656 8928 4134 4794 2.09 20764
In [53]:
# excel 데이터 불러오기
pop_seoul = pd.read_excel("01. population_in_Seoul.xls", 
                          encoding = "UTF-8",
                          header = 2,
                          parse_cols = "B, D, G, J, N")
pop_seoul.head()
C:\Users\buill\Anaconda3\envs\deep\lib\site-packages\ipykernel_launcher.py:5: FutureWarning: the 'parse_cols' keyword is deprecated, use 'usecols' instead
  """
Out[53]:
자치구 계.1 계.2 65세이상고령자
0 합계 10197604.0 9926968.0 270636.0 1321458.0
1 종로구 162820.0 153589.0 9231.0 25425.0
2 중구 133240.0 124312.0 8928.0 20764.0
3 용산구 244203.0 229456.0 14747.0 36231.0
4 성동구 311244.0 303380.0 7864.0 39997.0
In [54]:
# 변수명 변경하기
pop_seoul.rename(columns = {pop_seoul.columns[0] : "구별",
                            pop_seoul.columns[1] : "인구수",
                            pop_seoul.columns[2] : "한국인",
                            pop_seoul.columns[3] : "외국인",
                            pop_seoul.columns[4] : "고령자",}, inplace = True)
pop_seoul.head()
Out[54]:
구별 인구수 한국인 외국인 고령자
0 합계 10197604.0 9926968.0 270636.0 1321458.0
1 종로구 162820.0 153589.0 9231.0 25425.0
2 중구 133240.0 124312.0 8928.0 20764.0
3 용산구 244203.0 229456.0 14747.0 36231.0
4 성동구 311244.0 303380.0 7864.0 39997.0
In [16]:
# 행 이름
pop_seoul.index
Out[16]:
RangeIndex(start=0, stop=27, step=1)
In [17]:
# 데이터의 정보
pop_seoul.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 27 entries, 0 to 26
Data columns (total 5 columns):
구별     26 non-null object
인구수    26 non-null float64
한국인    26 non-null float64
외국인    26 non-null float64
고령자    26 non-null float64
dtypes: float64(4), object(1)
memory usage: 1.1+ KB
In [18]:
# 기술통계량 구하기
pop_seoul.describe()
Out[18]:
인구수 한국인 외국인 고령자
count 2.600000e+01 2.600000e+01 26.000000 2.600000e+01
mean 7.844311e+05 7.636129e+05 20818.153846 1.016506e+05
std 1.924156e+06 1.873421e+06 51598.169516 2.491801e+05
min 1.332400e+05 1.243120e+05 2017.000000 2.076400e+04
25% 3.348055e+05 3.316718e+05 4489.000000 4.831200e+04
50% 4.135115e+05 4.051690e+05 9079.500000 5.439750e+04
75% 4.907855e+05 4.864445e+05 14901.500000 6.431075e+04
max 1.019760e+07 9.926968e+06 270636.000000 1.321458e+06
In [21]:
# 정렬하기 : 내림차순
pop_seoul.sort_values(by = "인구수", ascending = False)
Out[21]:
구별 인구수 한국인 외국인 고령자
0 합계 10197604.0 9926968.0 270636.0 1321458.0
24 송파구 667483.0 660584.0 6899.0 72506.0
16 강서구 603772.0 597248.0 6524.0 72548.0
23 강남구 570500.0 565550.0 4950.0 63167.0
11 노원구 569384.0 565565.0 3819.0 71941.0
21 관악구 525515.0 507203.0 18312.0 68082.0
12 은평구 494388.0 489943.0 4445.0 72334.0
15 양천구 479978.0 475949.0 4029.0 52975.0
8 성북구 461260.0 449773.0 11487.0 64692.0
25 강동구 453233.0 449019.0 4214.0 54622.0
22 서초구 450310.0 445994.0 4316.0 51733.0
17 구로구 447874.0 416487.0 31387.0 56833.0
7 중랑구 414503.0 409882.0 4621.0 56774.0
20 동작구 412520.0 400456.0 12064.0 56013.0
19 영등포구 402985.0 368072.0 34913.0 52413.0
14 마포구 389649.0 378566.0 11083.0 48765.0
5 광진구 372164.0 357211.0 14953.0 42214.0
6 동대문구 369496.0 354079.0 15417.0 54173.0
10 도봉구 348646.0 346629.0 2017.0 51312.0
9 강북구 330192.0 326686.0 3506.0 54813.0
13 서대문구 327163.0 314982.0 12181.0 48161.0
4 성동구 311244.0 303380.0 7864.0 39997.0
18 금천구 255082.0 236353.0 18729.0 32970.0
3 용산구 244203.0 229456.0 14747.0 36231.0
1 종로구 162820.0 153589.0 9231.0 25425.0
2 중구 133240.0 124312.0 8928.0 20764.0
26 NaN NaN NaN NaN NaN
In [22]:
# 특정 변수만 불러오기
pop_seoul["인구수"]
Out[22]:
0     10197604.0
1       162820.0
2       133240.0
3       244203.0
4       311244.0
5       372164.0
6       369496.0
7       414503.0
8       461260.0
9       330192.0
10      348646.0
11      569384.0
12      494388.0
13      327163.0
14      389649.0
15      479978.0
16      603772.0
17      447874.0
18      255082.0
19      402985.0
20      412520.0
21      525515.0
22      450310.0
23      570500.0
24      667483.0
25      453233.0
26           NaN
Name: 인구수, dtype: float64
In [23]:
# 일부의 행만 불러오기
pop_seoul[0:3]
Out[23]:
구별 인구수 한국인 외국인 고령자
0 합계 10197604.0 9926968.0 270636.0 1321458.0
1 종로구 162820.0 153589.0 9231.0 25425.0
2 중구 133240.0 124312.0 8928.0 20764.0
In [29]:
# 하나의 열만 추출하기
pop_seoul.loc[: , "구별"]
Out[29]:
0       합계
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     NaN
Name: 구별, dtype: object
In [30]:
# 한 개 이상의 열을 추출하기
pop_seoul.loc[: , ["구별", "인구수"]]
Out[30]:
구별 인구수
0 합계 10197604.0
1 종로구 162820.0
2 중구 133240.0
3 용산구 244203.0
4 성동구 311244.0
5 광진구 372164.0
6 동대문구 369496.0
7 중랑구 414503.0
8 성북구 461260.0
9 강북구 330192.0
10 도봉구 348646.0
11 노원구 569384.0
12 은평구 494388.0
13 서대문구 327163.0
14 마포구 389649.0
15 양천구 479978.0
16 강서구 603772.0
17 구로구 447874.0
18 금천구 255082.0
19 영등포구 402985.0
20 동작구 412520.0
21 관악구 525515.0
22 서초구 450310.0
23 강남구 570500.0
24 송파구 667483.0
25 강동구 453233.0
26 NaN NaN
In [34]:
# 특정한 행과 특정한 열만 추출하기
# 구별 열만 추출하기
pop_seoul.loc[pop_seoul.구별 == "양천구", "인구수"]
Out[34]:
15    479978.0
Name: 인구수, dtype: float64
In [35]:
# iloc를 이용한 특정한 행과 열을 추출하기
pop_seoul.iloc[1:3, 2:4]
Out[35]:
한국인 외국인
1 153589.0 9231.0
2 124312.0 8928.0
In [37]:
# 데이터 복사하기
pop_seoul2 = pop_seoul.copy()
pop_seoul2.head()
Out[37]:
구별 인구수 한국인 외국인 고령자
0 합계 10197604.0 9926968.0 270636.0 1321458.0
1 종로구 162820.0 153589.0 9231.0 25425.0
2 중구 133240.0 124312.0 8928.0 20764.0
3 용산구 244203.0 229456.0 14747.0 36231.0
4 성동구 311244.0 303380.0 7864.0 39997.0
In [42]:
# 구별에 용산구가 있는지를 확인
pop_seoul["구별"].isin(["용산구"])
Out[42]:
0     False
1     False
2     False
3      True
4     False
5     False
6     False
7     False
8     False
9     False
10    False
11    False
12    False
13    False
14    False
15    False
16    False
17    False
18    False
19    False
20    False
21    False
22    False
23    False
24    False
25    False
26    False
Name: 구별, dtype: bool
In [44]:
# 양적 자료인 열에 대한 누적합 구하기
pop_seoul.iloc[:, 1:4].apply(np.cumsum)
Out[44]:
인구수 한국인 외국인
0 10197604.0 9926968.0 270636.0
1 10360424.0 10080557.0 279867.0
2 10493664.0 10204869.0 288795.0
3 10737867.0 10434325.0 303542.0
4 11049111.0 10737705.0 311406.0
5 11421275.0 11094916.0 326359.0
6 11790771.0 11448995.0 341776.0
7 12205274.0 11858877.0 346397.0
8 12666534.0 12308650.0 357884.0
9 12996726.0 12635336.0 361390.0
10 13345372.0 12981965.0 363407.0
11 13914756.0 13547530.0 367226.0
12 14409144.0 14037473.0 371671.0
13 14736307.0 14352455.0 383852.0
14 15125956.0 14731021.0 394935.0
15 15605934.0 15206970.0 398964.0
16 16209706.0 15804218.0 405488.0
17 16657580.0 16220705.0 436875.0
18 16912662.0 16457058.0 455604.0
19 17315647.0 16825130.0 490517.0
20 17728167.0 17225586.0 502581.0
21 18253682.0 17732789.0 520893.0
22 18703992.0 18178783.0 525209.0
23 19274492.0 18744333.0 530159.0
24 19941975.0 19404917.0 537058.0
25 20395208.0 19853936.0 541272.0
26 NaN NaN NaN
In [49]:
# 양적 자료인 열에 대한 범위 구하기
pop_seoul.iloc[:, 1:4].apply(lambda x: x.max() - x.min())
Out[49]:
인구수    10064364.0
한국인     9802656.0
외국인      268619.0
dtype: float64
In [55]:
# 첫 행 제거하기
pop_seoul.drop([0], inplace = True)
pop_seoul.head()
Out[55]:
구별 인구수 한국인 외국인 고령자
1 종로구 162820.0 153589.0 9231.0 25425.0
2 중구 133240.0 124312.0 8928.0 20764.0
3 용산구 244203.0 229456.0 14747.0 36231.0
4 성동구 311244.0 303380.0 7864.0 39997.0
5 광진구 372164.0 357211.0 14953.0 42214.0
In [56]:
# 구별 목록 보기
pop_seoul["구별"].unique()
Out[56]:
array(['종로구', '중구', '용산구', '성동구', '광진구', '동대문구', '중랑구', '성북구', '강북구',
       '도봉구', '노원구', '은평구', '서대문구', '마포구', '양천구', '강서구', '구로구', '금천구',
       '영등포구', '동작구', '관악구', '서초구', '강남구', '송파구', '강동구', nan], dtype=object)
In [57]:
# NAN 추출하기
pop_seoul[pop_seoul["구별"].isnull()]
Out[57]:
구별 인구수 한국인 외국인 고령자
26 NaN NaN NaN NaN NaN
In [58]:
# 구별에 NAN을 포함하는 행 삭제하기
pop_seoul.drop([26], inplace = True)
pop_seoul.head()
In [60]:
# 새로운 변수 만들기
pop_seoul["외국인비율"] = (pop_seoul["외국인"] / pop_seoul["인구수"])*100
pop_seoul["고령자비율"] = (pop_seoul["고령자"] / pop_seoul["인구수"])*100
pop_seoul.head()
Out[60]:
구별 인구수 한국인 외국인 고령자 외국인비율 고령자비율
1 종로구 162820.0 153589.0 9231.0 25425.0 5.669451 15.615404
2 중구 133240.0 124312.0 8928.0 20764.0 6.700690 15.583909
3 용산구 244203.0 229456.0 14747.0 36231.0 6.038828 14.836427
4 성동구 311244.0 303380.0 7864.0 39997.0 2.526635 12.850689
5 광진구 372164.0 357211.0 14953.0 42214.0 4.017852 11.342849
In [61]:
# 인구수를 기준으로 내림차순으로 정렬하기
pop_seoul.sort_values(by = "인구수", ascending = False)
pop_seoul.head()
Out[61]:
구별 인구수 한국인 외국인 고령자 외국인비율 고령자비율
1 종로구 162820.0 153589.0 9231.0 25425.0 5.669451 15.615404
2 중구 133240.0 124312.0 8928.0 20764.0 6.700690 15.583909
3 용산구 244203.0 229456.0 14747.0 36231.0 6.038828 14.836427
4 성동구 311244.0 303380.0 7864.0 39997.0 2.526635 12.850689
5 광진구 372164.0 357211.0 14953.0 42214.0 4.017852 11.342849
In [62]:
# CCTV와 인구 데이터 합치기
seoul = pd.merge(cctv_seoul, pop_seoul, on = "구별")
seoul.head()
Out[62]:
구별 소계 2013년도 이전 2014년 2015년 2016년 인구수 한국인 외국인 고령자 외국인비율 고령자비율
0 강남구 2780 1292 430 584 932 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217
1 강동구 773 379 99 155 377 453233.0 449019.0 4214.0 54622.0 0.929765 12.051638
2 강북구 748 369 120 138 204 330192.0 326686.0 3506.0 54813.0 1.061806 16.600342
3 강서구 884 388 258 184 81 603772.0 597248.0 6524.0 72548.0 1.080540 12.015794
4 관악구 1496 846 260 390 613 525515.0 507203.0 18312.0 68082.0 3.484582 12.955291
In [65]:
# 특정한 열 삭제하기
del seoul["2013년도 이전"]
del seoul["2014년"]
del seoul["2015년"]
del seoul["2016년"]
seoul.head()
Out[65]:
구별 소계 인구수 한국인 외국인 고령자 외국인비율 고령자비율
0 강남구 2780 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217
1 강동구 773 453233.0 449019.0 4214.0 54622.0 0.929765 12.051638
2 강북구 748 330192.0 326686.0 3506.0 54813.0 1.061806 16.600342
3 강서구 884 603772.0 597248.0 6524.0 72548.0 1.080540 12.015794
4 관악구 1496 525515.0 507203.0 18312.0 68082.0 3.484582 12.955291
In [66]:
# 기준 세팅하기
seoul.set_index("구별", inplace = True)
seoul.head()
Out[66]:
소계 인구수 한국인 외국인 고령자 외국인비율 고령자비율
구별
강남구 2780 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217
강동구 773 453233.0 449019.0 4214.0 54622.0 0.929765 12.051638
강북구 748 330192.0 326686.0 3506.0 54813.0 1.061806 16.600342
강서구 884 603772.0 597248.0 6524.0 72548.0 1.080540 12.015794
관악구 1496 525515.0 507203.0 18312.0 68082.0 3.484582 12.955291
In [67]:
# 상관계수 구하기
np.corrcoef(seoul["고령자비율"], seoul["소계"])
Out[67]:
array([[ 1.        , -0.28078554],
       [-0.28078554,  1.        ]])
In [68]:
# 상관계수 구하기
np.corrcoef(seoul["외국인비율"], seoul["소계"])
Out[68]:
array([[ 1.        , -0.13607433],
       [-0.13607433,  1.        ]])
In [69]:
# 상관계수 구하기
np.corrcoef(seoul["인구수"], seoul["소계"])
Out[69]:
array([[ 1.        ,  0.30634228],
       [ 0.30634228,  1.        ]])
In [84]:
# 가로막대 그래프
font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
rc('font', family=font_name)
seoul["소계"].plot(kind = "barh", grid = True, figsize = (10, 10))
plt.show()
In [85]:
# 가로막대 그래프
seoul["소계"].sort_values().plot(kind = "barh", grid = True, figsize = (10, 10))
plt.show()
In [86]:
seoul["CCTV비율"] = (seoul["소계"] / seoul["인구수"])*100
seoul["CCTV비율"].sort_values().plot(kind = "barh", grid = True, figsize = (10, 10))
plt.show()
In [90]:
# 산점도 작성하기
plt.figure(figsize = (10, 10))
plt.scatter(seoul["인구수"], seoul["소계"], s = 50)
plt.xlabel("인구수")
plt.ylabel("CCTV")
plt.grid()
plt.show()
In [92]:
fp1 = np.polyfit(seoul["인구수"], seoul["소계"], 1)
f1 = np.poly1d(fp1)
fx = np.linspace(100000, 700000, 100)
In [93]:
plt.figure(figsize = (10, 10))
plt.scatter(seoul["인구수"], seoul["소계"], s = 50)
plt.plot(fx, f1(fx), ls = "dashed", lw = 3, color = "g")
plt.xlabel("인구수")
plt.ylabel("CCTV")
plt.grid()
plt.show()
In [94]:
fp1 = np.polyfit(seoul["인구수"], seoul["소계"], 1)
f1 = np.poly1d(fp1)
fx = np.linspace(100000, 700000, 100)

seoul["오차"] = np.abs(seoul["소계"] - f1(seoul["인구수"]))
seoul_sort = seoul.sort_values(by = "오차", ascending = False)
seoul_sort.head()
Out[94]:
소계 인구수 한국인 외국인 고령자 외국인비율 고령자비율 CCTV비율 오차
구별
강남구 2780 570500.0 565550.0 4950.0 63167.0 0.867660 11.072217 0.487292 1388.055355
송파구 618 667483.0 660584.0 6899.0 72506.0 1.033584 10.862599 0.092587 900.911312
양천구 2034 479978.0 475949.0 4029.0 52975.0 0.839413 11.036964 0.423769 760.563512
서초구 1930 450310.0 445994.0 4316.0 51733.0 0.958451 11.488308 0.428594 695.403794
용산구 1624 244203.0 229456.0 14747.0 36231.0 6.038828 14.836427 0.665020 659.231690
In [95]:
plt.figure(figsize = (10, 10))
plt.scatter(seoul["인구수"], seoul["소계"], c = seoul["오차"], s = 50)
plt.plot(fx, f1(fx), ls = "dashed", lw = 3, color = "g")

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

plt.xlabel("인구수")
plt.ylabel("CCTV")
plt.colorbar()
plt.grid()
plt.show()

01서울시 구별 CCTV 현황 분석