티스토리 뷰
1. 판다스를 이용하여 데이터 정리하기
구글에서 '서울시 관서별 5대 범죄 발생 검거 현황'이라는 검색어로 구글에서 검색한 결과를 보면 data.go.kr이라는 주소가 나타난다. 공공데이터 포럼에 가서 원하는 데이터를 다운 받을 수 잇다. 2015년 자료를 가지고 하겠다. 자료의 이름을
crime_in_Seoul로 바꾸고 파이썬 폴더에 저장하자.
pandas를 이용해 데이터 정리하기
In:
|
import numpy as np |
먼저 numpy와 pandas는 항상 import하는 모듈이라고 생각하면 된다. 이제 다운받은 데이터를 pandas로 읽어보겠다. crime_anal_police라는 변수를 저장한다. 그 내용을 보면 서울시 경찰서별로 살인, 강도, 강간, 절도 , 폭력 이라는 5대 범죄
에 대해 발생 건수와 검거 건수를 가지고 있다.
In:
|
crime_anal_police = pd.read_csv('C:/myPyCode/data/02. crime_in_Seoul.csv', thousands=',', encoding='euc-kr') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
그런데 여기서 문제가 하나 생겼다. 우리는 강남 3구가 안전한지를 확인하려는 것인데 데이터가 관서별로 되어 있다. 서울시에는 한 구에 하나 혹은 두 군데의 경찰서가 위치해 있고, 구 이름과 다른 경찰서도 있다. 이 경찰서 목록을 소속 구별로 변경하고 싶다. 그러기 위해서는 먼저 경찰서 먼저 경찰서 이름으로 구 정보를 알아야 한다. 양이 많지 않으니 직접 입력해도 되지만 우리는 프로그램으로 접근하겠다.
2. google맵에서 지도 정보를 얻기
위치에 대한 검색 결과 중 주소와 위도, 경도 정보를 제공하는 서비스가 구글에 있다. 바로 Google Maps API이다. Google Maps API 홈페이지에 접속해서 Google Maps Geocoding API에 접근하자. Googld Maps는 다양한 API가 있다. 그 중에 주소 검색과 위도, 경도 정보 정도를 얻을 수 있는 GeoCodingAPI를 선택해서 '키 가져오기'로 키를 가져오면 된다.
이제 googlemaps를 import해야 한다. 그리고 googlemap.Client로 키를 입력하면 된다.
In: |
import googlemaps |
In: |
gmaps_key = " 자신의 키 적기 " gmaps = googlemaps.Client(key=gmaps_key) |
In: Out:
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',
'types': ['establishment', 'point_of_interest', 'police']}]
Google Maps를 사용해서 '서울중부경찰서'라는 단어를 검색해 보자. 그러면 formatted_address 항목에 주소가 나오고 lng와 lat에서 위도 경도 정보도 확인해 볼 수 있다.
경찰서의 이름을 관서명이 아닌 **경찰서로 부르기 위해 다음과 같이 해보자.
In:
|
station_name = [] for name in crime_anal_police['관서명']: station_name |
Out:
|
['서울중부경찰서', '서울종로경찰서', '서울남대문경찰서', '서울서대문경찰서', '서울혜화경찰서', '서울용산경찰서', '서울성북경찰서', '서울동대문경찰서', '서울마포경찰서', '서울영등포경찰서', '서울성동경찰서', '서울동작경찰서', '서울광진경찰서', '서울서부경찰서', '서울강북경찰서', '서울금천경찰서', '서울중랑경찰서', '서울강남경찰서', '서울관악경찰서', '서울강서경찰서', '서울강동경찰서', '서울종암경찰서', '서울구로경찰서', '서울서초경찰서', '서울양천경찰서', '서울송파경찰서', '서울노원경찰서', '서울방배경찰서', '서울은평경찰서', '서울도봉경찰서', '서울수서경찰서'] |
구글 maps에 위 코드에 만들어ㄷㄴ 경찰서 이름을 이용해 주소를 받아오자.
In: station_name = [] for name in crime_anal_police['관서명']: station_name station_addreess = [] for name in station_name: station_lat.append(tmp_loc['location']['lat']) Out:
station_name.append('서울' + str(name[:-1]) + '경찰서')
station_lat = []
station_lng = []
tmp = gmaps.geocode(name, language='ko')
station_addreess.append(tmp[0].get("formatted_address"))
tmp_loc = tmp[0].get("geometry")
station_lng.append(tmp_loc['location']['lng'])
print(name + '-->' + tmp[0].get("formatted_address"))
서울중부경찰서-->대한민국 서울특별시 중구 을지로동 수표로 27
서울종로경찰서-->대한민국 서울특별시 종로구 종로1.2.3.4가동 율곡로 46
서울남대문경찰서-->대한민국 서울특별시 중구 남대문로5가 한강대로 410
서울서대문경찰서-->대한민국 서울특별시 서대문구 미근동 통일로 113
서울혜화경찰서-->대한민국 서울특별시 종로구 종로1.2.3.4가동 창경궁로 112-16
서울용산경찰서-->대한민국 서울특별시 용산구 원효로1가 25
서울성북경찰서-->대한민국 서울특별시 성북구 삼선동5가 301
서울동대문경찰서-->대한민국 서울특별시 동대문구 청량리동 약령시로21길 29
서울마포경찰서-->대한민국 서울특별시 마포구 아현동 618-1
서울영등포경찰서-->대한민국 서울특별시 영등포구 당산동3가 2-11
서울성동경찰서-->대한민국 서울특별시 성동구 행당1동 왕십리광장로 9
서울동작경찰서-->대한민국 서울특별시 동작구 노량진동 72
서울광진경찰서-->대한민국 서울특별시 광진구 구의1동 자양로 167
서울서부경찰서-->대한민국 서울특별시 은평구 대조동 통일로 757
서울강북경찰서-->대한민국 서울특별시 강북구 번1동 415-15
서울금천경찰서-->대한민국 서울특별시 관악구 신림동 544
서울중랑경찰서-->대한민국 서울특별시 중랑구 신내1동 신내역로3길 40-10
서울강남경찰서-->대한민국 서울특별시 강남구 대치동 998
서울관악경찰서-->대한민국 서울특별시 관악구 봉천동
서울강서경찰서-->대한민국 서울특별시 양천구 신월동 화곡로 73
서울강동경찰서-->대한민국 서울특별시 강동구 성내1동 성내로 57
서울종암경찰서-->대한민국 서울특별시 성북구 종암동 종암로 135
서울구로경찰서-->대한민국 서울특별시 구로구 가마산로 235
서울서초경찰서-->대한민국 서울특별시 서초구 서초3동 반포대로 179
서울양천경찰서-->대한민국 서울특별시 양천구 신정6동 목동동로 99
서울송파경찰서-->대한민국 서울특별시 송파구 가락본동 9
서울노원경찰서-->대한민국 서울특별시 노원구 하계동 노원로 283
서울방배경찰서-->대한민국 서울특별시 서초구 방배2동 방배천로 54
서울은평경찰서-->대한민국 서울특별시 은평구 불광2동 연서로 365
서울도봉경찰서-->대한민국 서울특별시 도봉구 창4동 노해로 403
서울수서경찰서-->대한민국 서울특별시 강남구 개포동 개포로 617
경찰서별 주소를 모두 얻었다.
주소를 저장하자.
In: Out:
station_addreess
['대한민국 서울특별시 중구 을지로동 수표로 27',
'대한민국 서울특별시 종로구 종로1.2.3.4가동 율곡로 46',
'대한민국 서울특별시 중구 남대문로5가 한강대로 410',
'대한민국 서울특별시 서대문구 미근동 통일로 113',
'대한민국 서울특별시 종로구 종로1.2.3.4가동 창경궁로 112-16',
'대한민국 서울특별시 용산구 원효로1가 25',
'대한민국 서울특별시 성북구 삼선동5가 301',
'대한민국 서울특별시 동대문구 청량리동 약령시로21길 29',
'대한민국 서울특별시 마포구 아현동 618-1',
'대한민국 서울특별시 영등포구 당산동3가 2-11',
'대한민국 서울특별시 성동구 행당1동 왕십리광장로 9',
'대한민국 서울특별시 동작구 노량진동 72',
'대한민국 서울특별시 광진구 구의1동 자양로 167',
'대한민국 서울특별시 은평구 대조동 통일로 757',
'대한민국 서울특별시 강북구 번1동 415-15',
'대한민국 서울특별시 관악구 신림동 544',
'대한민국 서울특별시 중랑구 신내1동 신내역로3길 40-10',
'대한민국 서울특별시 강남구 대치동 998',
'대한민국 서울특별시 관악구 봉천동',
'대한민국 서울특별시 양천구 신월동 화곡로 73',
'대한민국 서울특별시 강동구 성내1동 성내로 57',
'대한민국 서울특별시 성북구 종암동 종암로 135',
'대한민국 서울특별시 구로구 가마산로 235',
'대한민국 서울특별시 서초구 서초3동 반포대로 179',
'대한민국 서울특별시 양천구 신정6동 목동동로 99',
'대한민국 서울특별시 송파구 가락본동 9',
'대한민국 서울특별시 노원구 하계동 노원로 283',
'대한민국 서울특별시 서초구 방배2동 방배천로 54',
'대한민국 서울특별시 은평구 불광2동 연서로 365',
'대한민국 서울특별시 도봉구 창4동 노해로 403',
'대한민국 서울특별시 강남구 개포동 개포로 617']
위도와 경도를 얻어보자.
In: Out:
station_lat
[37.5636465,
37.5755578,
37.5547584,
37.5647848,
37.5718401,
37.538649,
37.5897271,
37.58506149999999,
37.550814,
37.5257884,
37.5617309,
37.5130685,
37.542873,
37.6128611,
37.6373881,
37.4814051,
37.618692,
37.5094352,
37.4743789,
37.5397827,
37.528511,
37.6020592,
37.494931,
37.4956054,
37.5165667,
37.5019065,
37.6423605,
37.4815453,
37.6283597,
37.6533589,
37.49349]
In: |
station_lng |
Out: |
[126.9895796, 126.9848674, 126.9734981, 126.9667762, 126.9988562, 126.966055, 127.0161318, 127.0457679, 126.954028, 126.901006, 127.0363806, 126.9428078, 127.083821, 126.9274951, 127.0273238, 126.9099508, 127.1047136, 127.0669578, 126.9509748, 126.8299968, 127.1268224, 127.0321577, 126.886731, 127.0052504, 126.8656763, 127.1271513, 127.0714027, 126.9829992, 126.9287226, 127.052682, 127.0772119] |
저장했던 주소를 띄어쓰기, 공백으로 나두고 두 번째 단어를 선택해서 구별이라는 컬럼으로 저장하자. 이렇게 하면 관서명에서 google maps의 도움을 받아 구별 이름으로 저장할 수 있게 된다.
In: gu_name = [] for name in station_addreess: Out:
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()
관서명
살인 발생
살인 검거
강도 발생
강도 검거
강간 발생
강간 검거
절도 발생
절도 검거
폭력 발생
폭력 검거
구별
0
중부서
2
2
3
2
105
65
1395
477
1355
1170
중구
1
종로서
3
3
6
5
115
98
1070
413
1278
1070
종로구
2
남대문서
1
0
6
4
65
46
1153
382
869
794
중구
3
서대문서
2
2
5
4
154
124
1812
738
2056
1711
서대문구
4
혜화서
3
2
5
4
96
63
1114
424
1015
861
종로구
단, 금천경찰서는 관악구에 위치해 있기 때문에 금천서는 예외 처리를 해야 한다.
In: Out:
crime_anal_police[crime_anal_police['관서명']=='금천서']
관서명살인 발생
살인 검거
강도 발생
강도 검거
강간 발생
강간 검거
절도 발생
절도 검거
폭력 발생
폭력 검거
구별
15
금천서
3
4
6
6
151
122
1567
888
2054
1776
관악구
관악구로 되어 있는 것을 금천구로 변경한다.
In: |
crime_anal_police.loc[crime_anal_police['관서명']=='금천서', ['구별']] = '금천구' crime_anal_police[crime_anal_police['관서명']=='금천서'] | ||||||||||||||||||||||||||
Out: |
|
인터넷에서 자료를 가져오는 경우 이 과정을 단순한 프로그램 오류가 발생할 수 있기에 적당한 이름으로 저장한다.
In: |
crime_anal_police.to_csv('../data/02. crime_in_Seoul_include_gu_name.csv', sep=',', encoding='utf-8') |
In: |
crime_anal_police.head() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out: |
|
3. pivot_table을 이용해 데이터 정리
In:
|
crime_anal_raw = pd.read_csv('../data/02. crime_in_Seoul_include_gu_name.csv', encoding='utf-8') crime_anal_raw.head() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
pandas의 pivot_table을 이용해 원 데이터를 관서별에서 구별로 바꾸면 다음과 같다.
In:
|
crime_anal_raw = pd.read_csv('../data/02. crime_in_Seoul_include_gu_name.csv', crime_anal = pd.pivot_table(crime_anal_raw, index='구별', aggfunc=np.sum) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
추가로 각 범죄별 검거율을 계산하고, 검거 건수는 검거율로 대체할 수 있기때문에 삭제하기로 하자. 그리고 pandas의 결과표를 한 화면에 표현하자.
In:
|
crime_anal['강간검거율'] = crime_anal['강간 검거']/crime_anal['강간 발생']*100 del crime_anal['강간 검거'] crime_anal.head() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
그런데 검거율이 100이 넘는 숫자들이 보인다. 그 이유는 전년도에 발생한 건수에 대한 검거가 포함되기 때문이다. 그냥 이 숫자들은 100으로 처리해 주자.
In:
|
con_list = ['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율'] for column in con_list: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
발생이라는 단어를 삭제해 보자.
In:
|
crime_anal.rename(columns = {'강간 발생':'강간', '강도 발생':'강도', '살인 발생':'살인', '절도 발생':'절도', '폭력 발생':'폭력'}, inplace=True) crime_anal.head() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
3. 데이터 표현을 다듬기
위 표를 보면 강도, 살인 사건은 두 자릿수인데, 절도와 폭력은 네 자릿수이다. 물론 숫자 그 자체로도 중요하지만 각각을 비슷한 범위에 놓고 비교하는 것이 편리할 수 잇다. 개념적으로는 살인 1건과 절도 1천 건이 같은 비중은 아니겠지만, 각 항목의 최대값을 1로 두면 추후 범죄 발생 건수를 종합적으로 비교할 때 변리할 것이다. 그래서 강간, 강도, 살인, 절도, 폭력에 대해 각 컬럼별로 '정규화'하도록 하겠다.
In:
|
from sklearn import preprocessing col = ['강간', '강도', '살인', '절도', '폭력'] x = crime_anal[col].values x_scaled = min_max_scaler.fit_transform(x.astype(float)) col2 = ['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율'] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
다양한 시각화에서 편리해지도록 각 발생건수를 정규화 시켰다.
In:
|
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() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
서울시 cctv 공부할때 나왔던 결과인 CCTV_result.csv를 읽어서 그 속에서 구별 인구수와 CCTV 개수를 가지고 오겠다.
In:
|
col = ['강간','강도','살인','절도','폭력'] crime_anal_norm['범죄'] = np.sum(crime_anal_norm[col], axis=1) crime_anal_norm.head() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
또한 발생 건수의 합을 '범죄'라는 항목으로 두고 이를 합하겠습니다. 만약 정규화하지 않았다면 몇 천 건의 절도에 수십 건의 살인의 비중이 애매했겠지만 정규화를 통해 그 부분은 유리해졌습니다. 단, 여기서는 범죄의 경중을 논하자는 것이 절대 아닙니다.
In:
|
col = ['강간검거율','강도검거율','살인검거율','절도검거율','폭력검거율'] crime_anal_norm['검거'] = np.sum(crime_anal_norm[col], axis=1) crime_anal_norm.head() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
그리고 검거율도 해당한다.
In: |
crime_anal_norm | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
그럼 이 결과를 어떻게 하면 효과적으로 인식할 수 있게 시각화할 수 있을까요? 혹시 정렬하는 것을 상상하셨다면, 그건 효과적이지 않습니다.
4. 범죄 데이터 시각화하기
Seaborn을 이용해보자. 일단 그래프 한글 폰트 문제를 해결한다.
In:
|
import matplotlib.pyplot as plt %matplotlib inline import platform path = "c:/Windows/Fonts/malgun.ttf" |
In: |
crime_anal_norm.head() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
pairplot으로 강도, 살인, 폭력 간의 상관관계를 그래프로 보겠다.
In:
|
sns.pairplot(crime_anal_norm, vars=["강도", "살인", "폭력"], kind='reg', size=3) plt.show() |
Out:
|
인구와 CCTV 개수, 그리고 살인과 강도에 대해 조사했다. 전체적인 상관계수는 CCTV와 살인의 관계가 낮을지 몰라도 CCTV가 없을 때 살인이 많이 일어나는 구간이 있다. 즉, CCTV 개수를 기준으로 좌측면에 살인과 강도의 높은 수를 갖는 데이터가 보인다.
In:
|
sns.pairplot(crime_anal_norm, x_vars=["인구수", "CCTV"], y_vars=["살인", "강도"], kind='reg', size=3) plt.show() |
Out:
|
살인 및 폭력 검거율과 CCTV의 관계가 양의 상관관계가 아니다. 오히려 음의 상관계수도 보인다. 또 인구와 살인 및 폭력 검겨율도 음의 상관관계가 관찰된다.
In:
|
sns.pairplot(crime_anal_norm, x_vars=["인구수", "CCTV"], y_vars=["살인검거율", "폭력검거율"], kind='reg', size=3) plt.show() |
Out:
|
In:
|
sns.pairplot(crime_anal_norm, x_vars=["인구수", "CCTV"], y_vars=["절도검거율", "강도검거율"], kind='reg', size=3) plt.show() |
Out:
|
이쯤에서 검거율의 합계인 검거 항목 최고 값을 100으로 한정하고 그 값으로 정렬한 다음, heatmap을 그려보자.
In:
|
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() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
In:
|
target_col = ['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율'] crime_anal_norm_sort = crime_anal_norm.sort_values(by='검거', ascending=False) plt.figure(figsize = (10,10)) |
Out:
|
결과를 보면 절도 검거율은 다른 검거율에 비해 낮다는 것을 알 수 있다. 그리고 그래프의 하단으로 갈수록 검거율이 낮은데 그 속에 강남3구 중에 '서초구'가 보인다. 전반적으로 검거율이 우수한 구는 '도봉구', '광진구', '성동구'로 보인다.
이번에는 발생 건수의 합으로 정렬해서 heatmap으로 관찰해보겠다.
In:
|
target_col = ['강간', '강도', '살인', '절도', '폭력', '범죄'] crime_anal_norm['범죄'] = crime_anal_norm['범죄'] / 5 plt.figure(figsize = (10,10)) |
Out:
|
발생 건수로 보니 '강남구', '양천구', '영등포구'가 범죄 발생 건수가 높다. 그리고 '송파구'와 '서초구'도 낮다고 볼 수 없다. 그렇다면 정말 강남 3구가 안전하다고 할 수 있을지 의문이 생긴다.
일단 여기까지 하고 저장하자.
In:
|
crime_anal_norm.to_csv('../data/02. crime_in_Seoul_final.csv', sep=',', encoding='utf-8') |
5. 서울시 범죄율에 대한 지도 시각화
이제 지도를 다루는 법도 알았으니 우리가 열심히 다듬은 자료를 시각화해보겠다. 물론 언제나 그렇듯이 난관은 있다. 서울시 구별 경계선을 그릴 수 있는 json파일이 있어야 한다. 이건 우리가 직접 만들 수 없기 때문에 검색을 해보면 Github에서 e9t라는 아이디로 활동하는 Lucy Park 님이 있다.
먼저 json파일을 로딩하자.
In:
|
import json geo_path = '../data/02. skorea_municipalities_geo_simple.json' geo_str = json.load(open(geo_path, encoding='utf-8')) |
그리고 서울시의 중심의 위도와 경도 정보를 먼저 입력하고 경계선을 그리는데, 컬러맵은 살인 발생 건수로 지정한다.
In:
|
map = folium.Map(location=[37.5502, 126.982], zoom_start=11, map.choropleth(geo_data = geo_str, |
결과를 보면 살인 발생 건수에서 강남 3구가 안전하다고 보기는 어렵다.
특히 강간 발생 건수로 다시 그려보면,
In:
|
map = folium.Map(location=[37.5502, 126.982], zoom_start=11, map.choropleth(geo_data = geo_str, |
더더욱 강남 3구가 안전한지 의심이 든다.
이전에 만들어둔 범죄 발생 건수 전체에 대해 살펴보면,
In:
|
map = folium.Map(location=[37.5502, 126.982], zoom_start=11, map.choropleth(geo_data = geo_str, |
강남3구와 강서구 주변이 범죄 발생 건수가 높은 것으로 나타나고 있다. 그러나 인구수를 고려해야 할 것 같다. 즉 인구 대비 범죄 발생 비율을 알아보는 것이다. 그래서 범죄 전체 발생 건수에 인구수를 나누고 소수점 밑으로 가서 적절한 값을 곱하는 것으로 하겠다.
In: |
tmp_criminal = crime_anal_norm['살인'] / crime_anal_norm['인구수'] * 1000000 map = folium.Map(location=[37.5502, 126.982], zoom_start=11, map.choropleth(geo_data = geo_str, |
결과를 다시 보면 인구 대비 범죄 발생 건수로 보면 강남 3구가 안전도가 제일 높다고 말할 수는 없을것 같다. 그런데 중구와 종로구의 범죄율이 엄청 높아졌다. 아마 거주 인구는 적고, 관광지여서 그런게 아닐지 추측해본다.
6. 서울시 경찰서별 검거율과 구별 범죄 발생률을 동시에 시각화하기
조금 더 진행해서 경찰서별 검거율과 방금 전까지 수행한 범죄 발생율을 동시에 표현하는 게 효과적일 것 같다.
검거만 따로 모아주자.
In:
|
mp_criminal = crime_anal_norm['범죄'] / crime_anal_norm['인구수'] * 1000000 map = folium.Map(location=[37.5502, 126.982], zoom_start=11, map.choropleth(geo_data = geo_str, |
앞서 수집해둔 각 경찰서의 위도와 경도 정보를 이용하자.
In:
|
map = folium.Map(location=[37.5502, 126.982], zoom_start=11, map.choropleth(geo_data = geo_str, |
경찰서의 위치만 먼저 확인했다.
이제 검거에 정한한 값(10)을 곱해서 원 넓이를 정하고, 경찰서의 검거율을 원의 넓이로 표현하겠다. 이러면 각 경찰서의 위치에서 넓은 원을 가지면 검거율이 높다고 보면 된다.
이제 색상을 붉은 색으로 해서 범죄 발생 건수를 넣어보자.
In:
|
map = folium.Map(location=[37.5502, 126.982], zoom_start=11) map.choropleth(geo_data = geo_str, for n in crime_anal_raw.index: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Out:
|
|
출처: 파이썬으로 데이터 주무르기
'beginner > 파이썬 분석' 카테고리의 다른 글
단일선형회귀분석 ② (0) | 2019.01.28 |
---|---|
단일선형회귀분석 ① (0) | 2019.01.24 |
서울시 구별 CCTV 현황 분석 (0) | 2019.01.18 |
데이터 시각화 (0) | 2019.01.17 |
데이터 분석을 위한 패키지-pandas ② (0) | 2019.01.17 |