지금까지 배운 것들을 바탕으로 이제 서울시 구별 범죄현황을 시각화할 차례다. 지도시각화를 위해서는 서울시의 지리정보가 포함된 json파일이 필요한데, 이번에는 Lucy Park님이 깃허브에 무료로 배포하신 정보를 바탕으로 진행한다. 해당 자료는 마지막 업데이트가 6년 전인 자료로, 한계는 분명히 존재하지만, 미니 프로젝트에 사용하기에는 무리가 없을 것이다.
https://github.com/southkorea/southkorea-maps
GitHub - southkorea/southkorea-maps: South Korea administrative divisions in ESRI Shapefile, GeoJSON and TopoJSON formats.
South Korea administrative divisions in ESRI Shapefile, GeoJSON and TopoJSON formats. - southkorea/southkorea-maps
github.com
1. 아래의 링크로 들어가 파일을 다운받는다.
southkorea-maps/kostat/2018/json/skorea-municipalities-2018-geo.json at master · southkorea/southkorea-maps
South Korea administrative divisions in ESRI Shapefile, GeoJSON and TopoJSON formats. - southkorea/southkorea-maps
github.com
2. 이 자료에서 서울시 부분만 추려서 다시 우리의 데이터로 활용한다. 아래의 코드를 작성한다.
import json
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'))
이전에 만들었던 범죄/CCTV 자료와 위에서 받은 지리자료를 받아 온다.
3. Stamen Toner 맵에 folium.Choropleth().add_to()를 이용해서 앞서 한 방법대로 범죄 현황을 표시한다.
tiles = "https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.png?api_key=API키 여기에 입력"
attr = "toner"
my_map = folium.Map(location=[37.5502, 126.982], zoom_start=11, tiles=tiles, attr=attr)
folium.Choropleth(
geo_data = geo_str,
data=crime_anal_norm['살인'],
columns=[crime_anal_norm.index, crime_anal_norm['살인']],
fill_color='PuRd',
key_on='feature.id',
fill_opacity=0.7,
line_opacity=0.2,
legend_name='정규화된 살인 발생 건수',
).add_to(my_map)
my_map

4. 이번엔 성범죄 발생 건수로 보자.
tiles = "https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.png?api_key=API키 여기에 입력"
attr = "toner"
my_map = folium.Map(location=[37.5502, 126.982], zoom_start=11, tiles=tiles, attr=attr)
folium.Choropleth(
geo_data = geo_str,
data=crime_anal_norm['강간,추행'],
columns=[crime_anal_norm.index, crime_anal_norm['강간,추행']],
fill_color='PuRd',
key_on='feature.id',
fill_opacity=0.7,
line_opacity=0.2,
legend_name='정규화된 성범죄 발생 건수',
).add_to(my_map)
my_map

5. 이번에는 5대 범죄 종합 점수로 보자.
tiles = "https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.png?api_key=API키 여기에 입력"
attr = "toner"
my_map = folium.Map(location=[37.5502, 126.982], zoom_start=11, tiles=tiles, attr=attr)
folium.Choropleth(
geo_data = geo_str,
data=crime_anal_norm['범죄'],
columns=[crime_anal_norm.index, crime_anal_norm['범죄']],
fill_color='PuRd',
key_on='feature.id',
fill_opacity=0.7,
line_opacity=0.2,
legend_name='정규화된 범죄 발생 건수',
).add_to(my_map)
my_map

6. 단순 합산치로만 보면 강남3구가 여전히 모든 부문에서 가장 높게 나타난다. 이제 인구 대비 범죄 건수를 통해 보다 확실하게 데이터를 판단해보자.
tiles = "https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.png?api_key=API키 여기에 입력"
attr = "toner"
tmp_criminal = crime_anal_norm['범죄'] / crime_anal_norm['인구수']
my_map = folium.Map(location=[37.5502, 126.982], zoom_start=11, tiles=tiles, attr=attr)
folium.Choropleth(
geo_data = geo_str,
data=tmp_criminal,
columns=[crime_anal_norm.index, tmp_criminal],
fill_color='PuRd',
key_on='feature.id',
fill_opacity=0.7,
line_opacity=0.2,
legend_name='정규화된 범죄 발생 건수',
).add_to(my_map)
my_map

7. 이번에는 경찰서별 정보를 바탕으로 범죄발생과 함께 정리해보자.

8. 경찰서 데이터를 정렬할 때 googlemaps의 geo데이터로 가져왔던 lat, lng를 바탕으로 마커를 표시한다.
my_map = folium.Map(location=[37.5502, 126.982], zoom_start=11)
for idx, rows in crime_anal_station.iterrows():
folium.Marker([rows['lat'], rows['lng']]).add_to(my_map)
my_map

9. 아직 부족하다. 좀 더 확실하게 시각화해주기 위해 '검거' 값에 적절한 값을 곱해 원의 넓이로 사용한다.
my_map = folium.Map(location=[37.5502, 126.982], zoom_start=11)
for idx, rows in crime_anal_station.iterrows():
folium.CircleMarker(
[rows['lat'], rows['lng']],
radius=rows['검거'] * 50,
popup = rows['구별'] + ' : ' + '%.2f' % rows['검거'],
color = '#3186cc',
fill = True,
fill_color = '#3186cc',
).add_to(my_map)
my_map

10. 마지막으로, 구별 범죄 현황과 경찰서별 검거율을 함께 표시해보자.
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['범죄']],
fill_color='PuRd',
key_on = 'feature.id',
fill_opacity = 0.7,
line_opacity = 0.2,
).add_to(my_map)
for idx, rows in crime_anal_station.iterrows():
folium.CircleMarker(
[rows['lat'], rows['lng']],
radius=rows['검거'] * 50,
popup = rows['구별'] + ' : ' + '%.2f' % rows['검거'],
color = '#3186cc',
fill = True,
fill_color = '#3186cc',
).add_to(my_map)
my_map

11. 여기까지만 보면 강남3구는 범죄율도 검거율도 높다. 그런데 이런 의문을 가질 수 있다. 강남3구에는 유흥가가 밀집되어 있다. 이러한 지역적 특성이 범죄율이 높은 것과 관련이 있지는 않을까? 지역적 분석이 필요하다.
추가검증
12. 확인을 위해 아래 링크에서 발생 장소별 데이터를 받아 오자. data 디렉토리에, 파일 이름은
02. crime_in_Seoul_location.csv로 저장했다.
https://www.data.go.kr/data/15054737/fileData.do
경찰청 서울특별시경찰청_5대범죄 발생 장소별 현황_20221231
2022년 5대범죄(살인, 강도, 강간 및 추행, 절도, 폭력) 발생장소별 현황으로 범죄명, 발생장소, 발생건수의 현황을 나타내는 통계입니다.
www.data.go.kr

13. 컬럼마다 .unique()로 컬럼들을 확인한 다음, 피벗테이블을 만들어 준다.


14. 정규화를 해준 뒤, 평균치를 기록한 '종합' 컬럼을 만든다.


15. 내림차순 정렬을 해주고, 시각화를 해준다. 히트맵 그래프를 먼저 만들어주자.
crime_loc_norm_sort = crime_loc_norm.sort_values(by='종합', ascending=False)
def drawGraph():
plt.figure(figsize=(10, 10))
sns.heatmap(crime_loc_norm_sort, annot=True, fmt='f', linewidths=0.5, cmap='RdPu')
plt.title('범죄와 발생 장소')
plt.show()
drawGraph()

'데이터분석 > 미니프로젝트 01. 서울시 CCTV 현황 분석' 카테고리의 다른 글
| 미니프로젝트 01-02-06. Folium 지도 시각화 (1) | 2024.03.29 |
|---|---|
| 미니프로젝트 01-02-05. 범죄현황데이터 시각화 (1) | 2024.03.26 |
| 미니프로젝트 01-02-04. 서울시 범죄현황 데이터 최종 정리 (3) | 2024.03.26 |
| 미니프로젝트 01-02-03. googlemaps에서 구별 정보를 얻어 데이터 정리, 구별데이터로 변경하기 (1) | 2024.03.26 |
| 미니프로젝트 01-02-02. 서울시 범죄현황 데이터를 피벗테이블로 정리, pip와 install 명령 (1) | 2024.03.24 |