import numpy as np
import pandas as pd
먼저 numpy와 pandas는 항상 import하는 모듈이라고 생각하면 됩니다. 이제 다운받은 데이터를 pandas로 읽어보겠습니다. crime_anal_police라는 변수에 저장합니다. 그내용을 보면 서울시 경찰서별로 살인,강도,강간,절도,폭력이라는 5대 범죄에 대해 발생 건수와 검거 건수를 가지고 있습니다.
crime_anal_police = pd.read_csv('./data/02. crime_in_Seoul.csv', thousands=',',
encoding='utf-8')
crime_anal_police.head()
Unnamed: 0 | Unnamed: 0.1 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 중부서 | 2 | 2 | 3 | 2 | 105 | 65 | 1395 | 477 | 1355 | 1170 | 중구 |
1 | 1 | 1 | 종로서 | 3 | 3 | 6 | 5 | 115 | 98 | 1070 | 413 | 1278 | 1070 | 종로구 |
2 | 2 | 2 | 남대문서 | 1 | 0 | 6 | 4 | 65 | 46 | 1153 | 382 | 869 | 794 | 중구 |
3 | 3 | 3 | 서대문서 | 2 | 2 | 5 | 4 | 154 | 124 | 1812 | 738 | 2056 | 1711 | 서대문구 |
4 | 4 | 4 | 혜화서 | 3 | 2 | 5 | 4 | 96 | 63 | 1114 | 424 | 1015 | 861 | 종로구 |
우리는 강남 3구가 안전한지를 확인하려는 것인데 데이터가 관서별로 되어있습니다. 서울시에는 한 구에 하나 혹은 두 군데의 경찰서가 위치해 있고, 구 이름과 다른 경찰서도 있습니다. 이 경찰서 목록을 소속 구별로 변경하고 싶습니다. 그러기 위해서는 먼저 경찰서 이름으로 구 정보를 알아야합니다. 양이 많지 않으니 직접 입력해도 되지만 우리는 프로그램으로 접근하도록 하겠습니다.
위치에 대한 검색 결과 중 주소와 위도, 경도 정보를 제공하는 서비스가 구글에 있습니다. Googole Maps API입니다. Google Maps API 홈페이지에 접속해서 Google Maps Geocoding API에 접근합니다. Google Maps는 다양한 API가 있습니다. 그중에 주소 검색과 위도, 경도 정보 정도를 얻을 수 있는 Geocoding API를 선택해서 '키 가져오기'로 키를 가져오면 됩니다. 터미널을 열고 pip install googlemaps라는 명령으로 파이썬에서 googlemaps를 사용할 수 있도록 합니다.
이제 Googlemaps를 import합니다. 그리고 googlemaps.Client로 키를 입력하면 됩니다.
pip install googlemaps
Collecting googlemaps Collecting requests<3.0,>=2.20.0 (from googlemaps) Using cached https://files.pythonhosted.org/packages/29/c1/24814557f1d22c56d50280771a17307e6bf87b70727d975fd6b2ce6b014a/requests-2.25.1-py2.py3-none-any.whl Collecting idna<3,>=2.5 (from requests<3.0,>=2.20.0->googlemaps) Using cached https://files.pythonhosted.org/packages/a2/38/928ddce2273eaa564f6f50de919327bf3a00f091b5baba8dfa9460f3a8a8/idna-2.10-py2.py3-none-any.whl Collecting urllib3<1.27,>=1.21.1 (from requests<3.0,>=2.20.0->googlemaps) Using cached https://files.pythonhosted.org/packages/09/c6/d3e3abe5b4f4f16cf0dfc9240ab7ce10c2baa0e268989a4e3ec19e90c84e/urllib3-1.26.4-py2.py3-none-any.whl Collecting chardet<5,>=3.0.2 (from requests<3.0,>=2.20.0->googlemaps) Using cached https://files.pythonhosted.org/packages/19/c7/fa589626997dd07bd87d9269342ccb74b1720384a4d739a1872bd84fbe68/chardet-4.0.0-py2.py3-none-any.whl Collecting certifi>=2017.4.17 (from requests<3.0,>=2.20.0->googlemaps) Using cached https://files.pythonhosted.org/packages/5e/a0/5f06e1e1d463903cf0c0eebeb751791119ed7a4b3737fdc9a77f1cdfb51f/certifi-2020.12.5-py2.py3-none-any.whl Installing collected packages: idna, urllib3, chardet, certifi, requests, googlemaps Successfully installed certifi-2020.12.5 chardet-4.0.0 googlemaps-4.4.5 idna-2.10 requests-2.25.1 urllib3-1.26.4 Note: you may need to restart the kernel to use updated packages.
import googlemaps
gmaps_key = "AIzaSyCAcnzbJzVPWOzOZ0hx-TGouJH5UvlO3sc"
gmaps = googlemaps.Client(key=gmaps_key)
gmaps.geocode('서울중부경찰서', language='ko')
[{'address_components': [{'long_name': '27', 'short_name': '27', 'types': ['premise']}, {'long_name': '수표로', 'short_name': '수표로', 'types': ['political', 'sublocality', 'sublocality_level_4']}, {'long_name': '을지로동', 'short_name': '을지로동', 'types': ['political', 'sublocality', 'sublocality_level_2']}, {'long_name': '중구', 'short_name': '중구', 'types': ['political', 'sublocality', 'sublocality_level_1']}, {'long_name': '서울특별시', 'short_name': '서울특별시', 'types': ['administrative_area_level_1', 'political']}, {'long_name': '대한민국', 'short_name': 'KR', 'types': ['country', 'political']}, {'long_name': '100-032', 'short_name': '100-032', 'types': ['postal_code']}], 'formatted_address': '대한민국 서울특별시 중구 을지로동 수표로 27', 'geometry': {'location': {'lat': 37.5636465, 'lng': 126.9895796}, 'location_type': 'ROOFTOP', 'viewport': {'northeast': {'lat': 37.56499548029149, 'lng': 126.9909285802915}, 'southwest': {'lat': 37.56229751970849, 'lng': 126.9882306197085}}}, 'place_id': 'ChIJc-9q5uSifDURLhQmr5wkXmc', 'plus_code': {'compound_code': 'HX7Q+FR 대한민국 서울특별시', 'global_code': '8Q98HX7Q+FR'}, 'types': ['establishment', 'point_of_interest', 'police']}]
'서울중부경찰서'라는 단어를 검색해 보았습니다. 그러면 formatted_address 항목에 주소가 나옵니다. lng와 lat에서 위도 경도 정보도 확인해 볼 수 있습니다. 나중에 지도 시각화에서 유용하게 사용할 수 있는 정보입니다.
station_name = []
for name in crime_anal_police["관서명"]:
station_name.append('서울' + str(name[:-1]) + '경찰서')
전에 코드를 보면 관서, 즉 경찰서의 이름이 중부서, 수서서처럼 되어 있습니다. 그러면 구글 검색에서 주소가 제대로 나오지 않아서 위 코드처럼 서울 ** 경찰서로 만들어야 하겠습니다. 코드를 실행하면 다음과 같이 나옵니다.
station_name
['서울중부경찰서', '서울종로경찰서', '서울남대문경찰서', '서울서대문경찰서', '서울혜화경찰서', '서울용산경찰서', '서울성북경찰서', '서울동대문경찰서', '서울마포경찰서', '서울영등포경찰서', '서울성동경찰서', '서울동작경찰서', '서울광진경찰서', '서울서부경찰서', '서울강북경찰서', '서울금천경찰서', '서울중랑경찰서', '서울강남경찰서', '서울관악경찰서', '서울강서경찰서', '서울강동경찰서', '서울종암경찰서', '서울구로경찰서', '서울서초경찰서', '서울양천경찰서', '서울송파경찰서', '서울노원경찰서', '서울방배경찰서', '서울은평경찰서', '서울도봉경찰서', '서울수서경찰서']
이름이 잘 만들어졌습니다
station_addreess = []
station_lat = []
station_lng = []
for name in station_name:
tmp = gmaps.geocode(name, language='ko')
station_addreess.append(tmp[0].get("formatted_address"))
tmp_loc = tmp[0].get("geometry")
station_lat.append(tmp_loc['location']['lat'])
station_lng.append(tmp_loc['location']['lng'])
print(name + '-->' + tmp[0].get("formatted_address"))
서울중부경찰서-->대한민국 서울특별시 중구 을지로동 수표로 27 서울종로경찰서-->대한민국 서울특별시 종로구 종로1.2.3.4가동 율곡로 46 서울남대문경찰서-->대한민국 서울특별시 중구 회현동 한강대로 410 서울서대문경찰서-->대한민국 서울특별시 서대문구 충현동 통일로 113 서울혜화경찰서-->대한민국 서울특별시 종로구 인의동 창경궁로 112-16 서울용산경찰서-->대한민국 서울특별시 용산구 원효로1가 백범로 329 서울성북경찰서-->대한민국 서울특별시 성북구 삼선동 보문로 170 서울동대문경찰서-->대한민국 서울특별시 동대문구 청량리동 약령시로21길 29 서울마포경찰서-->대한민국 서울특별시 마포구 아현동 마포대로 183 서울영등포경찰서-->대한민국 서울특별시 영등포구 영등포동1가 618-7 서울성동경찰서-->대한민국 서울특별시 성동구 행당동 왕십리광장로 9 서울동작경찰서-->대한민국 서울특별시 동작구 노량진1동 노량진로 148 서울광진경찰서-->대한민국 서울특별시 광진구 구의동 자양로 167 서울서부경찰서-->대한민국 서울특별시 은평구 녹번동 진흥로 58 서울강북경찰서-->대한민국 서울특별시 강북구 번1동 오패산로 406 서울금천경찰서-->대한민국 서울특별시 금천구 시흥1동 시흥대로73길 50 서울중랑경찰서-->대한민국 서울특별시 중랑구 신내동 신내역로3길 40-10 서울강남경찰서-->대한민국 서울특별시 강남구 대치동 테헤란로114길 11 서울관악경찰서-->대한민국 서울특별시 관악구 청룡동 관악로5길 33 서울강서경찰서-->대한민국 서울특별시 강서구 화곡동 화곡로 308 서울강동경찰서-->대한민국 서울특별시 강동구 성내1동 성내로 57 서울종암경찰서-->대한민국 서울특별시 성북구 종암동 종암로 135 서울구로경찰서-->대한민국 서울특별시 구로구 구로동 가마산로 235 서울서초경찰서-->대한민국 서울특별시 서초구 서초3동 반포대로 179 서울양천경찰서-->대한민국 서울특별시 양천구 신정6동 목동동로 99 서울송파경찰서-->대한민국 서울특별시 송파구 가락동 중대로 221 서울노원경찰서-->대한민국 서울특별시 노원구 하계동 노원로 283 서울방배경찰서-->대한민국 서울특별시 서초구 방배본동 동작대로 204 서울은평경찰서-->대한민국 서울특별시 은평구 불광동 연서로 365 서울도봉경찰서-->대한민국 서울특별시 도봉구 창4동 노해로 403 서울수서경찰서-->대한민국 서울특별시 강남구 개포동 개포로 617
위 결과를 얻었으니 각 경찰서별 주소를 모두 얻었습니다.
station_addreess
['대한민국 서울특별시 중구 을지로동 수표로 27', '대한민국 서울특별시 종로구 종로1.2.3.4가동 율곡로 46', '대한민국 서울특별시 중구 회현동 한강대로 410', '대한민국 서울특별시 서대문구 충현동 통일로 113', '대한민국 서울특별시 종로구 인의동 창경궁로 112-16', '대한민국 서울특별시 용산구 원효로1가 백범로 329', '대한민국 서울특별시 성북구 삼선동 보문로 170', '대한민국 서울특별시 동대문구 청량리동 약령시로21길 29', '대한민국 서울특별시 마포구 아현동 마포대로 183', '대한민국 서울특별시 영등포구 영등포동1가 618-7', '대한민국 서울특별시 성동구 행당동 왕십리광장로 9', '대한민국 서울특별시 동작구 노량진1동 노량진로 148', '대한민국 서울특별시 광진구 구의동 자양로 167', '대한민국 서울특별시 은평구 녹번동 진흥로 58', '대한민국 서울특별시 강북구 번1동 오패산로 406', '대한민국 서울특별시 금천구 시흥1동 시흥대로73길 50', '대한민국 서울특별시 중랑구 신내동 신내역로3길 40-10', '대한민국 서울특별시 강남구 대치동 테헤란로114길 11', '대한민국 서울특별시 관악구 청룡동 관악로5길 33', '대한민국 서울특별시 강서구 화곡동 화곡로 308', '대한민국 서울특별시 강동구 성내1동 성내로 57', '대한민국 서울특별시 성북구 종암동 종암로 135', '대한민국 서울특별시 구로구 구로동 가마산로 235', '대한민국 서울특별시 서초구 서초3동 반포대로 179', '대한민국 서울특별시 양천구 신정6동 목동동로 99', '대한민국 서울특별시 송파구 가락동 중대로 221', '대한민국 서울특별시 노원구 하계동 노원로 283', '대한민국 서울특별시 서초구 방배본동 동작대로 204', '대한민국 서울특별시 은평구 불광동 연서로 365', '대한민국 서울특별시 도봉구 창4동 노해로 403', '대한민국 서울특별시 강남구 개포동 개포로 617']
이렇게 전체 주소가 저장되었습니다.
station_lat
[37.5636465, 37.575548, 37.5547584, 37.5647439, 37.5718529, 37.5387099, 37.58977830000001, 37.58506149999999, 37.550814, 37.5153176, 37.5617303, 37.5130866, 37.542873, 37.6020914, 37.63730390000001, 37.4568722, 37.6186095, 37.5094352, 37.4743945, 37.5512463, 37.528511, 37.6020592, 37.494931, 37.4956054, 37.5167711, 37.5016941, 37.6425238, 37.4945959, 37.6280204, 37.6533589, 37.49349]
station_lng
[126.9895796, 126.9847471, 126.9734981, 126.9667705, 126.9989143, 126.9659183, 127.016589, 127.0457679, 126.954028, 126.905728, 127.0364217, 126.9428498, 127.083821, 126.9213528, 127.0273399, 126.8970429, 127.1045734, 127.0669578, 126.9513489, 126.8499633, 127.1268224, 127.0321577, 126.886731, 127.0052504, 126.8656996, 127.1272481, 127.0717076, 126.9831279, 126.9287899, 127.052682, 127.0772119]
경도를 모두 얻었습니다.
gu_name = []
for name in station_addreess:
tmp = name.split()
tmp_gu = [gu for gu in tmp if gu[-1] == '구'][0]
gu_name.append(tmp_gu)
crime_anal_police['구별'] = gu_name
crime_anal_police.head()
Unnamed: 0 | Unnamed: 0.1 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 중부서 | 2 | 2 | 3 | 2 | 105 | 65 | 1395 | 477 | 1355 | 1170 | 중구 |
1 | 1 | 1 | 종로서 | 3 | 3 | 6 | 5 | 115 | 98 | 1070 | 413 | 1278 | 1070 | 종로구 |
2 | 2 | 2 | 남대문서 | 1 | 0 | 6 | 4 | 65 | 46 | 1153 | 382 | 869 | 794 | 중구 |
3 | 3 | 3 | 서대문서 | 2 | 2 | 5 | 4 | 154 | 124 | 1812 | 738 | 2056 | 1711 | 서대문구 |
4 | 4 | 4 | 혜화서 | 3 | 2 | 5 | 4 | 96 | 63 | 1114 | 424 | 1015 | 861 | 종로구 |
전 코드에서 저장한 주소를 띄어쓰기, 공백으로 나누고(split) 두 번째 단어를 선택해서 구별이라는 컬럼으로 저장합니다. 이렇게 하면 관서명에서 google maps의 도움을 받아 구별 이름으로 저장할 수 있게 되었습니다.
crime_anal_police[crime_anal_police['관서명']=='금천서']
Unnamed: 0 | Unnamed: 0.1 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
15 | 15 | 15 | 금천서 | 3 | 4 | 6 | 6 | 151 | 122 | 1567 | 888 | 2054 | 1776 | 금천구 |
crime_anal_police.loc[crime_anal_police['관서명']=='금천서', ['구별']] = '금천서'
crime_anal_police[crime_anal_police['관서명']=='금천서']
Unnamed: 0 | Unnamed: 0.1 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
15 | 15 | 15 | 금천서 | 3 | 4 | 6 | 6 | 151 | 122 | 1567 | 888 | 2054 | 1776 | 금천서 |
관악구로 되어 있는 것을 금천구로 변경합니다.
crime_anal_police.to_csv('../DataScience_study/data/02. crime_in_Seoul.csv',
sep=',', encoding='utf-8')
인터넷에서 자료를 가져오는 경우는 이 과정을 단순한 프로그램 오류로 다시 수행할 때 발생하는 정신적 스트레스를 피하기 위해서 적당한 이름으로 저장합니다.
crime_anal_police.head()
Unnamed: 0 | Unnamed: 0.1 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 중부서 | 2 | 2 | 3 | 2 | 105 | 65 | 1395 | 477 | 1355 | 1170 | 중구 |
1 | 1 | 1 | 종로서 | 3 | 3 | 6 | 5 | 115 | 98 | 1070 | 413 | 1278 | 1070 | 종로구 |
2 | 2 | 2 | 남대문서 | 1 | 0 | 6 | 4 | 65 | 46 | 1153 | 382 | 869 | 794 | 중구 |
3 | 3 | 3 | 서대문서 | 2 | 2 | 5 | 4 | 154 | 124 | 1812 | 738 | 2056 | 1711 | 서대문구 |
4 | 4 | 4 | 혜화서 | 3 | 2 | 5 | 4 | 96 | 63 | 1114 | 424 | 1015 | 861 | 종로구 |
현재까지 우리가 확보한 데이터의 구조가 관서명을 기초로 했기 때문에 구별 컬럼에서는 같은 구 이름이 두 번 있을수 있습니다. 예를 들면 강남구에는 경찰서가 두 개이니 방금전 코드의 테이블에서는 강남구가 두 번 등장하게 됩니다. 우리는 이부분을 어떻게 해야 할지 공부해야 합니다.
crime_anal_raw = pd.read_csv('./data/02. crime_in_Seoul_include_gu_name.csv',
encoding = 'utf-8')
crime_anal_raw.head()
Unnamed: 0 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 중부서 | 2 | 2 | 3 | 2 | 105 | 65 | 1395 | 477 | 1355 | 1170 | 중구 |
1 | 1 | 종로서 | 3 | 3 | 6 | 5 | 115 | 98 | 1070 | 413 | 1278 | 1070 | 종로구 |
2 | 2 | 남대문서 | 1 | 0 | 6 | 4 | 65 | 46 | 1153 | 382 | 869 | 794 | 중구 |
3 | 3 | 서대문서 | 2 | 2 | 5 | 4 | 154 | 124 | 1812 | 738 | 2056 | 1711 | 서대문구 |
4 | 4 | 혜화서 | 3 | 2 | 5 | 4 | 96 | 63 | 1114 | 424 | 1015 | 861 | 종로구 |
pandas의 pivot_table 이용하여 원 데이터를 관서별에서 구별로 바꾸면 다음과 같습니다.
crime_anal_raw = pd.read_csv('./data/02. crime_in_Seoul_include_gu_name.csv',
encoding='utf-8', index_col = 0)
crime_anal = pd.pivot_table(crime_anal_raw, index='구별', aggfunc=np.sum)
crime_anal.head()
강간 검거 | 강간 발생 | 강도 검거 | 강도 발생 | 살인 검거 | 살인 발생 | 절도 검거 | 절도 발생 | 폭력 검거 | 폭력 발생 | |
---|---|---|---|---|---|---|---|---|---|---|
구별 | ||||||||||
강남구 | 349 | 449 | 18 | 21 | 10 | 13 | 1650 | 3850 | 3705 | 4284 |
강동구 | 123 | 156 | 8 | 6 | 3 | 4 | 789 | 2366 | 2248 | 2712 |
강북구 | 126 | 153 | 13 | 14 | 8 | 7 | 618 | 1434 | 2348 | 2649 |
관악구 | 221 | 320 | 14 | 12 | 8 | 9 | 827 | 2706 | 2642 | 3298 |
광진구 | 220 | 240 | 26 | 14 | 4 | 4 | 1277 | 3026 | 2180 | 2625 |
crime_anal['강간검거율'] = crime_anal['강간 검거']/crime_anal['강간 발생']*100
crime_anal['강도검거율'] = crime_anal['강도 검거']/crime_anal['강도 발생']*100
crime_anal['살인검거율'] = crime_anal['살인 검거']/crime_anal['살인 발생']*100
crime_anal['절도검거율'] = crime_anal['절도 검거']/crime_anal['절도 발생']*100
crime_anal['폭력검거율'] = crime_anal['폭력 검거']/crime_anal['폭력 발생']*100
crime_anal.head()
강간 검거 | 강간 발생 | 강도 검거 | 강도 발생 | 살인 검거 | 살인 발생 | 절도 검거 | 절도 발생 | 폭력 검거 | 폭력 발생 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
구별 | |||||||||||||||
강남구 | 349 | 449 | 18 | 21 | 10 | 13 | 1650 | 3850 | 3705 | 4284 | 77.728285 | 85.714286 | 76.923077 | 42.857143 | 86.484594 |
강동구 | 123 | 156 | 8 | 6 | 3 | 4 | 789 | 2366 | 2248 | 2712 | 78.846154 | 133.333333 | 75.000000 | 33.347422 | 82.890855 |
강북구 | 126 | 153 | 13 | 14 | 8 | 7 | 618 | 1434 | 2348 | 2649 | 82.352941 | 92.857143 | 114.285714 | 43.096234 | 88.637222 |
관악구 | 221 | 320 | 14 | 12 | 8 | 9 | 827 | 2706 | 2642 | 3298 | 69.062500 | 116.666667 | 88.888889 | 30.561715 | 80.109157 |
광진구 | 220 | 240 | 26 | 14 | 4 | 4 | 1277 | 3026 | 2180 | 2625 | 91.666667 | 185.714286 | 100.000000 | 42.200925 | 83.047619 |
추가로 각 범죄별 검거율을 계산하고, 검거 건수는 검거율로 대체할 수 있어서 삭제하기로 합니다.
그런데 검거율에 이상한 점이 있습니다. 100이 넘는 숫자들이 보입니다. 아마도 그 전년도 발생건수에 대한 검거도 포함되니 그런 듯합니다.
여기서는 깊은 고민없이 그냥 100이 넘는 숫자는 다 100으로 처리합니다.
con_list = ['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율']
for column in con_list:
crime_anal.loc[crime_anal[column] > 100, column] = 100
crime_anal.head()
강간 검거 | 강간 발생 | 강도 검거 | 강도 발생 | 살인 검거 | 살인 발생 | 절도 검거 | 절도 발생 | 폭력 검거 | 폭력 발생 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
구별 | |||||||||||||||
강남구 | 349 | 449 | 18 | 21 | 10 | 13 | 1650 | 3850 | 3705 | 4284 | 77.728285 | 85.714286 | 76.923077 | 42.857143 | 86.484594 |
강동구 | 123 | 156 | 8 | 6 | 3 | 4 | 789 | 2366 | 2248 | 2712 | 78.846154 | 100.000000 | 75.000000 | 33.347422 | 82.890855 |
강북구 | 126 | 153 | 13 | 14 | 8 | 7 | 618 | 1434 | 2348 | 2649 | 82.352941 | 92.857143 | 100.000000 | 43.096234 | 88.637222 |
관악구 | 221 | 320 | 14 | 12 | 8 | 9 | 827 | 2706 | 2642 | 3298 | 69.062500 | 100.000000 | 88.888889 | 30.561715 | 80.109157 |
광진구 | 220 | 240 | 26 | 14 | 4 | 4 | 1277 | 3026 | 2180 | 2625 | 91.666667 | 100.000000 | 100.000000 | 42.200925 | 83.047619 |
이제 뒤에 붙은 발생이라는 단어를 삭제하겠습니다.
crime_anal.rename(columns = {'강간 발생':'강간',
'강도 발생':'강도',
'살인 발생':'살인',
'절도 발생':'절도',
'폭력 발생':'폭력'}, inplace=True)
crime_anal.head()
강간 검거 | 강간 | 강도 검거 | 강도 | 살인 검거 | 살인 | 절도 검거 | 절도 | 폭력 검거 | 폭력 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
구별 | |||||||||||||||
강남구 | 349 | 449 | 18 | 21 | 10 | 13 | 1650 | 3850 | 3705 | 4284 | 77.728285 | 85.714286 | 76.923077 | 42.857143 | 86.484594 |
강동구 | 123 | 156 | 8 | 6 | 3 | 4 | 789 | 2366 | 2248 | 2712 | 78.846154 | 100.000000 | 75.000000 | 33.347422 | 82.890855 |
강북구 | 126 | 153 | 13 | 14 | 8 | 7 | 618 | 1434 | 2348 | 2649 | 82.352941 | 92.857143 | 100.000000 | 43.096234 | 88.637222 |
관악구 | 221 | 320 | 14 | 12 | 8 | 9 | 827 | 2706 | 2642 | 3298 | 69.062500 | 100.000000 | 88.888889 | 30.561715 | 80.109157 |
광진구 | 220 | 240 | 26 | 14 | 4 | 4 | 1277 | 3026 | 2180 | 2625 | 91.666667 | 100.000000 | 100.000000 | 42.200925 | 83.047619 |
이렇게 컬럼의 이름은 rename으로 변경할 수 있습니다.
각 항목의 최대값을 1로 두면 추후 범죄 발생 건수를 종합적으로 비교할 때 편리할 것입니다. 그래서 강간,강도,살인,절도,폭력에 대해 각 컬럼별로 '정규화(normalize)'하도록 하겠습니다.
!pip3 install sklearn
Collecting sklearn Downloading https://files.pythonhosted.org/packages/1e/7a/dbb3be0ce9bd5c8b7e3d87328e79063f8b263b2b1bfa4774cb1147bfcd3f/sklearn-0.0.tar.gz Collecting scikit-learn (from sklearn) Downloading https://files.pythonhosted.org/packages/a4/11/e5862273960aef46cf98e571db5433bdabe5e816ef3317260dcdabc9b438/scikit_learn-0.24.1-cp36-cp36m-manylinux1_x86_64.whl (20.0MB) 100% |████████████████████████████████| 20.0MB 11kB/s ta 0:00:015 Collecting numpy>=1.13.3 (from scikit-learn->sklearn) Using cached https://files.pythonhosted.org/packages/45/b2/6c7545bb7a38754d63048c7696804a0d947328125d81bf12beaa692c3ae3/numpy-1.19.5-cp36-cp36m-manylinux1_x86_64.whl Collecting threadpoolctl>=2.0.0 (from scikit-learn->sklearn) Downloading https://files.pythonhosted.org/packages/f7/12/ec3f2e203afa394a149911729357aa48affc59c20e2c1c8297a60f33f133/threadpoolctl-2.1.0-py3-none-any.whl Collecting joblib>=0.11 (from scikit-learn->sklearn) Downloading https://files.pythonhosted.org/packages/55/85/70c6602b078bd9e6f3da4f467047e906525c355a4dacd4f71b97a35d9897/joblib-1.0.1-py3-none-any.whl (303kB) 100% |████████████████████████████████| 307kB 20kB/s ta 0:00:01 Collecting scipy>=0.19.1 (from scikit-learn->sklearn) Using cached https://files.pythonhosted.org/packages/c8/89/63171228d5ced148f5ced50305c89e8576ffc695a90b58fe5bb602b910c2/scipy-1.5.4-cp36-cp36m-manylinux1_x86_64.whl Building wheels for collected packages: sklearn Running setup.py bdist_wheel for sklearn ... done Stored in directory: /home/wntkdl94/.cache/pip/wheels/76/03/bb/589d421d27431bcd2c6da284d5f2286c8e3b2ea3cf1594c074 Successfully built sklearn Installing collected packages: numpy, threadpoolctl, joblib, scipy, scikit-learn, sklearn Successfully installed joblib-1.0.1 numpy-1.19.5 scikit-learn-0.24.1 scipy-1.5.4 sklearn-0.0 threadpoolctl-2.1.0
from sklearn import preprocessing
col = ['강간', '강도', '살인', '절도', '폭력']
x = crime_anal[col].values
min_max_scaler = preprocessing.MinMaxScaler()
x_scaled = min_max_scaler.fit_transform(x.astype(float))
crime_anal_norm = pd.DataFrame(x_scaled, columns=col, index=crime_anal.index)
col2 = ['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율']
crime_anal_norm[col2] = crime_anal[col2]
crime_anal_norm.head()
강간 | 강도 | 살인 | 절도 | 폭력 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | |
---|---|---|---|---|---|---|---|---|---|---|
구별 | ||||||||||
강남구 | 1.000000 | 0.941176 | 0.916667 | 0.953472 | 0.661386 | 77.728285 | 85.714286 | 76.923077 | 42.857143 | 86.484594 |
강동구 | 0.155620 | 0.058824 | 0.166667 | 0.445775 | 0.289667 | 78.846154 | 100.000000 | 75.000000 | 33.347422 | 82.890855 |
강북구 | 0.146974 | 0.529412 | 0.416667 | 0.126924 | 0.274769 | 82.352941 | 92.857143 | 100.000000 | 43.096234 | 88.637222 |
관악구 | 0.628242 | 0.411765 | 0.583333 | 0.562094 | 0.428234 | 69.062500 | 100.000000 | 88.888889 | 30.561715 | 80.109157 |
광진구 | 0.397695 | 0.529412 | 0.166667 | 0.671570 | 0.269094 | 91.666667 | 100.000000 | 100.000000 | 42.200925 | 83.047619 |
파이썬의 머신러닝에 관한 모듈로 유명한 scikit learn에 있는 전처리 도구에는 최소값,최대값을 이용해서 정규화시키는 함수가 있습니다.
result_CCTV = pd.read_csv('./data/01. CCTV_result.csv', encoding='UTF-8',
index_col='구별')
crime_anal_norm[['인구수', 'CCTV']] = result_CCTV[['인구수', '소계']]
crime_anal_norm.head()
강간 | 강도 | 살인 | 절도 | 폭력 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | 인구수 | CCTV | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
구별 | ||||||||||||
강남구 | 1.000000 | 0.941176 | 0.916667 | 0.953472 | 0.661386 | 77.728285 | 85.714286 | 76.923077 | 42.857143 | 86.484594 | 570500.0 | 2780 |
강동구 | 0.155620 | 0.058824 | 0.166667 | 0.445775 | 0.289667 | 78.846154 | 100.000000 | 75.000000 | 33.347422 | 82.890855 | 453233.0 | 773 |
강북구 | 0.146974 | 0.529412 | 0.416667 | 0.126924 | 0.274769 | 82.352941 | 92.857143 | 100.000000 | 43.096234 | 88.637222 | 330192.0 | 748 |
관악구 | 0.628242 | 0.411765 | 0.583333 | 0.562094 | 0.428234 | 69.062500 | 100.000000 | 88.888889 | 30.561715 | 80.109157 | 525515.0 | 1496 |
광진구 | 0.397695 | 0.529412 | 0.166667 | 0.671570 | 0.269094 | 91.666667 | 100.000000 | 100.000000 | 42.200925 | 83.047619 | 372164.0 | 707 |
CCTV_result.csv를 읽어서 그 속에서 구별 인구수와 CCTV 개수를 가지고 오겠습니다.
col = ['강간', '강도', '살인', '절도', '폭력']
crime_anal_norm['범죄'] = np.sum(crime_anal_norm[col], axis=1)
crime_anal_norm.head()
강간 | 강도 | 살인 | 절도 | 폭력 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | 인구수 | CCTV | 범죄 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
구별 | |||||||||||||
강남구 | 1.000000 | 0.941176 | 0.916667 | 0.953472 | 0.661386 | 77.728285 | 85.714286 | 76.923077 | 42.857143 | 86.484594 | 570500.0 | 2780 | 4.472701 |
강동구 | 0.155620 | 0.058824 | 0.166667 | 0.445775 | 0.289667 | 78.846154 | 100.000000 | 75.000000 | 33.347422 | 82.890855 | 453233.0 | 773 | 1.116551 |
강북구 | 0.146974 | 0.529412 | 0.416667 | 0.126924 | 0.274769 | 82.352941 | 92.857143 | 100.000000 | 43.096234 | 88.637222 | 330192.0 | 748 | 1.494746 |
관악구 | 0.628242 | 0.411765 | 0.583333 | 0.562094 | 0.428234 | 69.062500 | 100.000000 | 88.888889 | 30.561715 | 80.109157 | 525515.0 | 1496 | 2.613667 |
광진구 | 0.397695 | 0.529412 | 0.166667 | 0.671570 | 0.269094 | 91.666667 | 100.000000 | 100.000000 | 42.200925 | 83.047619 | 372164.0 | 707 | 2.034438 |
또한 발생 건수의 합을 '범죄'라는 항목으로 두고 이를 합하겠습니다. 만약 정규화하지 않았다면 몇 천건의 절도에 수십 건의 살인의 비중이 애매했겠지만 정규화를 통해 그 부분은 유리해졌습니다. 단,여기서는 범죄의 경중을 논하자는 것이 절대 아닙니다.
col = ['강간검거율','강도검거율','살인검거율','절도검거율','폭력검거율']
crime_anal_norm['검거'] = np.sum(crime_anal_norm[col], axis=1)
crime_anal_norm
강간 | 강도 | 살인 | 절도 | 폭력 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | 인구수 | CCTV | 범죄 | 검거 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
구별 | ||||||||||||||
강남구 | 1.000000 | 0.941176 | 0.916667 | 0.953472 | 0.661386 | 77.728285 | 85.714286 | 76.923077 | 42.857143 | 86.484594 | 570500.0 | 2780 | 4.472701 | 369.707384 |
강동구 | 0.155620 | 0.058824 | 0.166667 | 0.445775 | 0.289667 | 78.846154 | 100.000000 | 75.000000 | 33.347422 | 82.890855 | 453233.0 | 773 | 1.116551 | 370.084431 |
강북구 | 0.146974 | 0.529412 | 0.416667 | 0.126924 | 0.274769 | 82.352941 | 92.857143 | 100.000000 | 43.096234 | 88.637222 | 330192.0 | 748 | 1.494746 | 406.943540 |
관악구 | 0.628242 | 0.411765 | 0.583333 | 0.562094 | 0.428234 | 69.062500 | 100.000000 | 88.888889 | 30.561715 | 80.109157 | 525515.0 | 1496 | 2.613667 | 368.622261 |
광진구 | 0.397695 | 0.529412 | 0.166667 | 0.671570 | 0.269094 | 91.666667 | 100.000000 | 100.000000 | 42.200925 | 83.047619 | 372164.0 | 707 | 2.034438 | 416.915211 |
구로구 | 0.515850 | 0.588235 | 0.500000 | 0.435169 | 0.359423 | 58.362989 | 73.333333 | 75.000000 | 38.072805 | 80.877951 | 447874.0 | 1561 | 2.398678 | 325.647079 |
금천구 | 0.141210 | 0.058824 | 0.083333 | 0.172426 | 0.134074 | 80.794702 | 100.000000 | 100.000000 | 56.668794 | 86.465433 | 255082.0 | 1015 | 0.589867 | 423.928929 |
노원구 | 0.273775 | 0.117647 | 0.666667 | 0.386589 | 0.292268 | 61.421320 | 100.000000 | 100.000000 | 36.525308 | 85.530665 | 569384.0 | 1265 | 1.736946 | 383.477292 |
도봉구 | 0.000000 | 0.235294 | 0.083333 | 0.000000 | 0.000000 | 100.000000 | 100.000000 | 100.000000 | 44.967074 | 87.626093 | 348646.0 | 485 | 0.318627 | 432.593167 |
동대문구 | 0.204611 | 0.470588 | 0.250000 | 0.314061 | 0.250887 | 84.393064 | 100.000000 | 100.000000 | 41.090358 | 87.401884 | 369496.0 | 1294 | 1.490147 | 412.885306 |
동작구 | 0.527378 | 0.235294 | 0.250000 | 0.274376 | 0.100024 | 48.771930 | 55.555556 | 100.000000 | 35.442359 | 83.089005 | 412520.0 | 1091 | 1.387071 | 322.858850 |
마포구 | 0.553314 | 0.529412 | 0.500000 | 0.510434 | 0.353748 | 84.013605 | 71.428571 | 100.000000 | 31.819961 | 84.445189 | 389649.0 | 574 | 2.446908 | 371.707327 |
서대문구 | 0.149856 | 0.000000 | 0.000000 | 0.256244 | 0.134547 | 80.519481 | 80.000000 | 100.000000 | 40.728477 | 83.219844 | 327163.0 | 962 | 0.540647 | 384.467802 |
서초구 | 0.838617 | 0.235294 | 0.500000 | 0.537804 | 0.215654 | 63.358779 | 66.666667 | 75.000000 | 41.404175 | 87.453105 | 450310.0 | 1930 | 2.327368 | 333.882725 |
성동구 | 0.069164 | 0.235294 | 0.166667 | 0.186110 | 0.029558 | 94.444444 | 88.888889 | 100.000000 | 37.149969 | 86.538462 | 311244.0 | 1062 | 0.686793 | 407.021764 |
성북구 | 0.138329 | 0.000000 | 0.250000 | 0.247007 | 0.170726 | 82.666667 | 80.000000 | 100.000000 | 41.512605 | 83.974649 | 461260.0 | 1464 | 0.806061 | 388.153921 |
송파구 | 0.340058 | 0.470588 | 0.750000 | 0.744441 | 0.427524 | 80.909091 | 76.923077 | 90.909091 | 34.856437 | 84.552352 | 667483.0 | 618 | 2.732611 | 368.150048 |
양천구 | 0.806916 | 0.823529 | 0.666667 | 1.000000 | 1.000000 | 77.486911 | 84.210526 | 100.000000 | 48.469644 | 83.065080 | 479978.0 | 2034 | 4.297113 | 393.232162 |
영등포구 | 0.556196 | 1.000000 | 1.000000 | 0.650359 | 0.493024 | 62.033898 | 90.909091 | 85.714286 | 32.995951 | 82.894737 | 402985.0 | 904 | 3.699580 | 354.547963 |
용산구 | 0.265130 | 0.529412 | 0.250000 | 0.169004 | 0.133128 | 89.175258 | 100.000000 | 100.000000 | 37.700706 | 83.121951 | 244203.0 | 1624 | 1.346674 | 409.997915 |
은평구 | 0.184438 | 0.235294 | 0.083333 | 0.291139 | 0.275715 | 84.939759 | 66.666667 | 100.000000 | 37.147335 | 86.920467 | 494388.0 | 1873 | 1.069920 | 375.674229 |
종로구 | 0.314121 | 0.352941 | 0.333333 | 0.383510 | 0.190589 | 76.303318 | 81.818182 | 83.333333 | 38.324176 | 84.212822 | 162820.0 | 1002 | 1.574494 | 363.991830 |
중구 | 0.195965 | 0.235294 | 0.083333 | 0.508040 | 0.174273 | 65.294118 | 66.666667 | 66.666667 | 33.712716 | 88.309353 | 133240.0 | 671 | 1.196905 | 320.649519 |
중랑구 | 0.244957 | 0.352941 | 0.916667 | 0.366746 | 0.321589 | 79.144385 | 81.818182 | 92.307692 | 38.829040 | 84.545135 | 414503.0 | 660 | 2.202900 | 376.644434 |
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
x = np.linspace(0, 14, 100)
y1 = np.sin(x)
y2 = 2*np.sin(x+0.5)
y3 = 3*np.sin(x+1.0)
y4 = 4*np.sin(x+1.5)
plt.figure(figsize=(10,6))
plt.plot(x,y1, x,y2, x,y3, x,y4)
plt.show()
간단하게 몇 개의 사인 함수를 그려보겠습니다. seaborn을 import할 때는 matplotlib도 같이 import되어 있어야 합니다,
sns.set_style("whitegrid")
plt.figure(figsize=(10,6))
plt.plot(x,y1, x,y2, x,y3, x,y4)
plt.show()
seaborn은 whitegrid라는 스타일을 지원합니다.
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
sns.set_style("whitegrid")
%matplotlib inline
tips = sns.load_dataset("tips")
tips.head(5)
total_bill | tip | sex | smoker | day | time | size | |
---|---|---|---|---|---|---|---|
0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
Tips라는 데이터셋입니다. 요일별 점심,저녁,흡연 여부와 식사 금액과 팁을 정리한 데이터입니다.
plt.figure(figsize=(8,6))
sns.boxplot(x="day", y="total_bill", data=tips)
plt.show()
이렇게 boxplot을 그리는데 x축에는 요일로, y축에는 전체 금액을 그릴 수 있습니다.
plt.figure(figsize=(8,6))
sns.boxplot(x="day", y="total_bill", hue="smoker", data=tips, palette="Set3")
plt.show()
hue라는 옵션을 이용해서 구분할 수 있습니다. 이코드의 경우는 흡연 여부로 구분한 것입니다. 흡연자가 결제 금액의 범위가 크네요.
sns.set_style("darkgrid")
sns.lmplot(x="total_bill", y="tip", data=tips, size=7)
plt.show()
/home/wntkdl94/.local/lib/python3.6/site-packages/seaborn/regression.py:580: UserWarning: The `size` parameter has been renamed to `height`; please update your code. warnings.warn(msg, UserWarning)
이번에는 darkgrid 스타일로 하고 lmplot을 그렸습니다. 데이터를 scatter처럼 그리고 직선으로 regression한 그림도 같이 그려주고 유효범위도 ci로 잡아줍니다.
sns.lmplot(x="total_bill", y="tip", hue="smoker", data=tips, palette="Set1", size=7)
plt.show()
/home/wntkdl94/.local/lib/python3.6/site-packages/seaborn/regression.py:580: UserWarning: The `size` parameter has been renamed to `height`; please update your code. warnings.warn(msg, UserWarning)
lmplot도 hue 옵션을 가질 수 있으며 마리 준비된 palette로 색상을 지정할 수 있습니다.
flights = sns.load_dataset("flights")
flights.head(5)
year | month | passengers | |
---|---|---|---|
0 | 1949 | Jan | 112 |
1 | 1949 | Feb | 118 |
2 | 1949 | Mar | 132 |
3 | 1949 | Apr | 129 |
4 | 1949 | May | 121 |
이번에는 연도 및 월별 항공기 승객수를 기록한 데이터를 가져오겠습니다.
flights = flights.pivot("month", "year", "passengers")
flights.head(5)
year | 1949 | 1950 | 1951 | 1952 | 1953 | 1954 | 1955 | 1956 | 1957 | 1958 | 1959 | 1960 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
month | ||||||||||||
Jan | 112 | 115 | 145 | 171 | 196 | 204 | 242 | 284 | 315 | 340 | 360 | 417 |
Feb | 118 | 126 | 150 | 180 | 196 | 188 | 233 | 277 | 301 | 318 | 342 | 391 |
Mar | 132 | 141 | 178 | 193 | 236 | 235 | 267 | 317 | 356 | 362 | 406 | 419 |
Apr | 129 | 135 | 163 | 181 | 235 | 227 | 269 | 313 | 348 | 348 | 396 | 461 |
May | 121 | 125 | 172 | 183 | 229 | 234 | 270 | 318 | 355 | 363 | 420 | 472 |
pivot 기능으로 간편하게 월별, 연도별로 구분할 수 있습니다.
plt.figure(figsize=(10,8))
sns.heatmap(flights, annot=True, fmt="d")
plt.show()
heatmap이라는 도구를 이용하면 이런 종류의 데이터는 그 경향을 설명하기 참 좋습니다.
sns.set(style="ticks")
iris = sns.load_dataset("iris")
iris.head(10)
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa |
5 | 5.4 | 3.9 | 1.7 | 0.4 | setosa |
6 | 4.6 | 3.4 | 1.4 | 0.3 | setosa |
7 | 5.0 | 3.4 | 1.5 | 0.2 | setosa |
8 | 4.4 | 2.9 | 1.4 | 0.2 | setosa |
9 | 4.9 | 3.1 | 1.5 | 0.1 | setosa |
이번에는 머신러닝에서 중요하게 다뤄지는 아이리스 꽃에 대한 데이터를 가지고 옵니다. 꽃잎,꽃받침의 너비와 폭을 가지고 그종을 구분할 수 있는지를 알아보겠습니다.
sns.pairplot(iris, hue="species")
plt.show()
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
import platform
path = "c:/Windows/Fonts/malgun.ttf"
from matplotlib import font_manager, rc
if platform.system() == 'Darwin':
rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
font_name = font_manager.FontProperties(fname=path).get_name()
rc('font', family=font_name)
else:
print('Unknown system... sorry~~~~')
Unknown system... sorry~~~~
pairplot으로 강도,살인,폭련 가의 상관관계를 그래프로 보겠습니다.
sns.pairplot(crime_anal_norm, vars=["강도", "살인", "폭력"], kind='reg', size=3)
plt.show()
/home/wntkdl94/.local/lib/python3.6/site-packages/seaborn/axisgrid.py:1969: UserWarning: The `size` parameter has been renamed to `height`; please update your code. warnings.warn(msg, UserWarning) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44053 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 46020 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 54253 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 47141 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44053 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 46020 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 54253 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 47141 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44053 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 46020 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 54253 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 47141 missing from current font. font.set_text(s, 0, flags=flags)
강도와 폭력,살인과 폭력,강도와 살인 모두 양의 상관관계가 보입니다.
sns.pairplot(crime_anal_norm, x_vars=["인구수", "CCTV"],
y_vars=["살인", "강도"], kind='reg', size=3)
plt.show()
/home/wntkdl94/.local/lib/python3.6/site-packages/seaborn/axisgrid.py:1969: UserWarning: The `size` parameter has been renamed to `height`; please update your code. warnings.warn(msg, UserWarning) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44396 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49688 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44053 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 46020 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44396 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49688 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44053 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 46020 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44396 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49688 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44053 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 46020 missing from current font. font.set_text(s, 0, flags=flags)
인구수와 CCTV개수, 그리고 살인과 강도에 대해 조사했습니다. 전체적인 상관계수는 CCTV와 살인의 관계가 낮을지 몰라도 CCTV가 없을 때 살인이 많이 일어나는 구간이 있습니다. 즉, CCTV개수를 기준으로 좌측면에 살인과 강도의 높은 수를 갖는 데이터가 보입니다.
sns.pairplot(crime_anal_norm,
x_vars=["인구수", "CCTV"],
y_vars=["살인검거율", "폭력검거율"], kind='reg', size=3)
plt.show()
/home/wntkdl94/.local/lib/python3.6/site-packages/seaborn/axisgrid.py:1969: UserWarning: The `size` parameter has been renamed to `height`; please update your code. warnings.warn(msg, UserWarning) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44160 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44144 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 50984 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44396 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49688 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 54253 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 47141 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44160 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44144 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 50984 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44396 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49688 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 54253 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 47141 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44160 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44144 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 50984 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44396 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49688 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 54253 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 47141 missing from current font. font.set_text(s, 0, flags=flags)
그런데 살인 및 폭력 검거율과 CCTV의 관계가 양의 상관관계가 아닙니다. 오히려 음의 상관계수도 보입니다. 또 인구수와 살인 및 폭력 검거율도 음의 상관관계가 관찰됩니다.
tmp_max = crime_anal_norm['검거'].max()
crime_anal_norm['검거'] = crime_anal_norm['검거'] / tmp_max * 100
crime_anal_norm_sort = crime_anal_norm.sort_values(by='검거', ascending=False)
crime_anal_norm_sort.head()
강간 | 강도 | 살인 | 절도 | 폭력 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | 인구수 | CCTV | 범죄 | 검거 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
구별 | ||||||||||||||
도봉구 | 0.000000 | 0.235294 | 0.083333 | 0.000000 | 0.000000 | 100.000000 | 100.0 | 100.0 | 44.967074 | 87.626093 | 348646.0 | 485 | 0.318627 | 100.000000 |
금천구 | 0.141210 | 0.058824 | 0.083333 | 0.172426 | 0.134074 | 80.794702 | 100.0 | 100.0 | 56.668794 | 86.465433 | 255082.0 | 1015 | 0.589867 | 97.997139 |
광진구 | 0.397695 | 0.529412 | 0.166667 | 0.671570 | 0.269094 | 91.666667 | 100.0 | 100.0 | 42.200925 | 83.047619 | 372164.0 | 707 | 2.034438 | 96.375820 |
동대문구 | 0.204611 | 0.470588 | 0.250000 | 0.314061 | 0.250887 | 84.393064 | 100.0 | 100.0 | 41.090358 | 87.401884 | 369496.0 | 1294 | 1.490147 | 95.444250 |
용산구 | 0.265130 | 0.529412 | 0.250000 | 0.169004 | 0.133128 | 89.175258 | 100.0 | 100.0 | 37.700706 | 83.121951 | 244203.0 | 1624 | 1.346674 | 94.776790 |
이쯤에서 검거율의 합계인 검거 항목 최고 값을 100으로 한정하고 그 값으로 정렬한 다음,
target_col = ['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율']
crime_anal_norm_sort = crime_anal_norm.sort_values(by='검거', ascending=False)
plt.figure(figsize = (10,10))
sns.heatmap(crime_anal_norm_sort[target_col], annot=True, fmt='f', linewidths=.5)
plt.title('범죄 검거 비율 (정규화된 검거의 합으로 정렬)')
plt.show()
/home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44053 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44036 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44160 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44144 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 50984 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 46020 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51208 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 54253 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 47141 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44053 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44036 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44160 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44144 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 50984 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 46020 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49332 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51064 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51208 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 54253 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 47141 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 48393 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44396 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44552 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 52380 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44305 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51652 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 46041 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 45824 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 47928 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 50857 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49328 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49457 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 48513 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 50577 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49436 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 45432 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 50896 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51473 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 46993 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51008 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 54217 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 47560 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 54252 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 45224 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44288 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 50501 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49569 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 54028 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51333 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 47196 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 50689 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 46321 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 52488 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51089 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 48393 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44396 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44552 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 52380 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44305 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51652 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 46041 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 45824 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 47928 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 50857 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49328 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49457 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 48513 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 50577 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49436 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 45432 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 50896 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51473 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 46993 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51008 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 54217 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 47560 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 54252 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 45224 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44288 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 50501 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49569 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 54028 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51333 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 47196 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 50689 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 46321 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 52488 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51089 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 48276 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51396 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 48708 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51221 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44508 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 54868 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 46108 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51032 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 54633 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 51004 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 47148 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 48324 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 48324 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 48276 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51396 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 48708 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51221 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44508 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 54868 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 46108 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51032 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 54633 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 51004 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 47148 missing from current font. font.set_text(s, 0, flags=flags)
결과를 보면 절도 검거율은 다른 검거율에 비해 낮다는 것을 알 수 있습니다. 그리고 그래프의 하단으로 갈수록 검거율이 낮은데 그 속에 강남3구 중에서 '서초구'가 보입니다. 전반적으로 검거율이 우수한 구는 '도봉구','광진구','성동구'로 보입니다.
target_col = ['강간', '강도', '살인', '절도', '폭력', '범죄']
crime_anal_norm['범죄'] = crime_anal_norm['범죄'] / 5
crime_anal_norm_sort = crime_anal_norm.sort_values(by='범죄', ascending=False)
plt.figure(figsize = (10,10))
sns.heatmap(crime_anal_norm_sort[target_col], annot=True, fmt='f', linewidths=.5)
plt.title('범죄비율 (정규화된 발생 건수로 정렬)')
plt.show()
/home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 48156 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49373 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 44148 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:238: RuntimeWarning: Glyph 49688 missing from current font. font.set_text(s, 0.0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 48156 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49373 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 44148 missing from current font. font.set_text(s, 0, flags=flags) /home/wntkdl94/.local/lib/python3.6/site-packages/matplotlib/backends/backend_agg.py:201: RuntimeWarning: Glyph 49688 missing from current font. font.set_text(s, 0, flags=flags)
발생 건수로 보니 '강남구','양천구','영등포구'가 범죄 발생 건수가 높습니다.
그리고 '송파구'와 '서초구'도 낮다고 볼 수 없습니다. 그렇다면 정말 강남3구가 안전하다고 할 수 있을지 의문이 생깁니다.
많은 지도 시각화 도구가 있지만 여기서는 Folium 라이브러리를 다루도록 하겠습니다. 먼저 터미널을 열고 pip install folium 이라고 입력해서 folium을 설치합니다. 그리고 간편하게 folium의 공식 페이지에 있는 튜토리얼을 확인합니다.
!pip3 install folium
Collecting folium Downloading https://files.pythonhosted.org/packages/c3/83/e8cb37afc2f016a1cf4caab8d22caf7fe4156c4c15230d8abc9c83547e0c/folium-0.12.1-py2.py3-none-any.whl (94kB) 100% |████████████████████████████████| 102kB 440kB/s a 0:00:01 Collecting requests (from folium) Using cached https://files.pythonhosted.org/packages/29/c1/24814557f1d22c56d50280771a17307e6bf87b70727d975fd6b2ce6b014a/requests-2.25.1-py2.py3-none-any.whl Collecting numpy (from folium) Using cached https://files.pythonhosted.org/packages/45/b2/6c7545bb7a38754d63048c7696804a0d947328125d81bf12beaa692c3ae3/numpy-1.19.5-cp36-cp36m-manylinux1_x86_64.whl Collecting branca>=0.3.0 (from folium) Downloading https://files.pythonhosted.org/packages/61/1f/570b0615c452265d57e4114e633231d6cd9b9d275256778a675681e4f711/branca-0.4.2-py3-none-any.whl Collecting jinja2>=2.9 (from folium) Using cached https://files.pythonhosted.org/packages/7e/c2/1eece8c95ddbc9b1aeb64f5783a9e07a286de42191b7204d67b7496ddf35/Jinja2-2.11.3-py2.py3-none-any.whl Collecting certifi>=2017.4.17 (from requests->folium) Using cached https://files.pythonhosted.org/packages/5e/a0/5f06e1e1d463903cf0c0eebeb751791119ed7a4b3737fdc9a77f1cdfb51f/certifi-2020.12.5-py2.py3-none-any.whl Collecting urllib3<1.27,>=1.21.1 (from requests->folium) Using cached https://files.pythonhosted.org/packages/09/c6/d3e3abe5b4f4f16cf0dfc9240ab7ce10c2baa0e268989a4e3ec19e90c84e/urllib3-1.26.4-py2.py3-none-any.whl Collecting idna<3,>=2.5 (from requests->folium) Using cached https://files.pythonhosted.org/packages/a2/38/928ddce2273eaa564f6f50de919327bf3a00f091b5baba8dfa9460f3a8a8/idna-2.10-py2.py3-none-any.whl Collecting chardet<5,>=3.0.2 (from requests->folium) Using cached https://files.pythonhosted.org/packages/19/c7/fa589626997dd07bd87d9269342ccb74b1720384a4d739a1872bd84fbe68/chardet-4.0.0-py2.py3-none-any.whl Collecting MarkupSafe>=0.23 (from jinja2>=2.9->folium) Using cached https://files.pythonhosted.org/packages/b2/5f/23e0023be6bb885d00ffbefad2942bc51a620328ee910f64abe5a8d18dd1/MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl Installing collected packages: certifi, urllib3, idna, chardet, requests, numpy, MarkupSafe, jinja2, branca, folium Successfully installed MarkupSafe-1.1.1 branca-0.4.2 certifi-2020.12.5 chardet-4.0.0 folium-0.12.1 idna-2.10 jinja2-2.11.3 numpy-1.19.5 requests-2.25.1 urllib3-1.26.4
import folium
map_osm = folium.Map(location=[45.5236, -122.6750])
map_osm
위도와 경도 정보를 주면 지도를 그려줍니다. 마이크로소프트의 익스플로러 브라우저에서는 지도가 파일로 저장은 되는데 브라우저에 저렇게 표현되지는 않습니다.
stamen = folium.Map(location=[45.5236, -122.6750], zoom_start=13)
stamen
또 zoom_start라는 옵션으로 확대 비율을 정의할 수도 있습니다.
stamen = folium.Map(location=[45.5236, -122.6750], tiles='stamen Toner',
zoom_start=13)
stamen
tiles 옵션으로 저런 모양의 지도도 만들 수 있습니다.
map_2 = folium.Map(location=[45.5236,-122.6750], zoom_start = 13)
folium.Marker([45.5244, -122.6699], popup='The Waterfront').add_to(map_2)
folium.CircleMarker([45.5215, -122.6261], radius = 50,
popup='Laurelhurst Park', color='#3186cc',
fill_color='#3186cc').add_to(map_2)
map_2
이번에는 지도를 그리고 그 상태에서 원하는 좌표(위도,경도)에 Marker 명령으로 마크를 찍을 수 있습니다.
그리고 CricleMarker 명령으로 반경과 색상을 지정하면 원을 그려줍니다.
import folium
import pandas as pd
이번에는 pandas도 import합니다. 같은 장 안에서도 같은 모듈을 import하는 이유는 혹시 여기부터 실습을 진행하는 경우에 코드의 문제가 없도록 하려는 것입니다.
state_unemployment = './data/02. folium_US_Unemployment_Oct2012.csv'
state_data = pd.read_csv(state_unemployment)
state_data.head()
State | Unemployment | |
---|---|---|
0 | AL | 7.1 |
1 | AK | 6.8 |
2 | AZ | 8.1 |
3 | AR | 7.2 |
4 | CA | 10.1 |
깃헙의 https://github.com/PinkWink/DataScience 가면 데이터를 받을수 있습니다.
state_geo = './data/02. folium_us-states.json'
map = folium.Map(location=[40, -98], zoom_start=4)
map.choropleth(geo_data=state_geo, data=state_data,
columns=['State', 'Unemployment'],
key_on='feature.id',
fill_color='YlGn',
legend_name='Unemployment Rate(%)')
map
/home/wntkdl94/.local/lib/python3.6/site-packages/folium/folium.py:413: FutureWarning: The choropleth method has been deprecated. Instead use the new Choropleth class, which has the same arguments. See the example notebook 'GeoJSON_and_choropleth' for how to do this. FutureWarning
그래서 state_geo라는 변수에 json 파일 경로를 담고, folium에서 choropleth 명령으로 json 파일과 지도에 표현하고 싶은 데이터를
입력하고, key_on 옵션으로 지도의 id를 알려주면 됩니다.
여기서 지도의 id가 서로 중복되지 않아야 합니다.
그러면 위 그림처럼 실업률이 colormap으로 표현된 결과를 얻을 수 있습니다.
서울시 구별 경계선을 그릴 수 있는 json파일이 있어야 합니다.
Github에서 e9t라는 아이디로 활동하는 Lucy Park 님이 있습니다.
https://github.com/southkorea/southkorea-maps 방문하면 한국 지도에 대해 json 파일을 얻을 수 있습니다.
import json
geo_path = './data/02. skorea_municipalities_geo_simple.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))
먼저 json파일을 로딩합니다.
map = folium.Map(location=[37.5502, 126.982], zoom_start=11,
tiles='Stamen Toner')
map.choropleth(geo_data = geo_str,
data = crime_anal_norm['살인'],
columns = [crime_anal_norm.index, crime_anal_norm['살인']],
fill_color = 'PuRd', #PuRd, YIGnBu
key_on = 'feature.id')
map
그리고 서울시의 중심의 위도와 경도 정보를 먼저 입력하고 경계선을 그리는데, 컬러맵은 살인 발생 건수로 지정합니다.
그 결과를 보면 살인 발생 건수에서 강남 3구가 안전하다고 보기는 어려울 것 같습니다.
map = folium.Map(location=[37.5502, 126.982], zoom_start=11,
tiles='Stamen Toner')
map.choropleth(geo_data = geo_str,
data = crime_anal_norm['강간'],
colums = [crime_anal_norm.index, crime_anal_norm['강간']],
fill_color = 'PuRd', #PuRd, YlGnBu
key_on = 'feature.id')
map
map = folium.Map(location=[37.5502, 126.982], zoom_start=11,
tiles='Stamen Toner')
map.choropleth(geo_data=geo_str,
data = crime_anal_norm['범죄'],
columns = [crime_anal_norm.index, crime_anal_norm['범죄']],
fill_color = 'PuRd', #PuRd, YIGnBu
key_on= 'feature.id')
map
이제 이전에 만들어둔 범죄 발생 건수 전체에 대해 살펴보면,
역시 강남3구와 강서구 주변이 범죄 발생 건수가 높은 것으로 나타나고 있습니다.
그러나 인구수를 고려해야 할 것 같습니다. 즉 인구 대비 범죄 발생 비율을 알아보는 것입니다. 그래서 범죄 전체 발생 건수에
인구수를 나누고 소수점 밑으로 가서 적절한 값을 곱하는 것으로 하겠습니다.
tmp_criminal = crime_anal_norm['살인'] / crime_anal_norm['인구수'] * 1000000
map = folium.Map(location=[37.5502, 126.982], zoom_start=11,
tiles='Stamen Toner')
map.choropleth(geo_data = geo_str,
data = tmp_criminal,
columns = [crime_anal.index, tmp_criminal],
fill_color = 'PuRd', #PuRd, YlGnBu
key_on = 'feature.id')
map
결과를 보면 다음과 같습니다.
인구 대비 범죄 발생 건수로 보면 강남 3구가 1위는 아니지만 안전도가 제일 높다고 말할 수는 없을 것 같습니다.
그런데 중구와 종로구의 범죄율이 엄청 높아졌습니다.
아마 거주 인구는 적고, 관광지여서 그런게 아닐지 추측해봅니다.
경찰서별 검거율과 방금 전까지 수행한 범죄 발생율을 동시에 표현하는게 효과적일 것 같습니다.
crime_anal_raw['lat'] = station_lat
crime_anal_raw['lng'] = station_lng
col = ['살인 검거', '강도 검거', '강간 검거', '절도 검거', '폭력 검거']
tmp = crime_anal_raw[col] / crime_anal_raw[col].max()
crime_anal_raw['검거'] = np.sum(tmp, axis=1)
crime_anal_raw.head()
관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | lat | lng | 검거 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 중부서 | 2 | 2 | 3 | 2 | 105 | 65 | 1395 | 477 | 1355 | 1170 | 중구 | 37.563646 | 126.989580 | 1.275416 |
1 | 종로서 | 3 | 3 | 6 | 5 | 115 | 98 | 1070 | 413 | 1278 | 1070 | 종로구 | 37.575548 | 126.984747 | 1.523847 |
2 | 남대문서 | 1 | 0 | 6 | 4 | 65 | 46 | 1153 | 382 | 869 | 794 | 중구 | 37.554758 | 126.973498 | 0.907372 |
3 | 서대문서 | 2 | 2 | 5 | 4 | 154 | 124 | 1812 | 738 | 2056 | 1711 | 서대문구 | 37.564744 | 126.966770 | 1.978299 |
4 | 혜화서 | 3 | 2 | 5 | 4 | 96 | 63 | 1114 | 424 | 1015 | 861 | 종로구 | 37.571853 | 126.998914 | 1.198382 |
검거만 따로 모아둡니다. 그리고 이미 앞서 수집해둔 각 경찰서의 위도와 경도 정보를 이용하겠습니다.
map = folium.Map(location=[37.5502, 126.982], zoom_start=11)
for n in crime_anal_raw.index:
folium.Marker([crime_anal_raw['lat'][n],
crime_anal_raw['lng'][n]]).add_to(map)
map
이렇게 경찰서의 위치만 먼저 확인했습니다.
map = folium.Map(location=[37.5502, 126.982], zoom_start=11)
for n in crime_anal_raw.index:
folium.CircleMarker([crime_anal_raw['lat'][n], crime_anal_raw['lng'][n]],
radius = crime_anal_raw['검거'][n]*10,
color='#3186cc', fill_color='#3186cc', fill=True).add_to(map)
map
이제 검거에 정당한 값(10)을 곱해서 원 넓이를 정하고, 경찰서의 검거율을 원의 넓이로 표현하겠습니다.
이러면 이제 각 경찰서의 위치에서 넓은 원을 가지면 검거율이 높다고 보면 됩니다.
이제 색상을 붉은 색으로 해서 범죄 발생 건수를 넣으면 될 듯합니다.
map = folium.Map(location=[37.5502, 126.982], zoom_start=11)
map.choropleth(geo_data = geo_str,
data = crime_anal_norm['범죄'],
columns = [crime_anal_norm.index, crime_anal_norm['범죄']],
fill_color = 'PuRd', #PuRd, YlGnBu
key_on = 'feature.id')
for n in crime_anal_raw.index:
folium.CircleMarker([crime_anal_raw['lat'][n], crime_anal_raw['lng'][n]],
radius = crime_anal_raw['검거'][n]*10,
color='#3186cc', fill_color='#3186cc', fill=True).add_to(map)
map
/home/wntkdl94/.local/lib/python3.6/site-packages/folium/folium.py:413: FutureWarning: The choropleth method has been deprecated. Instead use the new Choropleth class, which has the same arguments. See the example notebook 'GeoJSON_and_choropleth' for how to do this. FutureWarning
이렇게 구현할 수 있습니다. 큰 어려움 없이 두 종류의 코드를 단순히 배치만 시켰습니다.
우리는 이번 장에서 서울시 강남 3구 주민들이 자신의 구가 안전하다고 느낀다는 기사에 대해 검증했습니다.
이것저것 조사하고 관찰해도 강남 3구가 실제로 안전한지는 의문이 듭니다.
아마 많은 유흥업소들이 밀집해 있으니 범죄 발생율은 높겠지만 거주 지역에서는 발생 건수가 낮을 수도 있을 것 같다는 생각도 듭니다.
그 이유까지 조사하는 건 숙제로 남겨두겠습니다.
2장 서울시 범죄 현황 분석 (0) | 2021.04.07 |
---|---|
1장 서울시 구별 CCTV 현황 분석 (0) | 2021.04.06 |