
앞서 서울 '구'별 인구대비 CCTV 비율에 대한 데이터 정리는 끝이 났다.
이번에는 그 데이터들을 바탕으로 데이터 시각화를 해보려고 한다.
import matplotlib.pyplot as plt
from matplotlib import rc
plt.rcParams["axes.unicode_minus"] = False
#마이너스 부호 때문에 한글이 깨질 수 가 있어 주는 설정
rc("font", family="Arial Unicode Ms")
%matplotlib inline
data_result.head()

data_result["소계"].plot(kind="barh", grid=True, figsize=(10, 10));

그런데 눈에 데이터가 잘 들어오지 않아 정렬을 해보려고 한다.
그 결과 강남구부터 내림차순으로 그래프로 나타나게 된다.
data_result["소계"].sort_values().plot(kind="barh", grid=True, figsize=(10, 10));
그리고 이것을 함수에 담아 주겠다.
def drawGraph
data_result["소계"].sort_values().plot(
kind="barh", grid=True, figsize=(10, 10));
drawGraph()

여기에서 그래프의 정보를 더하여 주기 위해 title 등을 추가해 주겠다.
def drawGraph():
data_result["소계"].sort_values().plot(
kind="barh",
grid=True,
title="가장 CCTV가 많은 구",
figsize=(10, 10));
drawGraph()
결과적으로, 절대적인 CCTV 대수를 내림차순으로 정렬한 결과, 강남구가 가장 많은 CCTV를 설치한 것으로 나타났다.

이번에는 CCTV비율로 시각화를 해보자.
data_result.head()

def drawGraph():
data_result["CCTV비율"].sort_values().plot(
kind="barh",
grid=True,
title="가장 CCTV가 많은 구",
figsize=(10, 10));
drawGraph()
CCTV 비율로 내림차순 정렬을 하였더니, 종로구가 가장 인구대비 CCTV가 많은 것으로 나타났다.

비고)
kind : str
The kind of plot to produce:
‘line’ : line plot (default)
‘bar’ : vertical bar plot
‘barh’ : horizontal bar plot
‘hist’ : histogram
‘box’ : boxplot
‘kde’ : Kernel Density Estimation plot
‘density’ : same as ‘kde’
‘area’ : area plot
‘pie’ : pie plot
‘scatter’ : scatter plot (DataFrame only)
‘hexbin’ : hexbin plot (DataFrame only)
data_result.head()

인구수와 소계 컬럼으로 scatter plot을 그려보려고 한다.
가로축이 14, 세로축이 10인 크기의 figsize를 설정해주고, x축 = 인구수, y축 = CCTV로 설정하여 그래프를 그려보면 다음과 같다.
def drawGraph():
plt.figure(figsize=(14, 10))
plt.scatter(data_result["인구수"], data_result["소계"], s=50)
plt.xlabel("인구수")
plt.ylabel("CCTV")
plt.grid(True)
plt.show()
drawGraph()

polyfit method를 불러와 x축=인구수 y축=소계 로 설정해주면,이 두 변수에 대한 직선의 계수가 나오게 된다.
import numpy as np
fpl=np. polyfit(data_result["인구수"], data_result["소계"], 1)
fpl
계수 값이 1.11155868e-03, 1.06515745e+03

이것을 f1라는 변수로 poly1d를 써서 여기에 담아준다.
f1 = np.poly1d(fpl)
f1

f1(400000)

그렇다면, scatter plot에 추가해 줄 그래프를 만들어 보겠다.
fx = np.linspace(100000, 700000, 100)
경향선을 추가한 그래프를 그려보자.
def drawGraph():
plt.figure(figsize=(14, 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(True)
plt.show()
drawGraph()
직선을 넣어서 경향을 보여준다.

만약 인구가 50만인 구가 있다면, 그 구는 CCTV를 1600대 정도 가져야한다(서울시 기준)
fp1 = np.polyfit(data_result["인구수"], data_result["소계"], 1)
f1 = np.poly1d(fp1)
fx = np.linspace(100000, 700000, 100)
data_result.head(3)

오차를 계산하여 오차 컬럼을 추가해보려고 한다.
오차 = 소계 - f1값에 넣어준 인구수 로 정의해볼 수 있다.
data_result["오차"] = data_result["소계"] - f1(data_result["인구수"])
data_result.head()

경향과 비교해서 데이터의 오차가 너무 많이 나는 경우의 데이터를 계산해 주면,
# 경향과 비교해서 데이터의 오차가 너무 나는 데이터를 계산
df_sort_f = data_result.sort_values(by="오차", ascending=False) #내림차순
df_sort_t = data_result.sort_values(by="오차", ascending=True) #오름차순
# 경향 대비 CCTV를 많이 가진 구
df_sort_f.head()

# 경향 대비 CCTV를 적게 가진 구
df_sort_t.head()
이렇게 데이터 결과가 나왔다면,
위 그래프에, 경향에 따른 높고 낮음을 색깔로 표현해보고자 한다.
matplotlib의 colors라는 서브패키지를 가져와서 ListedColormap이라는 기능을 가져온다.
그리고 color_step이라는 리스트 안에 6개의 색깔을 지정한다.
my_cmap이라는 변수를 두고 ListedColormap객체를 가져와서 color_step변수를 넣어 준다.
from matplotlib.colors import ListedColormap
# colormap 을 사용자 정의(user define)로 세팅
color_step = ["#e74c3c", "#2ecc71", "#95a9a6", "#2ecc71", "#3498db", "#3498db"]
my_cmap = ListedColormap(color_step)
다음으로,
기존 그래프에 기능을 하나씩 추가해보자.
그러기 위해서 경향에서 가장 벗어나 있는 데이터 값이 무엇인지 확인을 해보겠다.
data_result.head()
오차비율이 가장 큰 date_result의 index[0]을 살펴보면,
강남구가 인구수 약 5만6천명에 CCTV가 약3200대로써 오차가 가장 크다고 판단되었다.
data_result["인구수"][0]
'561052'

data_result["소계"][0]
'3238'

data_result.index[0]
'강남구'

그렇다면, text method에 인구수, 소계, 인덱스, 폰트사이즈를 추가해준다.
def drawGraph():
plt.figure(figsize=(14, 10))
plt.scatter(data_result["인구수"], data_result["소계"], s=50, c=data_result["오차"], cmap=my_cmap)
plt.plot(fx, f1(fx), ls="dashed", lw=3, color="g")
plt.text(df_sort_f["인구수"][0] * 1.02, df_sort_f["소계"][0] * 0.98, df_sort_f.index[0], fontsize=15)
plt.xlabel("인구수")
plt.ylabel("CCTV")
plt.colorbar()
plt.grid(True)
plt.show()
drawGraph()
다음과 같이 경향성이 가장 크게 벗어난 지점에 '강남구'가 표시된다.

이를 for문으로 반복하여 상위 5개, 하위 5개의 '구'를 그래프 위에 표시해보자.
def drawGraph():
plt.figure(figsize=(14, 10))
plt.scatter(data_result["인구수"], data_result["소계"], s=50, c=data_result["오차"], cmap=my_cmap)
plt.plot(fx, f1(fx), ls="dashed", lw=3, color="g")
for n in range(5):
# 상위 5개
plt.text(
df_sort_f["인구수"][n] * 1.02, # x좌표
df_sort_f["소계"][n] * 0.98, # y좌표
df_sort_f.index[n],
fontsize=15
)
# 하위 5개
plt.text(
df_sort_t["인구수"][n] * 1.02,
df_sort_t["소계"][n] * 0.98,
df_sort_t.index[n],
fontsize=15
)
plt.xlabel("인구수")
plt.ylabel("CCTV")
plt.colorbar()
plt.grid(True)
plt.show()
drawGraph()

위와 같이 초록색 직선의 경향선을 기준으로 상위 5개, 하위 5개의 '구'를 확인할 수 있다.
서울시 CCTV수와 인구수의 데이터를 병합하여 이와 같은 결론이 나온셈이다.
data_result.to_csv("../data/01. CCTV_result.csv", sep=",", encoding="utf-8")