[Data] Frequency Analysis for Covid19 Keywords from Twitter, Naver & Creating WordCloud

2021, Dec 05    

필요한 module import

!pip install konlpy
import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt

from konlpy.tag import Twitter
from collections import Counter
from wordcloud import WordCloud
from tqdm import tqdm
  • crawling 할 때 사용한 source code 는 여기
naver_emo = pd.read_excel("/content/Naver/NAVER_코로나, 감정.xlsx")
naver_mood = pd.read_excel("/content/Naver/NAVER_코로나, 기분.xlsx")
naver_daily = pd.read_excel("/content/Naver/NAVER_코로나, 일상.xlsx")

twitter_emo = pd.read_excel("/content/Twitter/Tweets_코로나, 감정.xlsx")
twitter_mood = pd.read_excel("/content/Twitter/Tweets_코로나, 기분.xlsx")
twitter_daily = pd.read_excel("/content/Twitter/Tweets_코로나, 일상.xlsx")
naver_emo.rename(columns={'Tweets' : 'Contents'}, inplace=True)
naver_mood.rename(columns={'Tweets' : 'Contents'}, inplace=True)
naver_daily.rename(columns={'Tweets' : 'Contents'}, inplace=True)
naver_daily
Date Weekly Frequency Contents
0 20200101 558 [' 일상', '청주 봉명동 농수산물 도매시장 다농마트 물가정보 코로나 예방에 좋은...
1 20200107 592 ['중국 폐렴 원인 신종 코로나 바이러스 증상 및 예방법은', '마감코로나 잠정연...
2 20200114 580 ['왜 나는 항상 먹고나서 후회할까 원데이클래쓰 차 오픈 코로나 사태로 잠정 보류'...
3 20200121 892 [' 중국 남경 일상 신종 코로나 바이러스', '월일 화요일 신종 코로나바이러스 긴...
4 20200201 890 ['캄보디아씨엠립 일상 신종 코로나바이러스 상황', '일상코로나 어린이집휴원', '...
... ... ... ...
83 20210921 885 ['일상 코로나 시대 인천국제공항 다녀오기', ' 가을 그리고 코로나일상', '일...
84 20211001 880 ['일상 코로나 백신 접종 완료자가 밀접접촉자로 격리 되는 경우 후기얀센 백신', ...
85 20211007 886 ['파주 심학산 둘레길트레일 러닝코스코로나 일상', '일상 코로나 바이러스 감염 예...
86 20211014 882 ['일상 코로나 예방접종화이자 ', '월 프랑스 파리 날씨 위드코로나 일상 ', ...
87 20211021 881 ['위드코로나 뜻 월부터 일상 복귀 마스크 착용', '위드코로나 일상회복 이행계획 ...

88 rows × 3 columns

추출한 데이터에서 키워드별 빈도수 분석

- Stopwords 정의

remove = ["없었어요", "었어요", "한번", "적", "것", "한", "하게", "한게", "해요", "합니다",\
          "하여", "해서", "했습니다", "하나요", "할까요", "해가지고", "하니까", "하다고", "했는데"\
          "하면", "할까요", "하고", "했어요", "져서요", "집니다", "납니다", "하지만", "지만",\
          "할", "한걸까요", "까요", "입니다", "어떻게", "없어서", "그래서", "그런데", "그런", "근데", "같이",\
          "가끔", "너무", "때문", "때문에", "자꾸", "있을", "있는", "요즘", "약간", "영어",\
          "이런", "왜", "이럴까요", "저희", "우리", "많이", "계속", "다시", "이틀", "지금", "코로나", "백신",\
          "그냥", "부터", "승무원", '해도', "언젠가", "있으면", "시어머니", "아버님", "통장", "있고", "문장",\
          "현재", "치매", "해도", "있으면", "있고", "감정", "있었음", "있어요",\
          "그래도", "진자", "오늘", "같은", "기분", "진짜", "정말", "이번", "없는", "이렇게", "없이", "일상", "이제"]

- 기능별 함수 정의

1. 문장 –> 형태소 단위로 잘라서 list 에 append

def get_morphs(df_naver, df_twitter):
    twt = Twitter()

    global remove
    morphs = []
    morphs_twt = []

    for sentence in tqdm(df_naver['Contents']):
        morph = twt.pos(sentence)
        morphs.append(morph)

    for sentence in tqdm(df_twitter['Tweets']):
        morph = twt.pos(sentence)
        morphs_twt.append(morph)

    return morphs, morphs_twt 

2. 원하는 형태소만 추출해서 최종적으로 단어 리스트 만들기

def get_freqs_all(morphs, morphs_twt, keyword):
    words = []
    for sentence in tqdm(morphs):
        for elem in sentence:
          if elem[1] in ["Noun", "Adjective", "Adverb"]:
              tmp = elem[0]
              for r in remove:
                  tmp = tmp.replace(r, "")
              if tmp:
                words.append(tmp)

    words_twt = []
    for sentence in tqdm(morphs_twt):
        for elem in sentence:
          if elem[1] in ["Noun", "Adjective", "Adverb"]:
              tmp = elem[0]
              for r in remove:
                  tmp = tmp.replace(r, "")
              if tmp:
                words_twt.append(tmp)

    words = [word for word in words if len(word) > 1]
    words_twt = [word for word in words_twt if len(word) > 1]

    words_total = words + words_twt

    counter_total = Counter(words_total)
    freqs_total = counter_total.most_common(500)
    print(freqs_total[:30])

    freqs_total_df = pd.DataFrame(freqs_total, columns=['키워드', '빈도수'])
    freqs_total_df.to_excel(keyword + "_total_freq.xlsx")

    return freqs_total

키워드 빈도수 분석 결과를 Word Cloud 로 생성하기

!apt -qq -y install fonts-nanum > /dev/null
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
import matplotlib.font_manager as fm
fontpath="/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf"
font = fm.FontProperties(fname=fontpath)
from wordcloud import ImageColorGenerator
from PIL import Image

mask = np.array(Image.open('/content/cloud2.jpg'))
colors = ImageColorGenerator(mask)
def get_wordcloud(freqs, add_stopwords):
    stopwords = ["기초", "같고", "자주", "인해", "아이"]
    stopwords += add_stopwords
    
    wordcloud = WordCloud(font_path=fontpath, 
                          background_color="black",
                          relative_scaling=0.5,
                          colormap='tab20c',
                          mask = mask,
                          stopwords=stopwords,
                          contour_color='black',
                          )
    cloud = wordcloud.generate_from_frequencies(dict(freqs))
    plt.figure(figsize=(25, 8))
    plt.axis("off")
    plt.imshow(cloud)
    plt.show()

코로나 + 감정 from Naver, Twitter

morphs_emo, morph_emo_twt = get_morphs(naver_emo, twitter_emo)
/usr/local/lib/python3.7/dist-packages/konlpy/tag/_okt.py:16: UserWarning: "Twitter" has changed to "Okt" since KoNLPy v0.4.5.
  warn('"Twitter" has changed to "Okt" since KoNLPy v0.4.5.')
100%|██████████| 88/88 [03:06<00:00,  2.12s/it]
100%|██████████| 88/88 [00:23<00:00,  3.67it/s]
morphs_emo
morph_emo_twt
emo_freqs = get_freqs_all(morphs_emo, morph_emo_twt, "감정")
100%|██████████| 88/88 [00:08<00:00, 10.57it/s]
100%|██████████| 88/88 [00:00<00:00, 117.49it/s]


[('아이', 3647), ('마음', 3625), ('블루', 3284), ('사람', 2868), ('생각', 2705), ('시대', 2594), ('바이러스', 2508), ('시간', 1914), ('우울', 1795), ('인해', 1763), ('상황', 1734), ('불안', 1581), ('극복', 1552), ('이후', 1502), ('스트레스', 1468), ('엄마', 1348), ('함께', 1325), ('생활', 1287), ('사회', 1266), ('코칭', 1261), ('표현', 1226), ('심리', 1120), ('검사', 1119), ('많은', 1118), ('있다', 1118), ('조절', 1059), ('교육', 1053), ('방법', 1029), ('건강', 1029), ('시작', 1027)]
emo_freqs[:30]
[('아이', 3647),
 ('마음', 3625),
 ('블루', 3284),
 ('사람', 2868),
 ('생각', 2705),
 ('시대', 2594),
 ('바이러스', 2508),
 ('시간', 1914),
 ('우울', 1795),
 ('인해', 1763),
 ('상황', 1734),
 ('불안', 1581),
 ('극복', 1552),
 ('이후', 1502),
 ('스트레스', 1468),
 ('엄마', 1348),
 ('함께', 1325),
 ('생활', 1287),
 ('사회', 1266),
 ('코칭', 1261),
 ('표현', 1226),
 ('심리', 1120),
 ('검사', 1119),
 ('많은', 1118),
 ('있다', 1118),
 ('조절', 1059),
 ('교육', 1053),
 ('방법', 1029),
 ('건강', 1029),
 ('시작', 1027)]
get_wordcloud(emo_freqs, [])


코로나 + 기분 from Naver, Twitter

morphs, morphs_twt = get_morphs(naver_mood, twitter_mood)
/usr/local/lib/python3.7/dist-packages/konlpy/tag/_okt.py:16: UserWarning: "Twitter" has changed to "Okt" since KoNLPy v0.4.5.
  warn('"Twitter" has changed to "Okt" since KoNLPy v0.4.5.')
100%|██████████| 88/88 [02:48<00:00,  1.92s/it]
100%|██████████| 88/88 [01:17<00:00,  1.13it/s]
morphs
morphs_twt
mood_freqs = get_freqs_all(morphs, morphs_twt, "기분")
100%|██████████| 88/88 [00:10<00:00,  8.22it/s]
100%|██████████| 88/88 [00:03<00:00, 27.12it/s]


[('검사', 5808), ('접종', 3805), ('좋은', 3364), ('전환', 3328), ('사람', 3164), ('일상', 2946), ('여행', 2906), ('마스크', 2594), ('생각', 2505), ('블루', 2478), ('바이러스', 2473), ('후기', 2410), ('시간', 2144), ('시대', 2048), ('마음', 1965), ('하루', 1714), ('아이', 1620), ('우울', 1579), ('시작', 1493), ('극복', 1396), ('이후', 1370), ('생활', 1310), ('화이자', 1246), ('좋게', 1224), ('거리', 1196), ('상황', 1185), ('격리', 1179), ('인해', 1160), ('이제', 1155), ('집콕', 1142)]
get_wordcloud(mood_freqs, ["그래도", "진자", "오늘", "같은", "기분", "진짜", "정말", "이번", "없는", "이렇게", "없이"])

코로나 + 일상 from Naver, Twitter

morphs_daily, morphs_daily_twt = get_morphs(naver_daily, twitter_daily)
/usr/local/lib/python3.7/dist-packages/konlpy/tag/_okt.py:16: UserWarning: "Twitter" has changed to "Okt" since KoNLPy v0.4.5.
  warn('"Twitter" has changed to "Okt" since KoNLPy v0.4.5.')
100%|██████████| 88/88 [03:00<00:00,  2.05s/it]
100%|██████████| 86/86 [02:16<00:00,  1.58s/it]
morphs_daily
morphs_daily_twt
daily_freqs = get_freqs_all(morphs_daily, morphs_daily_twt, "일상")
100%|██████████| 88/88 [00:08<00:00, 10.14it/s]
100%|██████████| 86/86 [00:04<00:00, 17.32it/s]


[('생활', 4734), ('마스크', 4150), ('접종', 4043), ('회복', 3428), ('바이러스', 3316), ('사람', 2924), ('출장', 2815), ('단계', 2593), ('검사', 2592), ('시간', 2557), ('하루', 2497), ('위드', 2420), ('시작', 2301), ('함께', 2279), ('거리', 2218), ('여행', 2199), ('생각', 2139), ('아이', 2085), ('방역', 2073), ('집콕', 2051), ('카페', 1975), ('재앙', 1951), ('만남', 1950), ('미국', 1938), ('이후', 1781), ('시대', 1772), ('모두', 1662), ('사회', 1587), ('행복', 1586), ('상황', 1544)]
daily_freqs[:30]
[('생활', 4734),
 ('마스크', 4150),
 ('접종', 4043),
 ('회복', 3428),
 ('바이러스', 3316),
 ('사람', 2924),
 ('출장', 2815),
 ('단계', 2593),
 ('검사', 2592),
 ('시간', 2557),
 ('하루', 2497),
 ('위드', 2420),
 ('시작', 2301),
 ('함께', 2279),
 ('거리', 2218),
 ('여행', 2199),
 ('생각', 2139),
 ('아이', 2085),
 ('방역', 2073),
 ('집콕', 2051),
 ('카페', 1975),
 ('재앙', 1951),
 ('만남', 1950),
 ('미국', 1938),
 ('이후', 1781),
 ('시대', 1772),
 ('모두', 1662),
 ('사회', 1587),
 ('행복', 1586),
 ('상황', 1544)]
get_wordcloud(daily_freqs, ["일상", "이제"])