코로나 19 데이터 시각화 프로젝트 - 시각화 및 데이터 분석

코로나 데이터를 통해 알아보는 시각적 접근

 

서론

코로나19와 함께 싸워온 지난 날들의 데이터를 바탕으로 초기 감염자가 바이러스를 확산해 가는 과정들을 분석하는데 초점을 맞추어보았습니다.

현재 우리나라뿐만 아니라 세계적으로 문제가 되고 있는 코로나 바이러스에 대한 시각화와 인사이트 분석을 통해 저희가 공부한 것을 적용해 보고자 하였습니다. 이번 프로젝트로 인해 데이터 시각화 여러 기술을 접해보고 오류도 해결해 나가면서 배운 것이 많습니다. 아직 많이 부족하지만, 나름대로 표현 하고자 했던 것을 그려놓았으니 재밌게 봐주시기 바랍니다!

저희는 뉴스 데이터를 통해 코로나가 이슈화 되었던 시기와 코로나19 관련 키워드들 중에 이슈가 되는 키워드에 집중하여 접근하였습니다. 그리고 이어서 새로운 논점을 제시하여 이를 다양한 방법으로 표현하려고 하였습니다. 이 과정에서 저희는 초기집단 감염자들의 확산 루트와 파급력에 대해 집중하였는데, 이는 이슈화 되었던 시기의 패턴을 분석하여 집단감염을 예방하는데 도움을 줄 수 있을 것입니다. 또한 마스크 5부제와 사회적 거리두기 정책의 실행 전후에 코로나 확산이 어떻게 이루어졌는지 분석하면서 마무리하도록 하겠습니다.

 

 

코로나에 대한 사람들의 관심

코로나를 언급한 뉴스의 기사 건수를 그래프화 해보자.

path = r'./'
corona_news = pd.read_csv(path + "corona_news_count.csv")
corona_news_df = pd.pivot_table(corona_news, values='date', index=['date'])
corona_news_df

 

path_gmarket = path +'GmarketSansTTFMedium.ttf'
font_gmarket = fm.FontProperties(fname=path_gmarket, size=16)
plt.style.use('ggplot')

fig = plt.figure(figsize=(20,10))
plt.plot(corona_news_df.index, corona_news_df, '-ok')
plt.plot([corona_news['date'][corona_news[corona_news['date']=='2020-01-20'].index[0]],
          corona_news['date'][corona_news[corona_news['date']=='2020-01-20'].index[0]]], 
         [-500, 17500], 
         lw=4, 
         c='pink')
plt.plot([corona_news['date'][corona_news[corona_news['date']=='2020-02-18'].index[0]],
          corona_news['date'][corona_news[corona_news['date']=='2020-02-18'].index[0]]],
         [-500, 17500],
         lw=4,
         c='pink')

fig.suptitle('\n코로나 언급 뉴스 기사 건수', fontproperties=font_gmarket, fontsize=20, position=(0.5, 0.95))
plt.annotate('국내 첫 확진',[corona_news['date'][corona_news[corona_news['date']=='2020-01-20'].index[0]-4], 18000],fontsize=15, fontproperties=font_gmarket)
plt.annotate('신천지 집단 감염',[corona_news['date'][corona_news[corona_news['date']=='2020-02-18'].index[0]-6],18000],fontsize=15, fontproperties=font_gmarket)

plt.xticks(['2020-01-01', '2020-01-15', '2020-01-20', '2020-02-01', '2020-02-15', '2020-02-18', '2020-03-01', '2020-03-15', '2020-04-01', '2020-04-15', '2020-05-01', '2020-05-15', '2020-06-01', '2020-06-15', '2020-07-01', '2020-07-15', '2020-08-01', '2020-08-15', '2020-09-01'],
           rotation=45, fontproperties=font_gmarket, fontsize=10)
plt.yticks(fontproperties=font_gmarket, fontsize=10)

plt.xlabel('\n일자', fontproperties=font_gmarket, fontsize=18)
plt.ylabel('\n뉴스기사 건수', fontproperties=font_gmarket, fontsize=18)
plt.xlim(0, '2020-05-01')

plt.show()

* 데이터가 주기적으로 증감현상을 보이는 것은 주말 휴일에 기사를 내지 않아서 입니다.

 

1월부터 6월까지의 네이버 '많이 본 뉴스' 기사 제목에서 코로나 관련 핫 토픽을 알아보자.

 

* count_list_cov19 = { '이유': 226, '신천지': 225,'속보': 219, '논란': 217, '한국': 182, '마스크': 163,
                             '종합': 160, '단독': 154, '확진': 127, '교회': 126,'감염': 115,'오늘': 96, '건강': 95, '공개': 92,
                             '뉴스': 89, '예배': 89, '전국': 87, '정부': 64, '국내': 63, '환자': 61, '격리': 59, '우한': 56,
                             '총': 56,'中': 53,'병원': 53, '치료': 52, '신도': 52, '방역': 49,'이슈': 48 }

 

my_wc = WordCloud(font_path= path + 'NanumBarunGothicBold.ttf', background_color='white')
plt.imshow(my_wc.generate_from_frequencies(count_list_cov19))
plt.axis('off')
plt.show()

 

가장 크게 보이는 '신천지'와 '코로나'는 우리나라 사람들에게 얼마나 많은 관심을 받았는지 알 수 있다.

  • 그만큼 코로나의 확산에 신천지의 영향력이 컸다는 것을 보여준다.
  • 신천지의 초기 발생지인 대구 지역감염에서 전국적인 확산으로 어떻게 발전했는지 알아보자.

 

대구 코로나 확산

대구지역에서 있었던 초기 감염자를 찾아보자.

region = pd.read_csv(path+"Region.csv")
patientinfo = pd.read_csv(path+"Patientinfo.csv")
patientroute = pd.read_csv(path +"PatientRoute.csv")
case =  pd.read_csv(path + "Case.csv")
df_info = pd.DataFrame(patientinfo)
df_region = pd.DataFrame(region)

 

# 위도, 경도 추출

info_31_loc = pd.merge(region, info_31, on=['city','province'])
home_31 = info_31_loc[['latitude', 'longitude']]
home_31

# 초기 확진자가 다녀갔던 장소의 위도 , 경도 추출

route_31 = patientroute[patientroute['patient_id']==1200000031].reset_index()
route_31

 

route_31_pos = route_31[['latitude', 'longitude']]
route_31_pos

 

# 31번 확진자가 이동한 동선을 영역으로 시각화하였습니다.

import folium
from folium import plugins
map_data = folium.Map([35.765788, 128.619197], zoom_start=10)
lines = route_31_pos.values[:].tolist()

folium.PolyLine( 
    locations=lines,
    fill=True,
    color='orange').add_to(map_data)

map_data

 

# 31번 확진자로 인해 감염된 사람들 리스트
infected_31 = patientinfo[(patientinfo['infected_by']=='1200000031')].reset_index()
infected_31['city'] = infected_31['city'].fillna('Daegu')
infected_31
merge_df = pd.merge(df_region, infected_31, on=['city','province'])
result = merge_df[['latitude', 'longitude']]
result_lines = result.values[:].tolist()
map_count = folium.Map([36.4, 128], zoom_start=7)

plugins.MousePosition().add_to(map_count) 
plugins.MarkerCluster(result).add_to(map_count)

folium.PolyLine( 
    locations=result_lines,
    color='orange').add_to(map_count)

folium.CircleMarker(
    home_31,
    radius=10,
    fill_color='red',
    color='red',
    weight=7).add_to(map_count)

map_count

  • 31번 확진자가 빨간색으로 표시되어있고 31번 확진자가 감염시킨 사람들을 이어놓은 그래프 시각화입니다.
  • 시각화 자료에서 숫자는 해당 지역 주변에 거주하는 확진자 수이며, 파란 핀의 아이콘은 거주하는 확진자 수가 한 명 일때의 표시입니다.

 

신천지로 인한 대구 내 지역 감염을 시각화 해보자.

import folium
from folium import plugins

region = pd.read_csv(path+"Region.csv")
patientinfo = pd.read_csv(path+"Patientinfo.csv")
patientroute = pd.read_csv(path +"PatientRoute.csv")
case =  pd.read_csv(path + "Case.csv")

case.head()
df_case = case[case["group"] == True]
case[case["infection_case"] == "etc"]

* etc(기타등등)의 집담감염은 전부 FLASE이므로 비집단감염이다.

 

case[case["infection_case"] == "contact with patient"]

* contact with patient의 집담감염은 전부 FLASE이므로 비집단감염이다.

 

subset = pd.DataFrame(result[['province','city', 'latitude', 'longitude','infection_case']])
subset.head()

# 1 subset = [(시,도), 도시, 위도, 경도, 감염 요인]

sigungu_count = result[['latitude','longitude']].dropna()
sigungu_count.head()

 

# 2 대구 지역 감염 원인 순위

# 대구 지역은 etc가 많은 것으로 보아 정확한 감염 원인 분석이 이루어지지 않은 것으로 보인다.
subset_DaeguGyeongbuk = pd.DataFrame(subset[(subset.province =='Daegu')])
subset_DaeguGyeongbuk = subset_DaeguGyeongbuk.reset_index()
subset_DaeguGyeongbuk['infection_case'].value_counts()

 

# 3 지도에 표시하기 위해 위도, 경도, 감염 요인으로 데이터 추출

# 감염 요인의 경우의 수를 count (같은 위도와 경도별로)
df_map = subset_DaeguGyeongbuk.groupby(["latitude", "longitude",'infection_case']).size().reset_index(name="count")
idx_num = df_map[df_map["count"] == 96].index
df_edit_map = df_map.drop(idx_num).reset_index()

 

# 4 색깔 지정 (신천지로 인한 감염 - darkblue)

df_edit_map['color']=0
for x in range(len(df_edit_map)):
    if (df_edit_map['infection_case'][x] == 'Shincheonji Church'):    
        df_edit_map['color'][x] = 'darkblue'
    #신천지가 감염경로가 아닌 지역들은 투명한 색생으로 표시
    else:    
        df_edit_map['color'][x] = 'red'
#     else:
#         df_map['color'][x] = 'red'   # 미확인(etc)
df_edit_map

 

# 5 우리나라 신천지 감염 구역 시각화

# 대구지역과 인근 지역에 주로 밀집해서 표현되는 것을 볼 수 있다.
Daegu_map = folium.Map(location=[35.845046, 128.598141], tiles="cartodbpositron", zoom_start=13)
for x in range(len(df_edit_map)):
    location = [df_edit_map['latitude'][x],df_edit_map['longitude'][x]]
    radius=df_edit_map['count'][x]*3.1

    folium.CircleMarker(
        location,
        radius,
        popup=df_edit_map['infection_case'][x],
        color=df_edit_map['color'][x],
        fill=True,
        fill_color=df_edit_map['color'][x],
        control_scale=True
        
    ).add_to(Daegu_map)
Daegu_map

* 아래 그림은 대구 지역 신천지로 인한 감염을 지도에 시각화한 결과를 보기 쉽게 캡쳐한 화면이다.

 

신천지로 인한 대구에서 유동인구로 인한 감염이 어떠했는지 알아보자.

 위에서 31번 확진자의 이동 경로를 보시면 대구 경북지역에서 12명의 감염자를 감염시켰는데, 이 감염자들이 2차 전파자가 되어 전국적인 코로나 확산에 지대한 영향을 미쳤습니다.

 

import networkx as nx
first_patient = patientinfo[patientinfo['infected_by']=='1200000031']
infected_by = first_patient[['infected_by', 'patient_id']]
infected_by
import networkx as nx
first_patient = patientinfo[patientinfo['infected_by']=='1200000031']
infected_by = first_patient[['infected_by', 'patient_id']]
infected_by

 

patient_add = patientinfo[(patientinfo['infected_by']=='1600000005')|(patientinfo['infected_by']=='2000000013'
                            )|(patientinfo['infected_by']=='2000000015')|(patientinfo['infected_by']=='2000000050')]

patient_add = patient_add[['infected_by', 'patient_id']]
patient_add = infected_by.append(patient_add)
patient_add

 

g = nx.from_pandas_edgelist(patient_add, 'infected_by', 'patient_id', create_using = nx.DiGraph())
pos = nx.spring_layout(g, scale=2.0)
nx.draw(g, with_labels=True, node_color='pink',node_shape='8',
        node_size=800, font_size=8)

  • 편의상 그림에서는 3차 감염자까지만 나타내었습니다.
  • 31번 환자로 인해 감염된 사람들이 2차 감염자가 되어 3차 감염자를 만들어 내고 있습니다.
  • 이 감염자들은 추후에 n차 감염자들을 양산해내었고, 전국적인 코로나 유행을 야기했습니다.

 

코로나 정책의 효과

이에 대한 정책으로 마스크 5부제 및 사회적 거리두기를 시행했을 때의 효과를 살펴보자.

# 각 일별 확진자 데이터 컬럼을 추가해줍니다.
Time = pd.read_csv('./Time.csv')
Time
Time['date'] = pd.to_datetime(Time['date'])
Time

def date_to_count(series):
    data=[0]
    for i in range(1,len(series)):
        data.append(series[i]-series[i-1])
    data =pd.DataFrame(data)
    return data
Time['confirmed_date'] = date_to_count(Time['confirmed'])
Time
from datetime import datetime
# 마스크 정책에 관한 그래프
plt.figure(figsize=(20,10))
sns.lineplot(x='date',y='confirmed_date',data=Time, palette="tab10", color='k', linewidth=2.5)
# 2020년 2월 26일부터 마스크 및 손소독제 긴급수급조정조치(마스크 수출금지, 마스크 생산량 50% 공직 판매처에 출고)
plt.axvline(x=datetime(2020, 2, 26), color='r', linestyle='--', linewidth=3,label="마스크 긴급수급조정조치")
# 2020년 3월 9일 마스크 5부제 시행
plt.axvline(x=datetime(2020, 3, 9), color='g', linestyle='--', linewidth=3,label="마스크 5부제")
plt.xticks(rotation=45)
plt.legend(fontsize=20)
plt.show()

 

# 사회적 거리두기의 효과를 나타내는 그래프

plt.figure(figsize=(20,10))
sns.lineplot(x='date',y='confirmed_date',data=Time, palette="tab10", color='k', linewidth=2.5)
# 2020년 3월 22일 부터 사회적 거리두기 정책을 시작합니다.
plt.axvline(x=datetime(2020, 3, 22), color='r', linestyle='--', linewidth=3,label="사회적 거리두기 시작")
# 원래는 2020년 4월 6일까지 사회적 거리두기 정책을 실시하기로 하였으나, 이를 4월 19일까지 연장합니다.
plt.axvline(x=datetime(2020, 4, 6), color='b', linestyle='--', linewidth=3, label="사회적 거리두기 연장")
# 4월 20일부터 5월 5일까지 다소 완화된 형태의 사회적 거리두기 정책을 시행합니다.
plt.axvline(x=datetime(2020, 4, 20), color='g', linestyle='--', linewidth=3, label="사회적 거리두기 완화")
# 코로나 확산세가 주춤하는 모습을 보이며 5월 6일부터 생활 속 거리두기(현재 사회적 거리두기 1단계) 체계로 전환화였습니다.
plt.axvline(x=datetime(2020, 5, 6), color='y', linestyle='--', linewidth=3, label="생활 속 거리두기")
# 이후 6월 28일부터 사회적 거리두기 정책을 1~3 단계로 구분하기 시작합니다.
plt.xticks(rotation=45)

plt.legend(fontsize=20)
plt.show()

  • 2020년 3월 22일부터 시작된 사회적 거리두기 정책은 대구 지역에서 코로나19의 확산세가 진정된 이후에 실시됨으로 인해 정책 시기 상 조금 늦은 감이 없지 않아 있었습니다.
  • 이러한 사회적 거리두기 정책은 기간을 연장함에 따라서 조금씩 확진자가 감소하는 효과를 보여주고 있습니다.
  • 5월 6일 이후부터 시작된 생활 속 거리두기 정책(현 사회적 거리두기 1단계) 이후에도 잘 유지되는 모습을 보여주고 있습니다.

 

결론

  • '신천지 집단감염'은, 31번 슈퍼 전파자로 인해 지역감염에서 전국적으로 확산되는데 많은 영향을 미쳤다.
  • 이 확진자가 신천지 예배 당시 460명 가량의 사람들과 같은 공간에 있었다는 것이 문제가 되었다. 그리고 31번 확진자가 용인 사람임에도 대구에 예배를 드리러 갔다는 사실을 묵인한 채, 신도들이 아닌 사람들과도 접촉한 사실이 밝혀지면서 더 이슈가 되었다.
  • 초기 '신천지 집단감염'의 근원지인 대구에서 신천지 교인들을 중심으로 대구 내 확진자 수가 급격하게 증가하였고, 슈퍼 전파자의 무책임한 행동으로 전국적으로 코로나 확산이 진행되었다.
  • 정부에서는 '사회적 거리두기'와 '마스크 5부제' 정책을 발의하여 확진자 수를 줄이기 위해 노력했고, 코로나가 종식되는 분위기를 보이면서 '생활 속 거리두기' 이후에도 확진자 수가 안정적으로 유지되는 양상을 보여준다.
  • 코로나 유행이 또 다시 시작되었을 때, 대구 신천지 집단감염 사건을 발판으로 더 빠른 대응을 할 수 있을 것이라 사료된다.
반응형