본문으로 바로가기

데이터 과학이라고 거창하게 부르지 않아도 요즘은 데이터를 이용해서 실제 원하는 결과를 검증하고 이를 블로그에 올리거나, Github page에 올리는 경우를 많이 봅니다. 그 주제가 참 멋지고 그 과정이 아름다운 분들도 많구요^^. 저도 그냥 가벼운 마음에 통계자료를 가지고 살짝 뭔가를 해볼려고 합니다. 뭐 거창한 알고리즘을 쓴 건 아니구요. 그저 그래프나 깨작거리고 그리고, 데이터의 순서나 좀 바꾸던지.. 혹은 조금 만지작 거리는 수준입니다.^^. 

살짝... "서울 강남 3구 체감안전도 높아"라는 위 기사를 보고~~~ 실제 통계자료도 그렇게 나타나는지를 볼려고 했습니다. 사람들이 생각하는 체감안전도와 혹시 통계자료에서 보는 안전도가 같을지 확인해 보는거죠^^

데이터 가져오기

공공데이터포털이라는 사이트에 가보면 아주아주 많은 통계 자료를 얻을 수 있습니다.

거기서 서울시 관서별 5대 범죄 발생 검거 현황이라는 자료가 있습니다. 그걸 받아서 사용해 볼려구요^^

데이터 다듬기 - 뭐 전처리라고 해둘까요^^

import numpy as np
import pandas as pd

import matplotlib.pyplot as plt
import seaborn as sns

import platform

from matplotlib import font_manager, rc
if platform.system() == 'Darwin':
    rc('font', family='AppleGothic')
elif platform.system() == 'Windows':
    font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
    rc('font', family=font_name)
else:
    print('Unknown system... sorry~~~~') 
    
%matplotlib inline

먼저 들어가기에 앞서~ Jupyter Notebook에서 작성할 거구요... Anaconda 4.1.1에서 테스트되었습니다^^. 그리고 자료형은 기본적으로 제가 연재로 설명한 적이 있는 pandas[바로가기]를 사용합니다. 일단, matplotlib의 한글문제를 해결하기 위해 최근 이야기한 적[바로가기]이 있는 platformimport해서 맥인지 윈도우인지를 확인하고 있습니다. 그리고...

df = pd.read_excel('data/2016서울범죄현황.xlsx', convert_float=True, encoding='euc-kr')
df.head()

아까 공공데이터 포털에서 받은 데이터는 "2016서울범죄현황.xlsx"로 저장했구요. 그 내용은 ...

이렇네요... 5대 범죄에 대해 검거와 발생 건수가 각 경찰서 별로 정리가 되어 있군요^^ 문제는 저는 각 경찰서를 각 구별로 정리를 하고 싶다는 거죠^^ 위키백과의 서울시지방경찰청[바로가기] 항목에는 서울시의 각 경찰청 리스트가 글 하단에 있습니다. 여기서 서울시 경찰청의 소속 구를 확인하구요...

SeoulGu_name = {'서대문서': '서대문구', '수서서': '강남구', '강서서': '강서구', '서초서': '서초구',
                '서부서': '은평구', '중부서': '중구', '종로서': '종로구', '남대문서': '중구',
                '혜화서': '종로구', '용산서': '용산구', '성북서': '성북구', '동대문서': '동대문구',
                '마포서': '마포구', '영등포서': '영등포구', '성동서': '성동구', '동작서': '동작구',
                '광진서': '광진구', '강북서': '강북구', '금천서': '금천구', '중랑서': '중랑구',
                '강남서': '강남구', '관악서': '관악구', '강동서': '강동구', '종암서': '성북구', 
                '구로서': '구로구', '양천서': '양천구', '송파서': '송파구', '노원서': '노원구', 
                '방배서': '서초구', '은평서': '은평구', '도봉서': '도봉구'}

df['구별'] = df['관서명'].apply(lambda v: SeoulGu_name.get(v, v))
df.head()

위에서 처럼 dict 자료형을 이용해서 구별~~이라는 column을 만들었습니다.

이제 위 결과처럼 df['구별']도 만들어 졌네요^^ 이제 '구별'로 구분은 되었지만... 구별 데이터를 쉽게 확인하기 위해서는 경찰서위주로 데이터가 되어 있는것 보다 구별로 되어있는것이 좋겠죠... 즉, 서초구처럼 경찰서가 두 개있는 구도 있으니, 전 구별로 모아서 데이터를 보고 싶다는 거죠^^. 그렇게 해주는 꽤 편리한 명령이 있습니다. .pivot_table[바로가기]입니다.^^

guDF = pd.pivot_table(df, index='구별', aggfunc=np.sum)
guDF = guDF.drop(['계'])
guDF.head()

이렇게 pivot_table을 사용하면 각 구별로 데이터를 쉽게 모아서 볼 수 있습니다. 그 결과는...

입니다.~~^^ 괜찮게 되었죠^^

guDF['강간검거율'] = guDF['강간(검거)']/guDF['강간(발생)']*100
guDF['강도검거율'] = guDF['강도(검거)']/guDF['강도(발생)']*100
guDF['살인검거율'] = guDF['살인(검거)']/guDF['살인(발생)']*100
guDF['절도검거율'] = guDF['절도(검거)']/guDF['절도(발생)']*100
guDF['폭력검거율'] = guDF['폭력(검거)']/guDF['폭력(발생)']*100

del guDF['강간(검거)']
del guDF['강도(검거)']
del guDF['살인(검거)']
del guDF['절도(검거)']
del guDF['폭력(검거)']

guDF.head()

이제 관심있는 데이터를 좀 만들고, 관심없는 데이터는 지우죠...

이렇게 되었습니다. 발생건수와 검거율만 남았네요~~~ 그런데 검거율이 100%가 넘는게 있네요... 아마 발생건수는 2016이고, 그 전해에 발생한 건수에 대한 검거가 2016에 이뤄지면 검거에 그게 반영된 모양입니다. 뭐 여기서는 그냥 100넘는건 100으로 하죠^^

guDF[guDF[['강간검거율', '강도검거율', '살인검거율', '절도검거율', '폭력검거율']] > 100] = 100
guDF.head(10)

넵~

수정되었습니다.^^.

guDF['검거율'] = guDF['소계(검거)']/guDF['소계(발생)']*100
guDF.head()

아차.. 전체 검거율도 만들어야죠~

음.. 가지고 놀만큼 되었네요^^그러나... 그냥 표가 넓어지는게 마음에 안들어서^^

guDF.rename(columns = {'강간(발생)':'강간', 
                       '강도(발생)':'강도', 
                       '살인(발생)':'살인', 
                       '절도(발생)':'절도', 
                       '폭력(발생)':'폭력'}, inplace=True)
del guDF['소계(발생)']
del guDF['소계(검거)']

guDF.head()

Column의 이름을 바꾸도록 하겠습니다.^^

앗.. 표가 확 줄어든게 마음에 드네요 ㅋㅋㅋㅋ. (이상한거에 만족합니다^^)

pop_kor.csv

위 파일을 받아서

popDF = pd.read_csv('data/pop_kor.csv', encoding='UTF-8', index_col='구별')
popDF.head()

보면...

구별 인구수가 있습니다. 어디 다른데서 사용하던건데... 필요해서 가져다 옵니다. 아마 2015년 인구라 지금이랑 맞지는 않지만, 경향정도를 확인하는 걸로 사용하도록 하겠습니다.

guDF = guDF.join(popDF)
guDF.head()

그렇게 받은 두 데이터의 index가 같기 때문에 쉽게 join 명령으로 합치도록 하겠습니다.

잘 합쳐졌죠^^ 

guDF.sort_values(by='검거율', ascending=False, inplace=True)
guDF.head()

일단.. 전체 검거율을 가지고 순위를 한 번 매겨 보겠습니다.

어때요... 종로, 용산, 서초, 등등의 구가 검거율이 높은게 아니네요... 강서구, 금천구, 강북구가.. 검거율이 높습니니다.. 응? 뭐.. 검거율이 체감안전도랑 좀 다르긴 할 수도 있겠죠.. 이제 조금더 가볼까요^^

그래프로 각 구별 현황 확인해보기

target_col = ['강간', '강도', '살인', '절도', '폭력']
weight_col = guDF[target_col].max()

crime_count_norm = guDF[target_col]/weight_col
crime_count_norm.head()

먼저... 5대범죄의 발생 건수만 대상으로 하고... 표현할려는 그래프의 특성을 잘 살리기 위해 각 범죄의 최댓값으로 각 column을 나눠서 정규화시키도록 하겠습니다.

넵... 각 범죄별 경중을 이야기할려는 것이 아니라 종합적인 시각화효과를 위해서 입니다^^

plt.figure(figsize = (10,10))
sns.heatmap(crime_count_norm.sort_values(by='살인', ascending=False), annot=True, fmt='f', linewidths=.5)
plt.title('범죄 발생(살인발생으로 정렬) - 각 항목별 최대값으로 나눠 정규화')
plt.show()

예전에 제가 연재한 적이 있는 seaborn의 heatmap[바로가기]을 사용했습니다.

비록 살인 발생 건수로 정렬했지만, 위로 갈수록 전반적으로 범죄 발생 건수가 높다는 것을 알 수 있습니다. 강남3구는 어디에 있나요^^ 네.. 결코 낮지 않네요.. 강남구는 누가봐도 5대 범죄 전체에 있어서 상위권입니다.

crime_ratio = crime_count_norm.div(guDF['인구수'], axis=0)*100000

plt.figure(figsize = (10,10))
sns.heatmap(crime_ratio.sort_values(by='살인', ascending=False), annot=True, fmt='f', linewidths=.5)
plt.title('범죄 발생(살인발생으로 정렬) - 각 항목을 정규화한 후 인구로 나눔')
plt.show()

이제 단순히 범죄건수만 보지 말고 이를 인구수로 나눠서 인구대비 발생비율로 보겠습니다.

이번에는 중구가 눈에 확~ 보이네요. 애초 기사에서 종로구에 있는 종로서가 체감안전도 1위였는데.. 종로구의 범죄발생 비율은 상위권이네요ㅠㅠ.

crime_ratio['전체발생비율'] = crime_ratio.mean(axis=1)

plt.figure(figsize = (10,10))
sns.heatmap(crime_ratio.sort_values(by='전체발생비율', ascending=False), annot=True, fmt='f', linewidths=.5)
plt.title('범죄 발생(전체발생비율로 정렬) - 각 항목을 정규화한 후 인구로 나눔')
plt.show()

이번에는 전체발생비율로 정렬하고 다시 보죠^^

확실히 알 수 있습니다. 중구, 종로구, 영등포구가 인구대비 발생비율이 높습니다. 강남구와 서초구도 만만치 않네요. 인구대비로 보니 송파는 그래도 하위권이긴 합니다.

지도에 데이터를 표현하기...

지도에 데이터를 표현하는 것도 한 번 해볼까 합니다. 예전에 제가 소개한 적이 있는 Folium[바로가기]을 이용할려구요. 이 부분을 따라가기 전에 필요한 데이터가 하나 있는데....

skorea_municipalities_geo_simple.json

입니다. 출처는 [바로가기]에 있는 한국 지도 데이터 중 서울만 제가 따로 추려낸 것입니다.

import json
import folium
import warnings
warnings.simplefilter(action = "ignore", category = FutureWarning)

geo_path = 'data/skorea_municipalities_geo_simple.json'
geo_str = json.load(open(geo_path, encoding='utf-8'))

일단 위 코드로 지도를 사용하기 위한 준비를 하구요

map = folium.Map(location=[37.5502, 126.982], zoom_start=11, tiles='Stamen Toner')

map.choropleth(geo_str = geo_str,
               data = guDF['살인'],
               columns = [guDF.index, guDF['살인']],
               fill_color = 'PuRd', #PuRd, YlGnBu
               key_on = 'feature.id')
map

심플하게 살인사건의 발생 건수를 표시해보죠

어떤거요... 갑가지 강남3구가 확 들어옵니다. 그리고 영등포구와 중랑구도 눈에 들어오네요... 저런...

map = folium.Map(location=[37.5502, 126.982], zoom_start=11, tiles='Stamen Toner')

map.choropleth(geo_str = geo_str,
               data = crime_ratio['전체발생비율'],
               columns = [crime_ratio.index, crime_ratio['전체발생비율']],
               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_str = geo_str,
               data = guDF['검거율'],
               columns = [guDF.index, guDF['검거율']],
               fill_color = 'YlGnBu', #PuRd, YlGnBu
               key_on = 'feature.id')
map

이번에는 검거율을 보죠^^

흠.. 검거율은 강서구와... 금천구, 강북구가 높네요. 

경찰서의 위치 정보에 데이터를 포함시켜서 지도에 나타내기...

처음 데이터... df라고 저장했던 데이터에는 경찰서별 정보가 남아 있습니다. 여기서... 응? '계'는 없애구요^^

이걸 가지고 경찰서의 검거율을 지도에 같이 표현해보려구요..

station_name = []

for name in df['관서명']:
    station_name.append('서울'+str(name[:-1])+'경찰서')

station_name

일단 제가 사용할 것은 googlemaps입니다. 그럴려면 경찰서의 fullname이 필요하거든요^^

이렇게 말이죠^^...

df['경찰서'] = station_name
df['검거율'] = df['소계(검거)']/df['소계(발생)']*100
df.head()

그리고.. 경찰서별 검거율을 계산해두고...

그런데.. 검거율의 폭이 좀 좁아서 가장 낮은 검거율과 가장 높은 검거율을 가지는 경찰서를 일종의 점수 개념으로 간격을 좀 벌리겠습니다. 지도에 표기할때 눈에 잘 들어나게 할려구요^^

def reRange(x, oldMin, oldMax, newMin, newMax):
    return (x - oldMin)*(newMax - newMin) / (oldMax - oldMin) + newMin

df['점수'] = reRange(df['검거율'], min(df['검거율']), max(df['검거율']), 1, 100)
df.head()

그래서 위와 같이 점수로 표기합니다. 단순히 경찰서의 능력을 검거율로만 볼수 없겠죠... 단지 얻은 데이터를 기준으로 보는 것이니까요...

이렇게 되었네요^^ 이제 sort를 시켜서 결과를 보면~

어~ 강서경찰서, 금천경찰서가 검거율 1, 2위네요... 그 뒤를 강북서, 도봉서, 수서서가 따라가고 있습니다. 이제... [바로가기]에서 소개한 데로 googlemaps를 사용해서 각 경찰서의 위도, 경도 정보를 얻을 겁니다.

import googlemaps
gmaps = googlemaps.Client(key="-- input your key --")

lat = []
lng = []

for name in df['경찰서']:
    tmpMap = gmaps.geocode(name)
    tmpLoc = tmpMap[0].get('geometry')
    lat.append(tmpLoc['location']['lat'])
    lng.append(tmpLoc['location']['lng'])
    
df['lat'] = lat
df['lng'] = lng

df.head()

위 코드의 결과는 각 경찰서의 위도 경도 정보를 얻을 수 있는거죠...

이렇게 말이죠^^...

map = folium.Map(location=[37.5502, 126.982], zoom_start=11)

for n in df.index:
    folium.CircleMarker([df['lat'][n], df['lng'][n]], radius=df['점수'][n]*25, 
                        color='#3186cc', fill_color='#3186cc').add_to(map)
    
map

이제 각 경찰서의 위치에 검거율을 환산한 점수를 원의 넓이로 표기하도록 하겠습니다.

아하.. 어떤가요.. 괜찮죠^^

map = folium.Map(location=[37.5502, 126.982], zoom_start=11)

map.choropleth(geo_str = geo_str,
               data = crime_ratio['전체발생비율'],
               columns = [crime_ratio.index, crime_ratio['전체발생비율']],
               fill_color = 'PuRd', #PuRd, YlGnBu
               key_on = 'feature.id')

for n in df.index:
    folium.CircleMarker([df['lat'][n], df['lng'][n]], radius=df['점수'][n]*25, 
                        color='#3186cc', fill_color='#3186cc').add_to(map)
    
map

마지막으로...

이렇게 아까 했던 범죄발생비율과 경찰서의 검거율을 같이 지도에 그려보았습니다. 어떤가요^^

  • 강남3구의 체감 안전도가 높다는 기사의 내용을 가지고, 실제 통계적으로도 그런 결과가 도출되는지 확인함
  • 강남3구의 5대 범죄 발생 건수는 다른 구와 비교해서 높음
  • 인구대비 발생 비율도 강남3구가 낮지는 않음
  • 단, 강남구와 서초구는 유흥업소 밀집지역에서 범죄 발생이 높을 수 있음

아무튼.. 서울시 5대 범죄 발생건수와 검거율을 가지고 잠시 즐거운 분석 시간을 가져 보았습니다. 요즘.. 제 취미활동이거든요^^


댓글을 달아 주세요

  1. 이전 댓글 더보기
  2. 정재호 2017.04.20 21:07

    안녕하세요.
    제가 프로그래밍을 혼자서 주먹구구식으로 배우다 이 블로그를 찾게 되어서 정말 기뻤습니다.

    제가 잘 되지 않는 게 있어서 그런데 조언 좀 구해도 될까요?
    지금 윈도우 컴퓨터로 위의 내용을 따라해 보고 있는데 seaborn을 설치할 수가 없어서 어려움을 겪고 있습니다. 제가 아진 맥북으로도 해보려고 했는데, 거기서도 seaborn 설치가 되지 않더라구요.

    제가 이해하기로는 seaborn이라는 걸 설치하면 spciy란 것도 같이 설치가 되는 것 같은데, 맥북에서는 설치 중간에 scipy 설치 과정에서 에러가 나고, 그래서 따로 scipy를 설치해주고 경로를 지정해 주어도 결국 seaborn 설치가 되지 않았구요,
    지금 윈도우 컴퓨터로는 설치하려고 하면,

    Building wheels for collected packages: scipy
    Running setup.py bdist_wheel for scipy ... error

    이런 말이 나오고, 그 다음 긴 내용의 말들이 나온 다음, 제일 마지막 부분에서는

    Command ""c:\users\sunyoung and jaeho\appdata\local\programs\python\python35-32\python.exe" -u -c "import setuptools, tokenize;__file__='C:\\Users\\SUNYOU~1\\AppData\\Local\\Temp\\pip-build-g3nhh07u\\scipy\\setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record C:\Users\SUNYOU~1\AppData\Local\Temp\pip-8t0usrqy-record\install-record.txt --single-version-externally-managed --compile" failed with error code 1 in C:\Users\SUNYOU~1\AppData\Local\Temp\pip-build-g3nhh07u\scipy\

    라는 말이 나오고, 결과적으로는 설치가 되지 않더라구요.

    제가 구글로 검색해 봐도 아직 해결하지 못하고 있는데, 혹시 조언을 해 주실 수 있으세요?

    감사합니다!

  3. 정재호 2017.04.20 21:25

    안녕하세요, 조금 전에 글 남겼던 정재호인데요..^^;
    제가 anaconda라는 걸 설치하고, anaconda promt를 실행시켜서 seaborn을 설치하려고 하니 이미 설치되어 있다고 나오더라구요. 그래서 확인해 보려고 python을 실행시키고 import seaborn을 실행시키니 ValueError: _getfullpathname: embedded null character in path 라는 말을 포함한 긴 내용이 나오고 결국 실행이 안되더라구요..

    조금 진척이 있었던 것 같은데, 혹시 지금 단계에서 어떤 걸 하면 좋을지 조언해 주실 수 있으세요? 감사합니다!

    • BlogIcon PinkWink 2017.04.21 06:14 신고

      만약 기존에 따로 python을 설치하고 또 여러 모듈을 설치하고.. 그리고 다시 아나콘다를 설치하고... 하면... 버젼관리가 안되서 알 수 없는 여러 에러가 나더라구요.ㅠㅠ. 기존의 python을 지우고 환경설정에서 기존 python에 대한 환경변수도 삭제하고 다시 conda install을 실행해 보시는 것은 어떨까요?

  4. 정재호 2017.04.21 07:30

    답변 감사드립니다!!


    다행히 제가 하고자 하는 부분인 지도에 수치를 표현하는 것에는 크게 영향이 없는 것 같더라구요.. 그래서 일단 좌표를 얻는 것까지는 성공했습니다.

    조금만 더 여쭤봐도 될까요?^^;;

    제가 지도에 데이터 표시하기 부분을 할 때 에러 없이 지나간 걸로 봐서는 된 것 같긴 한데요.. 수정된 그림은 어떻게 확인하면 되는 거에요?^^;; 그리고 저는 명령어 창에서 파이썬 코드를 실행하면 >>> 가 뜨는 창에서 내용들이 출력이 되는데, 여기 올려주신 것처럼 깔끔하게 표로 보이게 하는 거랑 그림을 출력하는 방법은 찾아봐도 나오질 않더라구요.. 이 부분 좀 알려주실 수 있으세요?

    정말 감사합니다. 저는 경제학을 공부하는 학생인데요, 여기 블로그를 알게 되어서 정말 기쁘기고, 오히려 저보다 더 잘 하시는 것 같아서 부럽기도 합니다.


    감사합니다!!

    • BlogIcon PinkWink 2017.04.21 10:08 신고

      여기( http://pinkwink.kr/940 ) 있듯이 저는 아나콘다 4.1.1을 설치 했구요... 그리고 DataScience 카테고리는 Jupyter로 코드를 작성해서 보여드리고 있습니다.^^ http://pinkwink.kr/946 입니다.^^

  5. 정재호 2017.04.22 01:51

    안녕하세요. ^^;;

    제가 알려주신 대로 주피터를 설치했는데 윈도우 컴퓨터랑 맥 둘 모두에서 툴? 이 안보이더라구요.. 실행할 수 있는 방법 자체가 없고 명령어만 입력할 수 있는 상황이어서, 다시 구글로 찾아보고 기존에 설치되어 있던 파이썬과 아나콘다를 삭제하고 다시 실행해 봤는데 여전히 이 문제를 해결하지 못하고 있어요.. ;

    혹시 이 문제는 어떻게 해결할 수 있는지 아세요? ^^;; 제가 본문과 관련 없는 부분에서 계속 문제가 생기니까 컴퓨터가 이상한 건지, 아니면 제가 뭔가 중요한 걸 잘못하고 있는건지 잘 구분이 안되네요.. ^^;;

    감사합니다!!

  6. 정재호 2017.04.22 11:52

    아, 제가 바보였네요..;;; 스파이더의 오른편에 나오는 실행결과 부분을 보면 되는 거였네요..;
    감사합니다!! ^^;;

  7. BlogIcon 한도림 2017.12.08 14:17

    안녕하세요 파이썬 공부중인 학생입니다.
    이 게시글에 있는
    "서울시 경찰서별 5대범죄 발생, 검거..." 이
    공공데이터에서 없어진거 같습니다.
    공부를 위해서 "서울시 경찰서별 5대범죄 발생, 검거....".csv or .xlsx 파일을 주실수 있습나요?
    myesung12@naver.com 입니다.

    • BlogIcon PinkWink 2017.12.08 18:49 신고

      블로그 제일 상단에 github 링크가 있습니다. 아이콘으로.. 거기 가셔서 DataScience라는 폴더에 보면 데이터가 있을 겁니다.

  8. WerBer 2018.01.05 09:47

    초반에 엑셀파일 read할 때 'data/2016...' 쓰셨는데 저 data폴더는 어디에 위치시키신건가요....

    • BlogIcon PinkWink 2018.01.05 09:58 신고

      이 코드에서는 소스코드가 위치하는 폴더와 같은 곳일 겁니다.

    • WerBer 2018.01.05 10:03

      빠른답변 감사합니다ㅠㅠ
      그럼 jupyter가 위치한곳 이라는건가요???

      C:\Anaconda3\envs\python3\lib\site-packages\pandas\io\excel.py in read_excel 이렇게 떠서 pandas 폴더에 넣었는데 계속 에러가 나네요

    • BlogIcon PinkWink 2018.01.05 10:30 신고

      아니요.. 작성하고 계신 소스코드가 위치한 폴더입니다. (프로그램이 설치된 폴더가 아닌..)

  9. 파이썬입문자 2018.04.03 15:37

    핑크윙크님 항상 좋은 자료 올려주셔서 많은 도움을 받고 있습니다. 감사합니다.
    지도를 만드는 map.choropleth까지 입력을 하고 출력받는 가운데 오류가 자꾸 발생합니다.
    1) 지도가 뜨지만 지도의 색깔이 한 색으로 표시되거나
    2) 오류의 설명으로: '<' not supported between instances of 'str' and 'int', float을 제외한 int형식은 입력되지 않는다.
    두 가지 오류가 계속 발생하는데,
    혹시 이 문제가 무엇때문인지, 어떻게 해결하면 되는지 알려주실 수 있으신가요?ㅠㅠ

    • BlogIcon PinkWink 2018.04.05 00:17 신고

      흠.. 혹시 ... 수치로 된 데이터가 올바르게 수치형인지 확인해 보세요.. 데이터가 pandas 데이터프레임이면 info 명령으로 해당 컬럼의 데이터형을 알 수 있습니다.

    • 파이썬입문자 2018.04.10 14:52

      info 명령어에 넣는 데이터의 형식을 잘 이해하지 못하여서ㅠ exel에서 데이터를 숫자로 바꾸고 맵으로 다시 확인해보았습니다.
      index의 범위가 나오는 것을 보면 숫자로 읽히는 것 같은데, 혹시 수치형으로 되지 않은게 아니라면 무엇이 문제일까요..?
      아래 map그림을 첨부합니다.

      https://docs.google.com/document/d/1GZrl2GpqhrxzgyRaBIhyPjgvqgAkxpYh6QHVLrPEmI8/edit?usp=sharing

    • BlogIcon PinkWink 2018.04.12 00:20 신고

      실제 데이터가 수치형인지 확인하셔야 합니다.
      info() 명령의 결과를 보면 숫자인 컬럼은 float이나 int라고 되어 있습니다.

  10. 2018.05.28 22:12

    비밀댓글입니다

  11. song 2018.06.04 11:55

    안녕하세요 도서를 참고하며 공부를 해나가고 있는 중 궁금한 점이 생겨 질문드립니다
    pivot_table을 이용하여 데이터를 관서별에서 구별로 바꾸는 과정에서 데이터가 누락되는 문제점이 발생하는데, 왜 이런 누락이 발생하는지 모르겠습니다.

    crime_anal_raw=pd.read_csv('D:/pydata/crime_in_Seoul_gu_name.csv',encoding='utf-8',index_col=0)
    를 이용하면 다음과 같이

    관서명 살인 발생 살인 검거 강도 발생 강도 검거 ... 절도 발생 절도 검거 폭력 발생 폭력 검거 구별
    0 중부서 2 2 3 2 ... 1,395 477 1,355 1,170 중구
    1 종로서 3 3 6 5 ... 1,070 413 1,278 1,070 종로구
    2 남대문서 1 0 6 4 ... 1,153 382 869 794 중구
    3 서대문서 2 2 5 4 ... 1,812 738 2,056 1,711 서대문구

    출력됨을 확인하였습니다.

    그런데, pivot_table을 이용하여 구별로 바꾸는 과정에서 절도와 폭력이 누락되는 현상이 발생합니다.
    crime_anal=pd.pivot_table(crime_anal_raw,index='구별',aggfunc=np.sum)
    를 이용하여 crime_anal을 출력해보면

    [31 rows x 12 columns]
    강간 검거 강간 발생 강도 검거 강도 발생 살인 검거 살인 발생
    구별
    강남구 349 449 18 21 10 13
    강동구 123 156 8 6 3 4
    강북구 126 153 13 14 8 7
    관악구 221 320 14 12 8 9
    와 같이 출력됩니다. 12colums가 존재한다고는 하는데 다음 코드인

    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
    에서 절도가 존재하지 않아 오류가 발생하였다 라는 오류가 발생합니다.

    다음은 오류 로그입니다.
    Traceback (most recent call last):
    File "C:\Users\Admin\PycharmProjects\SeoulCriminal\venv\lib\site-packages\pandas\core\indexes\base.py", line 3063, in get_loc
    return self._engine.get_loc(key)
    File "pandas\_libs\index.pyx", line 140, in pandas._libs.index.IndexEngine.get_loc
    File "pandas\_libs\index.pyx", line 162, in pandas._libs.index.IndexEngine.get_loc
    File "pandas\_libs\hashtable_class_helper.pxi", line 1492, in pandas._libs.hashtable.PyObjectHashTable.get_item
    File "pandas\_libs\hashtable_class_helper.pxi", line 1500, in pandas._libs.hashtable.PyObjectHashTable.get_item
    KeyError: '절도 검거'

    왜 이런 현상이 발생하는지 궁금하여 질문드립니다.

    • BlogIcon PinkWink 2018.06.04 12:29 신고

      crime_anal.info()
      명령을 수행해서
      사라진다는 컬럼을 확인해보세요
      아마 숫자(float)가 아니라 문자(object)로 되어 있을 수 있습니다.
      pivot_table은 숫자만 value로 바꿔주거든요.
      일단 제가 생각한 상황이 맞는지 info() 명령으로 확인해 주세요.

    • song 2018.06.04 13:48

      생각하신 문제가 맞습니다.
      .info()로 확인해보니 절도와 폭력 부분이 object 형입니다.
      1000이 넘는 숫자는 1,000의 형식으로 표현하려하는데 csv파일이라 큰따옴표로 묶여있어서 숫자가 아닌 문자로 인식된 것 같습니다.

    • BlogIcon PinkWink 2018.06.04 13:54 신고

      그러면 read_csv를 할 때, thousands=',' 라고 옵션을 주시면 됩니다. 천단위에 콤마가 찍혀있는데 무시하라는 뜻입니다.

    • song 2018.06.04 14:03

      감사합니다!
      손으로 다 바꾸고 댓글 확인했네요 ㅋㅋ
      다음부터는 thousans=',' 를 사용해야겠습니다

    • BlogIcon PinkWink 2018.06.04 14:11 신고

      ㅎㅎ 네... 화이팅입니다.^^

  12. tina 2018.06.07 19:49

    "서울시 경찰서별 5대범죄 발생, 검거..." 이
    공공데이터에서 없어진거 같습니다.
    공부를 위해서 "서울시 경찰서별 5대범죄 발생, 검거....".csv or .xlsx
    답글에서 말씀하시는 다운받을 수 잇다는 폴더도 못 찾겠어요..
    wlgid94@gmail.com
    혹시 보내주실수잇을까요?

  13. 닉기 2018.08.12 16:54

    안녕하세요 집필해주신 교재 덕분에 재밌게 공부하고 있습니다
    한가지 질문이 있는데요 교재 80p In[5] 에서 gmaps.geocode('서울중부경찰서', language='ko'를 치면
    결과가 잘나오는데 '서울중부경찰서'를 제외한 다른 경찰서(예를 들면 '서울종로경찰서')를 치면
    결과가 안나오는 이유는 뭘까요??
    그로인해 82p In[7]을 치면 Out[7]로 뜨지않고 첫번째줄만 뜨고 오류가 나더군요
    그리고 geocode(' ') 이부분에 다른 장소를 치면 안되는건가요? 마찬가지로 오류가 뜹니다

  14. coincidence 2018.10.30 08:26

    서울지도한것처럼 강릉을 동별로도 가능할까요?

  15. BlogIcon 꾸르잼 2018.11.01 20:16

    전국지도에서 서울만 자료를 추출하셨다고 하셨는데

    혹시 다른 지역만 어떻게 하는지 알수 잇을까요?

  16. 2018.11.01 23:27

    비밀댓글입니다

  17. ree89 2018.11.20 12:54

    import warnings
    warnings.simplefilter(action = "ignore", category = FutureWarning)


    답변을 받을 수 있을지 의문이지만 남겨봅니다. ㅠㅠㅠㅠㅠ

    • BlogIcon PinkWink 2018.11.20 14:19 신고

      Python은 모듈별 버전 의존도도 있고 해서, 다음번 버전에는 이 명령을 쓰지 못하거나 문법등의 내용이 바뀌게 될때, Future Warning을 줍니다.
      그런데 이 워닝은 지금은 정상 동작을 하는거죠. 그래서 그 글이 작성될 시점 기준으로 그 퓨쳐워닝은 보고 싶지 않아서, 해당워닝은 표시하지 말라는 명령입니다.

  18. ree89 2018.11.20 12:57

    import warnings
    warnings.simplefilter(action = "ignore", category = FutureWarning)



    %% 질문!!
    import warnings 이부분은 왜 추가를하는지 알고싶습니다. 따로설명이없으시길래요!!!!!!

  19. bb 2019.03.26 11:01

    글 잘 읽었습니다! 그런데 혹시 프로그래밍에 사용된 서울시 경찰서별 5대 범죄발생 csv파일을 메일로좀 받을 수 있을까요..? 윗 댓글에 답변주신 github 사이트 및 공공데이터사이트를 모두 찾아보았는데 프로그래밍에 쓰신것과 같은 파일은 찾지 못하겠습니다...메일주소는 ngoodsamari@네이버 입니다!

  20. 초보자 2019.04.01 17:14

    안녕하세요
    만약 2개의 지점의 길찾기를 통해서 그림을 그리고 싶습니다.
    그때 네이버 api의 길찾기를 이용해서 좌표를 얻어서 시각화를 하고 싶은데 가능할까요?!
    감사합니다.

  21. WB 2019.12.29 16:18

    ---------------------------------------------------------------------------
    TypeError Traceback (most recent call last)
    <ipython-input-82-0641f1266ee9> in <module>
    5 columns = [popDF.index, popDF['인구수']],
    6 fill_color = 'PuRd', #PuRd, YlGnBu
    ----> 7 key_on = 'feature.id')
    8 map

    C:\ProgramData\Anaconda3\envs\WB\lib\site-packages\folium\folium.py in choropleth(self, *args, **kwargs)
    416 )
    417 from folium.features import Choropleth
    --> 418 self.add_child(Choropleth(*args, **kwargs))
    419
    420 def keep_in_front(self, *args):

    TypeError: __init__() missing 1 required positional argument: 'geo_data'

    이런 오류가 뜹니다.
    key_on = 'feature.id' 여기서 오류가 뜬 거 같은데 왜 그러는지 어떻게 해야 하는지 궁금합니다.. ㅠㅠ
    그리고 좋은 게시물 감사합니다.!

    • BlogIcon PinkWink 2020.01.02 01:20 신고

      아~.. 이런.. 잘 모르겠습니다. ㅠㅠ.

    • 미래 2020.03.26 13:29

      벌써2달이 지났네요
      저도 동일한 증상이였는데 해당 지도 .json 파일이 잘못된거는 아니고
      아마 파일 다운로드를 받으실때 다른이름으로 저장을 하면 html형식으로 다운받아져서 그런것 같습니다, DataScience 폴더를 그대로 클론해서 쓰면 정상 작동합니다.
      주소 입니다 https://github.com/PinkWink/DataScience

      또한 다음 코드인 map부분에서 geo_str=geo_str을
      get_data=get_str로 수정하면 정상작동됩니다

    • BlogIcon PinkWink 2020.03.28 21:03 신고

      아~ 어떤 현상인진 정확히 모르겠지만, 아무튼 해결이 되었다니 다행입니다.