인구수 열까지 포함한 gu_df의 데이터 프레임은 다음과 같다.
이 데이터 프레임을 시각화하기 쉽게 하기 위해서 정렬을 해보겠다.
'검거율'로 정렬을 시켜보도록 하겠습니다.
gu_df.sort_values(by='검거율', inplace=True, ascending=True)
gu_df
정렬 함수는 sort인데, '검거율' 열의 값을 기준으로 정렬이므로 sort_values를 사용한다.
( )안에는 기준열부터 작성하고, ascending의 뜻은 '올라가다'이다. 그런데 False이므로 내림차순으로 정렬이다. inplace는 덮어쓰기를 허용한다는 뜻이다.
이제 검거율과 인구수를 제거한 데이터 프레임으로 시각화를 진행해보자.
어느 구에서 5대 범죄가 많이 일어나는지 알아보기 위해서이다.
gu_df[[ '강간', '강도'. '살인', '절도', '폭력']]
시각화를 위한 함수는 seaborn 라이브러리에 있는 heatmap을 사용하면 쉽다.
seaborn을 사용하기 위해 다시 import 해주자.
import seaborn as sns
sns.heatmap(gu_df[ [ '강간', '강도'. '살인', '절도', '폭력'] ])
바로 figure을 불러오면 여러 문제점이 있다.
첫번째는 figure의 크기 문제이다.
강동구와 성북구 사이를 보면 행이 3개가 있다. 그런데 figure의 크기가 작아서 인덱스 이름은 2개만 있다.
이것은 figure의 크기 문제로 그냥 크게 바꿔주면 된다.
두번째는 feature의 scale이 엉망이라 시각화가 힘들다.
원인은 강도와 살인 열의 값은 1자리고, 나머지 열은 4자리로 서로 데이터 값의 차이가 심해서 강도와 살인열은 까맣게 되어 있다. 이것을 전문적으로 말하면 피쳐의 스케일이 엉망이라고 표현한다.
이것은 시각화 과정에서도 문제가 심하지만, 머신러닝 모델을 개발할 때 데이터 값의 차이가 심하면 학습을 중단하는 경우도 있다.
이때, 피쳐는 열의 또다른 이름이다. 열은 이름이 다양하다.
열 = column = attribute(특성) 데이터 프레임의 특성을 말한다고 생각하자, demention(차원) 지금은 열이 5개이므로 5차원이다, feature 넓은 의미로는 데이터의 특징 모두이고 좁은 의미로는 데이터 열 하나하나 명칭이다.
이 문제를 고치는 방법은 2가지가 있다. 하나는 min-max 알고리즘, 두번째는 standardization 기법이다. 이 두가지 방법 중 어떤게 더 좋다. 라고 콕 찝에서 설명을 못하는 것이 어떤 머신러닝 모델에서는 min-max가 좋고, 어떤 모델에서는 standardization 기법이 잘된다.
1. min-max 알고리즘
min-max 알고리즘은 열마다 최솟값이 0, 최댓값이 1로 바뀌는 것이다. 데이터값의 범위는 0~1이 된다.
살인열의 강북구행부터 min-max 알고리즘 방식으로 정리한다고 가정하겠다. 이때 기준값을 oldX, 살인열에서 최댓값은 10이므로 max(열)=10, 최솟값은 4이므로 min(열)=4라고 할 수 있다.
열의 값이 매우 많을 때는 gu_df['원하는 열 이름'].max( ) / .min( )
이때, 알아두면 유용한 것은 gu_df.quantile(0.5)
( )안의 값이 0이면 min 값, 0.25면 25% 값, 0.5면 50% 값==중윗값(median), 0.75면 75%값, 1이면 max 값
newX = ( oldX - min(열) ) / ( max(열) - min(열) )
기준 데이터 값을 최솟값으로 빼므로 -가 나올 수가 없다.
2. standardization 기법
이 기법은 mean(평균) 값, std(표준편차) 값 두가지를 이용하는 것이다. 이것은 열마다 평균값이 0, 표준편차값이 1이 되게 맞추는 것이다. 표준편차가 1이므로 데이터값의 범위는 -1 ~ +1이 된다.
마찬가지로 gu_df['원하는 열 이름'].mean( ) / .std( )
newX = ( oldX - mean(열) ) / std(열)
이 공식을 안외워도 되는 이유는 쉽게 데이터값을 조정해주는 함수가 있기 때문이다.
세번째 문제점은 matplotlib의 한글 문제이다.
지금은 행열의 글씨가 이쁘게 되어 있지만, 처음 heatmap을 실행시키면 행열이 ㅁㅁ로 되어 있다. 그것은 한글 폰트를 안불러 와서 그렇다.
한글 폰트를 불러오는 코드는 다음과 같다.
%matplotlib inline
font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
rc('font', family=font_name)
%matplotlib inline은 지금은 굳이 안써도 되는 코드이다. 새 창을 띄어서 figure을 보여주지 말고, jupyter notebook에 figure을 보여주라는 명령어이다.
font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name() 이 명령어가 matplotlib의 한글 문제를 해결해준다. font_manager.FontProperties는 그냥 한글 폰트를 꺼내는 함수이다.
fname는 폰트의 이름은 "~~"이 경로에 있다. 라는 뜻이다. 그런데 주의 사항은 폰트 파일 이름이 한글로 되어 있거나 띄어쓰기가 되어 있으면 안된다. .get_name() 는 폰트 파일에서 한글을 꺼내는 작업을 해준다.
rc는 그냥 설정을 세팅해주는 작업을 해준다. 정도만 알고 있으면 된다.
이제 데이터 값을 정리하는데, 이 데이터프레임으로 머신러닝을 돌릴것은 아니라 그냥 각 열의 최댓값으로 나누도록 한다.
crime_count_norm = gu_df[ [ '강간', '강도'. '살인', '절도', '폭력'] ] / gu_df[ [ '강간', '강도'. '살인', '절도', '폭력'] ].max( )
단순히 보면 그냥 A / A.max( )이다.
이제 다시 시각화를 해보자.
sns.heatmap(crime_count_norm.sort_values(by='살인', ascending=False))
crime_count_norm의 데이터 프레임으로 figure을 만드는데, '살인'열을 기준으로 내림차순으로 만드는 것이다.
훨신 이뻐지긴 했지만, figure의 크기가 작은 것은 여전하다.
이렇게 figure를 수정하려면 plt.~~~를 이용해 코드를 작성하고, plt.show( )를 하면 plt. 으로 시작하는 모든 코드를 종합해 수정한다. 이때 sns. 으로 시작하는 것도 plt.show( )가 종합하는데 그 이유는 seaborn 라이브러리 안에 plt가 포함되어 있기 때문이다.
plt.figure(figsize=(10, 10))
sns.heatmap(crime_count_norm.sort_values(by='살인', ascending=False),
annot=True, fmt='f', linewidths=.5, cmap='Reds')
plt.title('범죄 발생(살인발생으로 정렬) - 각 항목별 최대값으로 나눠 정규화')
plt.show()
함수명 | 설명 |
figure | figure를 수정하는 대표적인 함수이다. 도화지 개념 |
figsize | figure의 사이즈를 조정해주는 함수 |
annot | 셀 안에 데이터 값을 넣을 것이냐는 질문 |
fmt | 셀 안에 입력될 데이터 값의 수치 (몇자리수까지 표현할 것이냐는 질문) |
cmap | 셀의 색깔 |
title | 제목을 만드는 것 |
그런데 이것은 구마다 인구수를 고려하지 않고 단순 발생 건수만 가지고 시각화를 진행한 것이다.
사람이 많은 구에서는 사건 발생 건수도 높아지는데, 인구수를 고려해서 다시 만들어 보자.
crime_count_norm
이 DataFrame은 각 열의 서울시 5대 범죄의 최댓값만 나눈 것이다.
인구수는 gu_df 데이터 프레임에 '인구수'열에 있다.
crime_count_norm['살인'] = crime_count_norm['살인'] / gu_df['인구수']
이렇게 모든 열을 나눠주면 되지만 div 함수를 사용하면 더 효율적으로 사용 가능하다.
crime_count_norm = crime_count_norm.div(gu_df['인구수'], axis=0)*100000
crime_count_norm
A.div(B['특정 열 이름'], axis=0)
이때 axis=0는 열끼리 묶어서 실행한다는 뜻이다. axis=1이면 행을 기준으로 동작한다.
이제 마지막으로 다시 figure을 생성해보자.
plt.figure(figsize = (10,10))
sns.heatmap(crime_ratio.sort_values(by='살인', ascending=False), annot=True, fmt='f', linewidths=.5, cmap='Reds')
plt.title('범죄 발생(살인발생으로 정렬) - 각 항목을 정규화한 후 인구로 나눔')
'서울시 범죄현황 통계자료 분석 및 시각화' 카테고리의 다른 글
06. 서울시 범죄현황 통계자료 분석 및 시각화 (0) | 2023.07.02 |
---|---|
04. 서울시 범죄현황 통계자료 분석 및 시각화 (1) | 2023.06.30 |