데이터 출처 : https://www.kaggle.com/kimjihoo/coronavirusdataset#patient.csv
코로나19의 확진자가 급증하고 있다. 사람들은 현관문을 걸어잠그고 두문불출하고 있으며(나 역시 마찬가지다) 마스크를 구입하기 위한 외출만이 잦은 상태다. 한국은 높은 진단률로 많은 확진자들을 발견했고 그만큼 많은 데이터들을 생산해내고 있다. 현 시국이 매우 개탄스러운 상황임은 맞지만 데이터 분석을 공부하는 사람들의 입장에선 리얼 데이터를 다뤄볼 수 있는 기회인 셈이기도 하다.
코로나 관련 데이터를 분석해보고 싶다는 생각은 사실 코로나19 발병 초기부터 갖고 있었다. 몇 주 전부터 트위터 데이터를 수집해 코로나 연관 검색어를 분석하는 등 데이터 분석 공부를 하면서 코로나 데이터를 찔끔찔끔 건드리고는 있었다. 품이 많이 들어갈 것 같은 일에는 함부로 뛰어들지 못하는 성격이라 제대로 분석해보지 못했는데 개강이 늦춰진 만큼 시간이 조금 생겼고 이 시간 동안 코로나19 데이터를 분석하고 시각화한 결과물을 티스토리에 올릴 생각이다.
많이 부족한 실력이지만 앞으로 약 한 달에 걸쳐 코로나19 데이터 분석이 이뤄질 것이고, 최종적으로는 이로부터 유의미한 무언가를 도출해낼 수 있기를 희망한다. 데이터는 다양하게 다룰 예정이다. 정형, 비정형 등 다양한 유형의 데이터를 다룰 것이며 데이터는 직접 수집(크롤링), 이미 구축된 데이터셋(캐글 등)을 통해 수집할 것이다.
본 토이 프로젝트는 데이터 분석을 공부하고 있는 학부생의 부끄러운 수준에 머물 것이라는 점을 미리 양해구하며, 프로젝트의 목적은 1) 그동안 공부한 내용을 데이터 분석의 전체 프로세스에 따라 진행해보고 2) 데이터로부터 유의미한 가치를 도출해내기 위한 것임을 미리 밝힌다. 본격적으로 데이터를 수집하고 분석하기에 앞서 캐글의 데이터셋을 매우 러프한 수준에서 전처리하고 시각화하는 것으로 프로젝트를 시작한다.(캐글 데이터셋을 만드신 김지후님께 감사하다는 말씀을 먼저 전한다)
import pandas as pd
import numpy as np
import matplotlib; matplotlib.rc('font', family='Malgun Gothic')
import matplotlib.pyplot as plt
import seaborn as sns
import missingno as msno
import warnings; warnings.filterwarnings('ignore')
1. 데이터 기초정보 살펴보기¶
patient = pd.read_csv('../corona/patient.csv')
print(patient.shape)
patient.head()
patient.info()
# id는 범주형 변수이므로 데이터 타입을 바꾼다
patient['id'] = patient['id'].astype(str)
patient.info()
msno.bar(patient)
- 일단 결측치가 매우 많음
- 전염 원인(infection reason) 컬럼의 결측치도 매우 많은 것으로 보아 전염된 이유(전염 경로)를 확인하지 못한 케이스가 많다고 추측됨
- 그 외의 다른 컬럼들에도 결측치가 많음
patient.describe(include='all')
2. 탐색 & 전처리¶
먼저 각 컬럼들을 살펴보자¶
sex¶
print(patient.sex.value_counts())
patient['sex'].value_counts().plot.bar()
female 한 명이 따로 분리돼있다. 아마 단어 끝에 띄어쓰기가 들어가서 다른 값으로 분류된 것 같다. 이를 하나로 합친다
def sex_clean(df):
if pd.isnull(df):
return np.nan
if 'female' in df:
return 'female'
else:
return df
patient['sex'] = patient['sex'].apply(sex_clean)
patient['sex'].value_counts()
birth_year¶
patient['birth_year'].value_counts()
연도 뒤에 .0이 붙어있다
def birth_year_clean(df):
return str(df).split('.')[0]
patient['birth_year'] = patient['birth_year'].apply(birth_year_clean)
patient.head(3)
# 객체로 변환된 값들을 다시 float형으로 바꿔준다
patient['birth_year'] = patient['birth_year'].astype(float)
patient.dtypes
country & region¶
print(patient['country'].isnull().any())
print(patient['region'].isnull().any())
patient[['country', 'region']].head()
print(patient['country'].value_counts())
print(patient['region'].value_counts())
- region 컬럼의 경상북도가 'Gyeongsangbuk-do', 'gyungsangbuk-do' 두 개로 나눠져 있다. 같은 컬럼이므로 하나로 합친다(Gyeongbuk)
- Gangwon-do를 Gangwon으로
- Jeollabuk-do를 Jeonbuk으로
- Daejeon, Daejon을 Daejeon 하나로
- Chungcheongnam-do와 Chungcheongbuk-do를 하나로 합쳐 Chungcheong으로
- Capital city를 Capital로
def region_clean(df):
if pd.isnull(df):
return np.nan
else:
return df.replace('Gyeongsangbuk-do', 'Gyeongbuk').replace('Gyungsangbuk-do', 'Gyeongbuk').\
replace('Gangwon-do', 'Gangwon').replace('Jeollabuk-do', 'Jeonbuk').replace('Daejon', 'Daejeon').\
replace('Chungcheongnam-do', 'Chungcheong').replace('Chungcheongbuk-do', 'Chungcheong').replace('capital city', 'Capital').\
replace('capital area', 'Capital')
patient['region'] = patient['region'].apply(region_clean)
patient['region'].value_counts()
group, infection_reason, state¶
print(patient['group'].value_counts()); print('----------')
print(patient['infection_reason'].value_counts()); print('----------')
print(patient['state'].value_counts())
confirmed_date, released_date, deceased_date¶
msno.bar(patient[['confirmed_date', 'released_date', 'deceased_date']],
fontsize=30)
released_date와 deceased_date에는 결측치가 많다
confirmed_date를 위주로 봐야할 것 같다
먼저, int타입으로 되어있는 date 컬럼들을 datetime타입으로 바꾼다
patient['confirmed_date'] = pd.to_datetime(patient['confirmed_date'])
patient['released_date'] = pd.to_datetime(patient['released_date'])
patient['deceased_date'] = pd.to_datetime(patient['deceased_date'])
patient.dtypes
일별 확진자 추이를 그려보자¶
퇴원한 사람, 사망자 추이를 제외하는 건 현재 캐글 데이터의 해당 피처들에 결측치가 많기 때문에 정보가 부정확하다고 판단했기 때문.
추후 데이터를 직접 수집하고 업데이트해 다시 확인할 예정임
len(patient['id'].unique())
id컬럼에는 중복값이 없다.
이를 확인하는 이유는 아래 피봇테이블에서 써먹을 것이기 때문.
confirmed = pd.pivot_table(data=patient,
index='confirmed_date',
values='id',
aggfunc='count')
confirmed
1월 20일부터 2월 28일까지의 확진자 추이는 다음과 같다
sns.set(font_scale=1.4)
plt.rc('font', family='Malgun Gothic')
confirmed.plot(color='g', figsize=(18, 10))
plt.title('1/20~2/28 국내 확진자 추이')
plt.figure(figsize=(18,10))
sns.pointplot(data=confirmed.reset_index(), x=np.arange(len(confirmed.reset_index()['confirmed_date'])), y='id')
확진자 분포는 어떨까?
plt.figure(figsize=(18,10))
sns.distplot(confirmed, bins=3, hist=False)
plt.title('확진자 분포')
컬럼 순서 정리¶
분석에 주로 쓸 컬럼들을 앞쪽으로 뺀다
col = ['id',
'sex',
'country',
'region',
'birth_year',
'state',
'confirmed_date',
'released_date',
'deceased_date',
'infection_reason',
'contact_number',
'group',
'infected_by',
'infection_order']
df = patient[col].copy()
df.head()
'Legacy > [Legacy] Project' 카테고리의 다른 글
[토이프로젝트1] 코로나19 데이터 각 컬럼 시각화 및 ARIMA/Prophet 분석 (0) | 2020.03.05 |
---|