[샌프란시스코 범죄 분류] - 1
이번 시간에는 캐글 대회 샌프란시스코 범죄 분류에 대해서 진행해 볼 것이다.
이 대회는 총 39개의 범죄 유형을 예측해야 한다. 즉 다중 분류(Multi-Class Classification) 문제이다.
데이터는 아래의 링크에 있다.
https://www.kaggle.com/c/sf-crime
데이터 불러오기
데이터를 불러오자.
import pandas as pd
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
train.shape, test.shape
데이터는 약 88만 개 정도이고 Test 데이터의 개수가 Train 데이터의 개수보다 2개 적은 것을 확인할 수 있다.
그러면 Train 데이터와 Test 데이터의 변수 종류를 확인해보자.
train.info()
test.info()
데이터를 확인해보면 Train 데이터에 있는 Descript, Resolution, Category 데이터는 존재하지 않는다. Category는 종속 변수이지만, Descript, Resolution은 학습할 때 불필요하기 때문에 삭제할 것이다.
그렇다면 변수의 세부 사항을 알아보자.
변수를 확인해보면 크게 시간 데이터와 공간 데이터로 구분되는 것을 확인할 수 있다.
Dates, DayOfWeek 데이터는 시간 관련 데이터이고, PdDistrict, Address, X, Y 데이터는 공간과 관련된 데이터임을 확인할 수 있다. 본 대회는 시공간 데이터를 활용해 범죄의 유형을 예측하는 문제라고 정의할 수 있다.
이번에는 제출용 파일 정보를 확인해보자.
sample = pd.read_csv('sampleSubmission.csv')
sample.info()
탐색적 자료 분석(EDA)
데이터를 확인했으니 간단한 시각화나 데이터의 분포를 진행할 것이다.
# 탐색적 자료 분석
train_df = train.copy()
train_df.shape == train.shape
복제한 이유는 EDA를 진행할 때 다양한 형태로 데이터를 가공 및 전처리를 병행하면서 해야 하기 때문이다.
그렇다면 결측치와 중복 데이터가 있는지 확인해보자.
# 결측치 확인
def check_na(data):
isnull_na = (data.isnull().sum() / len(data)) * 100
data_na = isnull_na.drop(isnull_na[isnull_na == 0].index).sort_values(ascending = False)
missing_data = pd.DataFrame({'Missing Ratio' : data_na,
'Data Type' : data.dtypes[data_na.index]})
print('결측치 데이터 칼럼과 건수 : \n', missing_data)
check_na(train_df)
결측치는 없는 것을 확인할 수 있다.
이번에는 중복 데이터가 있는지 확인해보자.
# 중복 데이터 확인
train_df.duplicated().sum()
총 2,323개의 데이터가 있는 것을 확인한 후, 제거를 진행한다.
# 중복 제거
print('Before :', train_df.shape)
train_df.drop_duplicates(inplace = True)
print('After :', train_df.shape)
그 후에 범죄 내용과 관련된 두 개의 변수를 삭제하자.
# 범죄 내용과 관련된 변수 삭제
train_df.drop(['Descript', 'Resolution'], axis = 1, inplace = True)
train_df.shape
이제 종속 변수에 해당하는 Category 데이터의 상위 5개, 하위 5개를 출력해보자.
# Category 데이터 상위5개
train_df['Category'].value_counts()[:5]
데이터를 확인해보면 절도죄, 폭행, 마약 관련 범죄가 가장 많았음을 확인할 수 있다.
그렇다면 하위 5개도 알아보자.
train_df['Category'].value_counts()[-5:]
Extortion은 강요죄를 의미한다. 강요죄, 성범죄, 도박과 관련된 범죄가 하위에 있음을 확인할 수 있다.
Category에 대해 알아본 후 요일별 범죄 발생 건수에 대해서 알아보자.
# 요일별 범죄 발생 건수 확인
temp = train_df.groupby('DayOfWeek').count().iloc[:, 0]
temp = temp.reindex([
'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'
])
print(temp)
샌프란시스코에서는 금요일에 범죄가 가장 많이 일어나는 반면, 일요일에 상대적으로 범죄 발생 건수가 적은 것을 확인할 수 있다. 이것을 시각화로 알아보자.
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib import cm
import numpy as np
fig, ax = plt.subplots(figsize = (10, 6))
ax = sns.barplot(
temp.index, (temp.values / temp.values.sum()) * 100,
orient = 'v')
ax.set_title('Incident Rates Rates', fontdict = {'fontsize' : 16})
ax.set_xlabel('Weekday')
ax.set_ylabel('Incidents (%)')
plt.show()
비율적으로 확인해도 금요일에 가장 많은 범죄가 발생하고, 상대적으로 일요일에 적은 숫자가 관측된다. 그렇다면 각각 범죄 유형이 요일마다 어떻게 다른지 확인해보자.
# 범죄 유형이 요일마다 어떻게 다른지 확인
print('DayOfWeek Incident for each category in percentage\n')
for idx, data in enumerate(train_df.groupby(['Category'])['DayOfWeek']):
print('The Current index is :', data[0])
print(round(data[1].value_counts() / data[1].count() * 100, 1))
print()
if idx == 3:
break
전체를 확인하기엔 너무 많기 때문에 4개만 확인했다. 전체를 확인하고 싶을 땐 if문을 삭제하면 된다.
이번에는 PdDistrict에 대해 알아보자.
# PdDistrict 탐색
temp = train_df.groupby('PdDistrict').count().iloc[:, 0]
print(temp)
확인해보면 SOUTHERN, MISSION, NORTHERN 지역 순으로 범죄 발생 건수가 높은 것을 확인할 수 있다. 그리고 상대적으로 PARK, RICHMOND 지역에서 범죄 발생 건수가 낮음을 확인할 수 있다. 그렇다면 시각화를 통해 확인해보자.
# 실제 어느 정도 차이가 나는지 시각화를 통해 확인
fig, ax = plt.subplots(figsize = (10, 6))
ax = sns.barplot(
temp.index, (temp.values / temp.values.sum()) * 100,
orient = 'v')
ax.set_title('Incident Rates by PdDistrict', fontdict = {'fontsize' : 16})
ax.set_xlabel('PdDistrict')
ax.set_ylabel('Incidents (%)')
plt.show()
이렇게 시각화로 보기 편하게 작성할 수 있다.
이번에도 마찬가지로 각각 범죄 유형이 지역마다 어떻게 다른지 이번에도 4개만 뽑아서 확인해보자.
# 범죄 유형이 지역마다 어떻게 다른지 확인
print('DayOfWeek Incident for each category in percentage\n')
for idx, data in enumerate(train_df.groupby(['Category'])['PdDistrict']):
print('The Current index is:', data[0])
print(round(data[1].value_counts() / data[1].count() * 100, 1))
print()
if idx == 3:
break
각 범죄의 유형마다 지역에서 차지하는 발생 비율도 다른 것을 확인할 수 있다.
이번에는 위도와 경도를 시각해보자.
# 위도 경도 시각화
fig, ax = plt.subplots(figsize = (10, 6))
sns.scatterplot(x = 'X', y = 'Y',
data = train_df, alpha = 0.01, hue = 'PdDistrict', ax = ax)
plt.show()
시각화를 해보면 이상치가 있는 것을 확인할 수 있다. 그림을 확인해보면 극단적으로 어떤 값을 제거해야 하는지 알 수 있다.
위의 절차를 통해 이상치를 제거하자.
그 후의 산점도를 다시 그려보자.
# 산점도
fig, ax = plt.subplots(figsize = (10, 6))
sns.scatterplot(x = 'X', y = 'Y',
data = train_df, alpha = 0.01, hue = 'PdDistrict', ax = ax)
plt.show()
산점도를 그려보면 각 지역별로 그룹화가 된 것을 확인할 수 있다. 한 단계 더 깊숙이 탐색하려면 범죄 유형을 세분화해 살펴보는 것도 방법이다. 예시로 LARCENY/THEFT의 값을 추출한 뒤 시각화해보자.
# LARCENY/THEFT 값의 데이터만 추출한 뒤 시각화(세분화)
theft_df = train_df[train_df['Category'] == 'LARCENY/THEFT']
theft_df.shape
fig, ax = plt.subplots(figsize = (10, 6))
sns.scatterplot(x = 'X', y = 'Y',
data = theft_df, alpha = 0.01, hue = 'PdDistrict', ax = ax)
plt.show()
시각화를 해보면, 어느 지역에서 해당 범죄가 많이 일어나는지 확인할 수 있다. 전체적으로 보면 NORTHERN, SOUTHERN, CENTRAL 관할 지역에서 절도 범죄가 많이 일어나며, 상대적으로 RICHMOND, TARAVAL 지역에서는 덜 일어나는 것을 확인할 수 있다. 만약 다른 범죄 유형을 확인하고 싶다면 소스 코드에서 LARCENY/THEFT 부분을 수정해 확인할 수 있다.
지금까지 간단한 시각화, EDA를 진행해 보았다. 모든 데이터 분석에서는 데이터의 분포를 확인하고, 그것을 시각화하여 데이터를 이해하는 것이 굉장히 중요하다고 생각한다.
다음 시간에는 이어지는 EDA와 피처 엔지니어링, 모델 구축까지 진행해 볼 예정이다.
'Kaggle' 카테고리의 다른 글
[샌프란시스코 범죄 분류] - 2 (0) | 2021.10.06 |
---|---|
[진짜 재난 뉴스 판별기] - 2 (0) | 2021.10.04 |
[진짜 재난 뉴스 판별기] - 1 (0) | 2021.10.01 |
[자전거 수요 예측] - 1 (0) | 2021.09.10 |
[타이타닉 생존자 분류] - 2 (0) | 2021.09.09 |