티스토리 뷰
![](https://raw.githubusercontent.com/PinkWink/DataScience/master/img/title.jpg)
2장 - 서울시 범죄 현황 분석¶
2-1 데이터 획득하기¶
(데이터 출처: https://github.com/PinkWink/DataScience)
위에 github 에서 배포되는 데이터를 활용하여 실습해 보자.
import numpy as np
import pandas as pd
2-2 pandas를 이용하여 데이터 정리하기¶
먼저 numpy와 pandas는 항상 import 하는 모듈이라 생각하면 된다. 이제 다운받은 데이터를 pandas로 읽어보자. crime_anal_police 라는 변수에 저장한다.
crime_anal_police = pd.read_csv('/home/jaeyoon89/DataScience/data/02. crime_in_Seoul.csv', thousands=',',
encoding='utf-8')
crime_anal_police.head()
Unnamed: 0 | Unnamed: 0.1 | Unnamed: 0.1.1 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 중부서 | 2 | 2 | 3 | 2 | 105 | 65 | 1395 | 477 | 1355 | 1170 | 중구 |
1 | 1 | 1 | 1 | 종로서 | 3 | 3 | 6 | 5 | 115 | 98 | 1070 | 413 | 1278 | 1070 | 종로구 |
2 | 2 | 2 | 2 | 남대문서 | 1 | 0 | 6 | 4 | 65 | 46 | 1153 | 382 | 869 | 794 | 중구 |
3 | 3 | 3 | 3 | 서대문서 | 2 | 2 | 5 | 4 | 154 | 124 | 1812 | 738 | 2056 | 1711 | 서대문구 |
4 | 4 | 4 | 4 | 혜화서 | 3 | 2 | 5 | 4 | 96 | 63 | 1114 | 424 | 1015 | 861 | 종로구 |
2-3 지도 정보를 얻을 수 있는 Google Maps¶
그런데 여기서 문제가 생겼다. 우리는 강남 3구가 안전한지를 확인하려는 것인데 데이터가 관서별로 되어 있습니다. 위 표에도 나와있지만 서울시에는 한 구에 하나 혹은 두군데에 경찰서가 위치해 있고, 구 이름과 다른 경찰서도 있다. 이 경찰서 목록을 소속 구별로 변경하고 싶다. 그러기 위해서는 먼저 경찰서 이름으로 구 정보를 알아야 한다.
위치에 대한 검색 결과 중 주소와 위도, 경도 정보를 제공하는 서비스가 구글에 있다. 바로 google maps api 이다. 그중에 주소 검색과 위도, 경도 정보 정도를 얻을 수 있는 Geocoding API를 선택하여 키 가져오기로 키를 가져오자.
2-4 Google Maps를 이용해서 주소와 위도, 경도 정보 얻기¶
import googlemaps
gmaps_key = "AIzaSyDTbfmYGb5nplB8o9aUJVnjrDYiGiLITIM"
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']}]
google maps 를 사용해서 '서울중부경찰서'라는 단어를 검색해 보자. 그러면 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
이제 위 코드처럼 google maps 코드에 만들어둔 경찰서 이름을 이용해서 주소를 받아오자. 위의 결과를 얻었으니 각 경찰서별 주소를 모두 얻었다.
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 | Unnamed: 0.1.1 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 중부서 | 2 | 2 | 3 | 2 | 105 | 65 | 1395 | 477 | 1355 | 1170 | 중구 |
1 | 1 | 1 | 1 | 종로서 | 3 | 3 | 6 | 5 | 115 | 98 | 1070 | 413 | 1278 | 1070 | 종로구 |
2 | 2 | 2 | 2 | 남대문서 | 1 | 0 | 6 | 4 | 65 | 46 | 1153 | 382 | 869 | 794 | 중구 |
3 | 3 | 3 | 3 | 서대문서 | 2 | 2 | 5 | 4 | 154 | 124 | 1812 | 738 | 2056 | 1711 | 서대문구 |
4 | 4 | 4 | 4 | 혜화서 | 3 | 2 | 5 | 4 | 96 | 63 | 1114 | 424 | 1015 | 861 | 종로구 |
이제 위에서 저장한 주소를 띄어쓰기, 공백으로 나누고 두 번째 단어를 선택해서 구별이라는 컬럼으로 저장한다. 이렇게 하면 관서명에서 google maps의 도움을 받아 구별 이름으로 저장할 수 있게 된다.
단, 금천 경찰서의 경우 관악구에 위치해 있어 금천서는 예외 처리를 해야한다.
crime_anal_police[crime_anal_police['관서명']=='금천서']
Unnamed: 0 | Unnamed: 0.1 | Unnamed: 0.1.1 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
15 | 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 | Unnamed: 0.1.1 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
15 | 15 | 15 | 15 | 금천서 | 3 | 4 | 6 | 6 | 151 | 122 | 1567 | 888 | 2054 | 1776 | 금천서 |
관악구로 되어 있는 것을 금천구로 변경하자.
crime_anal_police.to_csv('../DataScience/data/02. crime_in_Seoul.csv',
sep=',', encoding='utf-8')
crime_anal_police.head()
Unnamed: 0 | Unnamed: 0.1 | Unnamed: 0.1.1 | 관서명 | 살인 발생 | 살인 검거 | 강도 발생 | 강도 검거 | 강간 발생 | 강간 검거 | 절도 발생 | 절도 검거 | 폭력 발생 | 폭력 검거 | 구별 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 중부서 | 2 | 2 | 3 | 2 | 105 | 65 | 1395 | 477 | 1355 | 1170 | 중구 |
1 | 1 | 1 | 1 | 종로서 | 3 | 3 | 6 | 5 | 115 | 98 | 1070 | 413 | 1278 | 1070 | 종로구 |
2 | 2 | 2 | 2 | 남대문서 | 1 | 0 | 6 | 4 | 65 | 46 | 1153 | 382 | 869 | 794 | 중구 |
3 | 3 | 3 | 3 | 서대문서 | 2 | 2 | 5 | 4 | 154 | 124 | 1812 | 738 | 2056 | 1711 | 서대문구 |
4 | 4 | 4 | 4 | 혜화서 | 3 | 2 | 5 | 4 | 96 | 63 | 1114 | 424 | 1015 | 861 | 종로구 |
현재까지 우리가 확보한 데이터의 구조가 관서명을 기초로 했기 때문에 구별 컬럼에서는 같은 구 이름이 두번 있을 수 있다. 예를 들면 강남구에는 경찰서가 두 개이니 위에서 강남구가 두 번 나온다.
2-5 pivot_table을 이용해서 데이터 정리하기¶
crime_anal_raw = pd.read_csv('/home/jaeyoon89/DataScience/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('/home/jaeyoon89/DataScience/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
del crime_anal['강간 검거']
del crime_anal['강도 검거']
del crime_anal['살인 검거']
del crime_anal['절도 검거']
del crime_anal['폭력 검거']
crime_anal.head()
강간 발생 | 강도 발생 | 살인 발생 | 절도 발생 | 폭력 발생 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | |
---|---|---|---|---|---|---|---|---|---|---|
구별 | ||||||||||
강남구 | 449 | 21 | 13 | 3850 | 4284 | 77.728285 | 85.714286 | 76.923077 | 42.857143 | 86.484594 |
강동구 | 156 | 6 | 4 | 2366 | 2712 | 78.846154 | 133.333333 | 75.000000 | 33.347422 | 82.890855 |
강북구 | 153 | 14 | 7 | 1434 | 2649 | 82.352941 | 92.857143 | 114.285714 | 43.096234 | 88.637222 |
관악구 | 320 | 12 | 9 | 2706 | 3298 | 69.062500 | 116.666667 | 88.888889 | 30.561715 | 80.109157 |
광진구 | 240 | 14 | 4 | 3026 | 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()
강간 발생 | 강도 발생 | 살인 발생 | 절도 발생 | 폭력 발생 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | |
---|---|---|---|---|---|---|---|---|---|---|
구별 | ||||||||||
강남구 | 449 | 21 | 13 | 3850 | 4284 | 77.728285 | 85.714286 | 76.923077 | 42.857143 | 86.484594 |
강동구 | 156 | 6 | 4 | 2366 | 2712 | 78.846154 | 100.000000 | 75.000000 | 33.347422 | 82.890855 |
강북구 | 153 | 14 | 7 | 1434 | 2649 | 82.352941 | 92.857143 | 100.000000 | 43.096234 | 88.637222 |
관악구 | 320 | 12 | 9 | 2706 | 3298 | 69.062500 | 100.000000 | 88.888889 | 30.561715 | 80.109157 |
광진구 | 240 | 14 | 4 | 3026 | 2625 | 91.666667 | 100.000000 | 100.000000 | 42.200925 | 83.047619 |
이제 뒤에 붙은 발생이라는 단어를 삭제하자.
crime_anal.rename(columns = {'강간 발생':'강간',
'강도 발생':'강도',
'살인 발생':'살인',
'절도 발생':'절도',
'폭력 발생':'폭력'}, inplace=True)
crime_anal.head()
강간 | 강도 | 살인 | 절도 | 폭력 | 강간검거율 | 강도검거율 | 살인검거율 | 절도검거율 | 폭력검거율 | |
---|---|---|---|---|---|---|---|---|---|---|
구별 | ||||||||||
강남구 | 449 | 21 | 13 | 3850 | 4284 | 77.728285 | 85.714286 | 76.923077 | 42.857143 | 86.484594 |
강동구 | 156 | 6 | 4 | 2366 | 2712 | 78.846154 | 100.000000 | 75.000000 | 33.347422 | 82.890855 |
강북구 | 153 | 14 | 7 | 1434 | 2649 | 82.352941 | 92.857143 | 100.000000 | 43.096234 | 88.637222 |
관악구 | 320 | 12 | 9 | 2706 | 3298 | 69.062500 | 100.000000 | 88.888889 | 30.561715 | 80.109157 |
광진구 | 240 | 14 | 4 | 3026 | 2625 | 91.666667 | 100.000000 | 100.000000 | 42.200925 | 83.047619 |
위와같이 컬럼의 이름은 rename 으로 변경할 수 있다.
2-6 데이터 표현을 위해 다듬기¶
앞서 코드를 보면 강도, 살인 사건은 두 자릿수인데, 절도와 폭력은 네 자릿수이다. 물로 숫자 그 자체로도 중요하지만 각각을 비슷한 범위에 놓고 비교하는 것이 편리할 수 있다. 개념적으로 살인 1건과 절도 1천건이 같은 비중이라고 이야기하는 것은 아니지만, 각 항목의 최대값을 1로 두면 추후 범죄 발생 건수를 종합적으로 비교할 때 편리할 것이다. 그래서 강간, 강도, 살인, 절도, 폭력에 대해 각 컬럼별로 정규화 해보자.
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에 있는 전처리(preprocessing) 도구에는 최소값, 최대값을 이용해서 정규화시키는 함수가 있다. 이제 다양한 시각화에서 편리해지도록 각 발생 건수는 정규화시켰다.
result_CCTV = pd.read_csv('/home/jaeyoon89/DataScience/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 |
결과는 위와 같다. 그럼 이 결과를 다음 단계에서 시각화해 보자.
출처 : 파이썬으로 데이터 주무르기
'파이썬으로 데이터 주무르기' 카테고리의 다른 글
파이썬으로 데이터 주무르기 ch.4 (0) | 2021.04.03 |
---|---|
파이썬으로 데이터 주무르기 ch.3-2 (0) | 2021.04.02 |
파이썬으로 데이터 주무르기 ch.3-1 (0) | 2021.04.01 |
파이썬으로 데이터 주무르기 ch.2-2 (0) | 2021.03.31 |
파이썬으로 데이터 주무르기 chapter.1 (0) | 2021.03.28 |