log.Sehee
[데이터 취업 스쿨 스터디 노트] Folium 지도 시각화 / 서울시 범죄 검거 현황 4 - 6 본문
서울시 범죄현황 데이터 시각화
기본 설정
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib import rc
plt.rcParams['axes.unicode_minus'] = False
rc('font', family='Arial Unicode MS')
get_ipython().run_line_magic('matplotlib', 'inline')
상관관계 확인
# pairplot 강도, 살인, 폭력에 대한 상관관계 확인
# kind : scatter, kde, hist, reg
sns.pairplot(data=crime_anal_norm, vars = ['살인', '강도', '폭력'], kind='reg', height=3);
# 인구수, CCTV와 살인, 강도의 상관관계 확인
def drawGraph():
sns.pairplot(
data = crime_anal_norm,
x_vars = ['인구수', 'CCTV'],
y_vars = ['살인', '강도'],
kind = 'reg',
height = 4,
)
plt.show()
drawGraph()
검거율 heatmap
# 검거율 heatmap
# 검거 column 기준으로 정렬
def drawGraph():
# 데이터 프레임 생성
target_col = ['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율', '검거']
crime_anal_norm_sort = crime_anal_norm.sort_values(by='검거', ascending=False)
# 그래프 설정
plt.figure(figsize = (10, 10))
sns.heatmap(
data = crime_anal_norm_sort[target_col],
annot = True,
fmt = 'f',
linewidths = 0.5, # 간격 설정
cmap = 'RdPu'
)
plt.title('범죄 검거 비율(정규화된 검거의 합으로 정렬)'),
plt.show()
drawGraph()
범죄 발생 건수 heatmap
# 범죄 발생 건수 heatmap
# '범죄' column을 기준으로 정렬
def drawGraph():
# 데이터 프레임 생성
target_col = ['강간', '강도', '살인', '절도', '폭력', '범죄']
crime_anal_norm_sort = crime_anal_norm.sort_values(by='범죄', ascending=False)
# 그래프 설정
plt.figure(figsize = (10, 10))
sns.heatmap(
data = crime_anal_norm_sort[target_col],
annot = True,
fmt = 'f',
linewidths = 0.5, # 간격 설정
cmap = 'RdPu'
)
plt.title('범죄 발생 비율(정규화된 발생 건수으로 정렬)'),
plt.show()
drawGraph()
# 데이터 저장
crime_anal_norm.to_csv('../data/02. crime_in_Seoul_final.csv', sep=',', encoding='utf-8')
folium
folium 설치
# folium 설치
pip install folium
import folium, json, pandas as pd
# zoom_start = 지도 확대 정도 , 0 ~ 18 권장
m = folium.Map(location=[37.4850084, 126.8779291], zoom_start = 18)
m
save() : 시각화 한 지도를 지정 파일 형식으로 저장
m.save('./folium.html')
!ls
tiles : 지도 디자인을 변경해준다.
m = folium.Map(
location=[37.4850084, 126.8779291],
zoom_start = 18,
tiles='Stamen Toner'
)
m
강의를 만들 때엔 Stamen Toner 옵션이 존재했던 것 같은데 기본 옵션에서 없어졌나보다.
Stamen Toner 옵션을 사용하려면 링크와 인증정보를 따로 기재해주어야 했다.
tiles = "https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.png?api_key=인증키"
attr = "toner"
m = folium.Map(
location=[37.4850084, 126.8779291],
zoom_start = 15,
tiles = tiles,
attr = attr
)
m
folium.Marker()
- 위도, 경도로 마커 위치 설정
- popup : 마우스로 클릭했을 때 정보가 나온다. html 문법으로 하이퍼링크, 볼드체, 이탤릭체 등 사용 가능
- tooltip : 마우스로 hover했을 때 정보가 나온다. 위와 같이 html 문법 적용 가능
- folium.Icon() : 아이콘 디자인을 변경
- color : 마커 색 변경
- icon_color : 마커 아이콘 색 변경
- icon : 아이콘 변경 / fontawesome 사이트에서 찾아서 설정 가능
- angel : 마커 크기 변경
- prefix : 기울기 조정
m = folium.Map(
location=[37.5696765, 126.976177],
zoom_start = 15
)
# 광화문역
folium.Marker(
(37.5696765, 126.976177),
icon = folium.Icon(color='black')
).add_to(m)
# 을지로역
folium.Marker(
(37.5660286, 126.9954924),
popup = '<b>Subway</b>',
tooltip = '<i>을지로역</i>',
icon = folium.Icon(
color='purple',
icon_color = 'pink',
icon = 'cloud'
)
).add_to(m)
# 을지로2가
folium.Marker(
(37.5658833, 126.9859321),
popup = '<a href="https://maps.app.goo.gl/mrt6y86vHp7unoUNA" target=_"blink">을지로2가</a>',
tooltip = '<i>을지로2가역</i>',
icon = folium.Icon(
color='red',
icon_color = 'beige',
icon = 'cat',
angel = 50, # 마커 크기
prefix = 'fa' # 기울기 / 조정해야만 나오는 아이콘들이 있다.
)
).add_to(m)
m
마우스 hover시 이미지. tooltip 옵션
마커 클릭 시 이미지. a 태그로 href를 달았다.
folium.CilckForMarker() : 지도 위에 마우스로 클릭했을 때 마커를 생성한다.
m = folium.Map(
location=[37.5696765, 126.976177],
zoom_start = 15
)
# popup : 마커의 정보. 기본적으로 위도, 경도가 나온다
m.add_child(folium.ClickForMarker(popup='Click'))
folium.LatLngPopup() : 지도를 마우스로 클릭했을 때 위도 경도 정보를 반환해준다.
m = folium.Map(
location=[37.5696765, 126.976177],
zoom_start = 15
)
m.add_child(folium.LatLngPopup())
Circle(), CircleMarker() : 설정 범위를 동그란 구역으로 표시해준다. 큰 차이점이 없으나 radius의 크기 차이가 있다.
m = folium.Map(
location=[37.5702, 126.9769],
zoom_start = 15
)
# Circle
folium.Circle(
location = [37.5702, 126.9769],
radius = 100,
fill = True,
color = 'green',
fill_color = 'red',
popup = 'Circle',
tooltip = 'C'
).add_to(m)
# Circle Marker, Circle과 큰 차이가 없다.
# radius 값의 차이가 있다.
folium.CircleMarker(
location = [37.5656, 126.9735],
radius = 30,
fill = True,
color = 'blue',
fill_color = 'yellow',
popup = 'Circle',
tooltip = 'C'
).add_to(m)
m
folium.Choropleth : 경계선 데이터를 이용해 색상의 정도로 데이터의 빈도를 그려준다.
import json
state_data = pd.read_csv('../data/02. US_Unemployment_Oct2012.csv')
state_data.tail(2)
m = folium.Map([43, -102], zoom_start=3) # 배경 지도
# json 파일 사용
folium.Choropleth(
geo_data = '../data/02. us-states.json', # 경계선 좌표값이 담긴 데이터
data = state_data, # Series or DataFrame / 실업률 데이터
columns = ['State', 'Unemployment'], # DataFrame columns
key_on = 'feature.id', # us-states.json 데이터와 state_date 묶기
fill_color = 'BuPu', # 색상 설정
fill_opacity = 1, # 배경 색상 투명도 설정
line_opacity = 1, # 경계선 투명도 설정
legend_name = 'Unemployment rate (%)'
).add_to(m)
m
아파트 유형 지도 시각화
공공데이터포털에서 '서울특별시 동작구_주택유형별 위치 정보 및 세대수 현황' 다운로드
import pandas as pd
df = pd.read_csv('../data/02. 서울특별시 동작구_주택유형별 위치 정보 및 세대수 현황_20240405.csv', encoding='cp949')
df.tail(2)
df.info()
데이터 갯수가 맞지 않아 Null 값 제거
# NaN 데이터 제거
df = df.dropna()
index 초기화
# reset_index의 drop 옵션은 기본 False. 인덱스가 column으로 들어온다. True일 때 column으로 들어오지 않으면서 index가 초기화된다.
df = df.reset_index(drop=True)
columns 정보확인
df.columns
column name 전처리
# 연번, 분류 column이 '연번 ', '분류 ' 으로 공백 제거를 위한 rename 실행
df = df.rename(columns={'연번 ':'연번', '분류 ':'분류'})
del df['연번']
df.tail()
세대수의 빈도에 따라 색상을 다르게 표시해주기 위해 데이터 확인. 50%를 기준으로 색상 변경
df.describe()
주택 위치 정보 표시 및 세대수 빈도에 따른 정보 표시
# folium
m = folium.Map(location=[37.4988794, 126.9516345], zoom_start = 13.5)
for idx, row in df.iterrows():
# location
lat, lng = row.위도, row.경도
# Marker
folium.Marker(
location = [lat, lng],
popup = row.주소,
tooltip = row.분류,
icon = folium.Icon(
icon = 'home',
color = 'lightred' if row.세대수 >= 204 else 'lightblue',
icon_color = 'darkred' if row.세대수 >= 204 else 'darkblue',
)
).add_to(m)
# Circle
folium.Circle(
location = [lat, lng],
radius = row.세대수 * 0.5,
fill = True,
color = 'pink' if row.세대수 >= 528 else 'green',
fill_color = 'pink' if row.세대수 >= 528 else 'green'
).add_to(m)
m
서울시 범죄 현황에 대한 지도 시각화
import json, folium, pandas as pd
crime_anal_norm = pd.read_csv(
'../data/02. crime_in_Seoul_final.csv', index_col = 0, encoding='utf-8'
)
geo_path = '../data/02. skorea_municipalities_geo_simple.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))
crime_anal_norm.tail(2)
살인 발생 건수 지도 시각화
# 살인 발생 건수 지도 시각화
my_map = folium.Map(
location = [37.5502, 126.982],
zoom_start = 11,
# tiles = 'Stamen Toner'
)
folium.Choropleth(
geo_data = geo_str, # 우리나라 경계선 좌표값이 담긴 데이터
data = crime_anal_norm['살인'],
columns = [crime_anal_norm.index, crime_anal_norm['살인']],
key_on = 'feature.id',
fill_color = 'PuRd',
fill_opacity = 0.7,
line_opacity = 0.2,
legend_name = '정규화된 살인 발생 건수'
).add_to(my_map)
my_map
인구 대비 범죄 건수 지도 시각화
# 인구 대비 범죄 건수 지도 시각화
tmp_criminal = crime_anal_norm['범죄'] / crime_anal_norm['인구수']
my_map = folium.Map(
location = [37.5502, 126.982],
zoom_start = 11,
# tiles = 'Stamen Toner'
)
folium.Choropleth(
geo_data = geo_str, # 우리나라 경계선 좌표값이 담긴 데이터
data = tmp_criminal,
columns = [crime_anal_norm.index, tmp_criminal],
key_on = 'feature.id',
fill_color = 'PuRd',
fill_opacity = 0.7,
line_opacity = 0.2,
legend_name = '인구 대비 범죄 발생 건수'
).add_to(my_map)
my_map
경찰서별 정보를 범죄 발생과 함께 정리
# 경찰서별 정보를 범죄 발생과 함께 정리
crime_anal_station = pd.read_csv('../data/02. crime_in_Seoul_raw.csv', encoding='utf-8')
crime_anal_station.tail(2)
검거 정규화
col = ['살인검거', '강간검거', '강도검거', '절도검거', '폭력검거']
tmp = crime_anal_station[col] / crime_anal_station[col].max() # 정규화
crime_anal_station['검거'] = np.mean(tmp, axis=1) # numpy에서 axis = 1은 가로(행), pandas에서 axis = 1은 세로(열)
crime_anal_station.head()
경찰서 위치 마커 표시
# 경찰서 위치 마커 표시
my_map = folium.Map(
location = [37.5502, 126.982], zoom_start = 11,
)
for idx, rows in crime_anal_station.iterrows():
folium.Marker(
location = [rows['lat'], rows['lng']]
).add_to(my_map)
my_map
범죄 발생률에 따른 경계선 표시와 검거율에 따른 정보 표시
# 검거에 값을 곱한 뒤 원의 넓이 적용
my_map = folium.Map(
location = [37.5502, 126.982], zoom_start = 11,
)
folium.Choropleth(
geo_data = geo_str,
data = crime_anal_norm['범죄'],
columns = [crime_anal_norm.index, crime_anal_norm['범죄']],
key_on = 'feature.id',
fill_color = 'PuRd',
fill_opacity = 0.7,
line_opacity = 0.2,
).add_to(my_map)
for idx, rows in crime_anal_station.iterrows():
folium.CircleMarker(
location = [rows['lat'], rows['lng']],
radius = rows['검거'] * 50,
popup = rows['구분'] + ' : ' + '%.2f' % rows['검거'],
color = '#3186cc',
fill = True,
fill_color = '#3186cc',
).add_to(my_map)
my_map
내일의 학습 목표
웹데이터 분석 1 - 3