TOP
class="layout-aside-left paging-number">
본문 바로가기
[파이썬 Projects]/<파이썬 데이터 분석>

[워드클라우드] 코로나 뉴스 기사 (feat.주사기 마스킹)

by 기록자_Recordian 2024. 8. 19.
728x90
반응형
수행 내용 및 목표

 

엔데믹이 선언된 후 약 1년 좀 지난 요즘, 코로나 환자가 다시 증가하고 있다.

실제로 내 주변에도 최근 코로나 감염자가 증가하고 있다.

1) 네이버 뉴스에서 코로나 관련 기사들을 수집하여

2) 워드클라우드를 만들어보고,

3) 주사기 이미지에 마스킹하는 작업

4) 그리고 주요 단어들의 빈도수 분석 연관 분석을 실행해보려 한다.

★ 주피터 노트북을 통해 분석


주피터 노트북 파일 생성 및 세팅 하기

 

먼저 주피터 노트북을 실행하여 새로운 파이썬 파일을 생성한다.

파일명은 Corona_NLP로 하였다.

 

필요한 모듈을 import 하고, 기본 세팅을 한다.

from tqdm import tqdm_notebook
import urllib.request
import time
import requests

# 웹 스크래핑을 위한 BeautifulSoup와 urllib을 import 
from bs4 import BeautifulSoup
from urllib.request import urlopen
import urllib
import time

from bs4 import BeautifulSoup
from wordcloud import WordCloud

from konlpy.tag import Okt

import numpy as np
import pandas as pd

import platform
import matplotlib.pyplot as plt

%matplotlib inline

# wordcloud 라이브러리에서 WordCloud 클래스와 STOPWORDS 세트가져오기
from wordcloud import WordCloud, STOPWORDS

# Python 이미징 라이브러리(PIL) 가져오기
from PIL import Image

#한글 폰트 문제 해결
path = "c:/Windows/Fonts/malgun.ttf"

from matplotlib import font_manager, rc
if platform.system() == 'Windows':
    font_name = font_manager.FontProperties(fname=path).get_name()
    rc('font', family=font_name)
else:
    print('Sorry')

# 마이너스 기호가 깨지는 문제를 해결
plt.rcParams['axes.unicode_minus'] = False

네이버 뉴스에서 '코로나' 키워드로 기사 및 키워드 수집

 

기본 세팅을 마친 뒤, 네이버 뉴스 내용을 크롤링할 코드를 입력한다.

해당 영역에 뜨는 키워드들을 수집할 예정이다.

# 검색할 질의어 설정
query = "코로나"

# 검색 결과 페이지 URL
url = f"https://search.naver.com/search.naver?ssc=tab.news.all&where=news&sm=tab_jum&query={query}"
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}

# 코로나 기사에 대한 후보 텍스트를 저장할 리스트를 초기화.
python_article_text = []  

start_num = 0  # 변수 초기화

# 범위 내에서 페이지를 반복하여 검색 결과를 가져오는 반복문.
for n in tqdm_notebook(range(1, 100, 10)):
    # 현재 페이지 URL
    page_url = f"{url}&start={start_num}"
    
    # HTTP GET 요청 보내고 응답 받기
    response = requests.get(page_url)
    
    # BeautifulSoup을 사용하여 HTML을 파싱.
    soup = BeautifulSoup(response.text, "html.parser")
  
    # HTML에서 모든 <div> 태그를 찾아서 가져옴.
    tmp = soup.find_all('div')
    
    # 각 태그에서 텍스트를 추출하여 python_article__text 리스트에 추가.
    for line in tmp:
        python_article_text.append(line.text)
    
    # 서버에 부담을 주지 않기 위해 0.5초의 간격을 두고 잠시 대기.
    time.sleep(0.5)

수집에 약 10초가 걸렸다.

해당 내용들은 python_article_text 변수에 저장되었다.

해당 변수를 입력하면

python_article_text


형태소 분석 및 토큰화

 

1) 먼저 nltk 모듈을 import 하고 okt 클래스도 불러온다

import nltk
from konlpy.tag import Okt; o = Okt()

 

2) 크롤링해서 저장한 python_article_text 리스트의 내용들을 줄 바꿈을 추가하여 새로운 텍스트로 나눈다.

# python_article_text 리스트에서 처음 100개의 요소를 가져와서 하나의 문자열인 python_text에 추가

#python_text 변수를 빈 문자열('')로 초기화
python_text = ''

# for 루프를 사용하여 python_article_text의 각 요소를 순회
for each_line in python_article_text[:100]: # python_article_text 리스트의 처음 100개의 요소를 가져옴

# 각 요소를 python_text 문자열에 추가(줄바꿈 문자('\n')를 추가하여 한 줄씩 새로운 텍스트로 구분)
    python_text = python_text + each_line + '\n'

 

3)  토큰화

tokens_ko = o.morphs(python_text)
tokens_ko

 

총 단어수와 중복을 제외한 단어수를 조회해보면

ko = nltk.Text(tokens_ko, name='코로나')
print(len(ko.tokens))
print(len(set(ko.tokens)))

총 단어 수는 8,737개 / 중복되지 않은 단어 수는 640개 이다.

 

4) 빈도수 확인
그리고 자연어 처리 (NLP)를 사용하여 텍스트 데이터에서 가장 자주 등장하는 단어들을 추출해보면

ko = nltk.Text(tokens_ko, name='코로나')
ko.vocab().most_common(300)


불용어 처리 후 빈도수 그래프 그리기

 
1) 앞서 빈도수 조회를 토대로 의미 없는 단어들을 찾아낸 뒤, 불용어 처리를 해준다.

# 불용어처리(여러 번 수행)
stop_words = [',', '을', '은', '는', '이', '가', 'keep', '(', '으로', '...',
              '하기', '의', '를', '된', '컨', '조', '순', '도', '바로가기',
              '자세히', '/', '한', '해', '・', '', '△', '·', '3', '개월', '로',
              '된다면', '주세요', '지', '에서', '등', '40', '1', '와', '끄기',
             '.','에','언론사',')','보기','닫기','도움말','전체','선택','keep',"'", 
             '과','펼치기','접기','화','인','-','언','하','1시간','"', '언론사', '19',
             '전','네이버뉴스','선정','옵션','선택','저장','전체', '6', '제','뉴스',
             ]

# 불용어가 제거된 텍스트를 기반으로 nltk 라이브러리의 Text 객체를 생성
tokens_ko = [each_word for each_word in tokens_ko if each_word not in stop_words]

ko = nltk.Text(tokens_ko, name='코로나')
ko.vocab().most_common(100)

1차 불용어 처리에도 관련없는 단어가 많이 나와서, 2차로 불용어를 추가해 준다.

# 불용어처리(여러 번 수행)
stop_words = [',', '을', '은', '는', '이', '가', 'keep', 'Keep', '(', '으로', '...',
              '하기', '의', '를', '된', '컨', '조', '순', '도', '바로가기', '…',
              '자세히', '/', '한', '해', '・', '', '△', '·', '3', '개월', '로',
              '된다면', '주세요', '지', '에서', '등', '40', '1', '와', '끄기', '…"',
             '.','에','언론사',')','보기','닫기','도움말','전체','선택','keep',"'", 
             '과','펼치기','접기','화','인','-','언','하','1시간','"', '언론사', '19',
             '전','네이버뉴스','선정','옵션','선택','저장','전체', '6', '제','뉴스','Keep'
             '…','명','검색','문서','2시간','지식','관련', '연합뉴스','동영상','3시간','5시간',
             '메인','청','부터','다음','중','6시간','유형', '분류', '뉴시스', '레이어', '4시간', '기사',
             '입니다', '건', '속', '블로그', '재', 'iN', '카페', '이미지', '쇼핑', '도서', '학술',
             '설정', '어', '학사', '전지', '모바일', '입력', '최신', '별', '개', '‘']

# 불용어가 제거된 텍스트를 기반으로 nltk 라이브러리의 Text 객체를 생성
tokens_ko = [each_word for each_word in tokens_ko if each_word not in stop_words]

ko = nltk.Text(tokens_ko, name='코로나')
ko.vocab().most_common(100)

 

빈도수 그래프도 그려본다

plt.figure(figsize=(15,6))
ko.plot(50)
plt.show()

빈도수 그래프 생성


워드 클라우드 그리기

 
빈도수가 높은 단어 300개를 가지고 워드 클라우드를 생성한다.

# 데이터 준비
data = ko.vocab().most_common(300)

# 워드클라우드 객체 생성 (폰트 지정)
wordcloud = WordCloud(font_path="c:/Windows/Fonts/malgun.ttf",
                      relative_scaling=0.5,  # 상대적인 크기 조정값 설정
                      background_color='white',  # 배경은 흰색
                      width=800, height=400  # 이미지의 가로와 세로 크기 설정
                      )

# 텍스트 생성
text = "\n".join([f"{word}: {freq}" for word, freq in data])

# 워드클라우드 생성
wordcloud.generate(text)

# 이미지 출력
plt.figure(figsize=(16, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')
plt.show()


주사기 이미지 다운로드 및 불러오기

 

먼저, 구글에서 주사기 png 파일을 검색하여 다운로드 해본다.

다운 받은 png 파일을 파이썬으로 불러온다.

# 주사기 이미지 불러오기
# 이미지 파일을 NumPy 배열로 로드
syringe_mask = np.array(Image.open(r'C:\Users\pc02\Downloads\syringe_mask.png'))
text = "\n".join([f"{word}: {freq}" for word, freq in data])

#Matplotlib의 imshow() 함수를 사용하여 syringe_mask로 표시되는 이미지를 표시/컬러맵은 회색조/ 이중선형 보간법
plt.figure(figsize=(8, 8))
plt.imshow(syringe_mask, cmap=plt.cm.gray, interpolation='bilinear')
plt.axis('off') #플롯에서 축 제거
plt.show()

이미지가 잘 로드되었다


빈도 분석된 단어를 그림에 겹치기

 

# 워드클라우드 객체 생성 (폰트 지정 및 마스크 적용)
wordcloud = WordCloud(
    font_path="c:/Windows/Fonts/malgun.ttf",  # 한글 폰트 경로 지정 (필요한 경우)
    background_color='white',  # 배경은 흰색
    mask=syringe_mask,  # 주사기 마스크 이미지 적용
    contour_color='black',  # 외곽선 색상 설정 (선택 사항)
    contour_width=1,  # 외곽선 두께 설정 (선택 사항)
    width=800,  # 이미지의 가로 크기 (마스크 이미지에 맞춰 조정)
    height=400  # 이미지의 세로 크기 (마스크 이미지에 맞춰 조정)
).generate(text)

# 워드클라우드 이미지 출력
plt.figure(figsize=(16, 8))
plt.imshow(wordcloud, interpolation='bilinear')
plt.axis('off')  # 플롯에서 축 제거
plt.show()


유사도 파악하기

 
먼저 word2vec 라이브러리를 임포트하고

from gensim.models import word2vec

 

조사나 어미 등을 제거하는 과정을 거치고

okt = Okt()
results = []
lines = python_article_text

for line in lines:
    malist = okt.pos(line, norm=True, stem=True)
    r = []

    for word in malist:
        if not word[1] in ["Josa", "Eomi", "Punctuation"]:
            r.append(word[0])

    r1 = (" ".join(r)).strip()
    results.append(r1)
    print(r1)

 

이렇게 만들어진 데이터를 저장.

data_file = 'co_article.data'
with open(data_file, 'w', encoding='utf-8') as fp:
    fp.write("\n".join(results))
# Word2Vec 임포트
from gensim.models import Word2Vec

# 파일 경로
data_file = 'co_article.data'

# 문장 단위로 읽어들이기
sentences = word2vec.LineSentence(data_file)

# 모델 학습
model = Word2Vec(sentences, vector_size=100, window=5, min_count=5, workers=4)

# 학습된 모델 저장
model.save('co_article.model')

 

그리고 모델을 불러와서

model = word2vec.Word2Vec.load('co_article.model')

 

'코로나'와 유사한 단어를 추출하면

model.wv.most_similar(positive=['코로나'])

조선, 0시간, 네이버뉴스 등의 단어가 나오기 때문에, 필요없는 단어들을 뺀 결과를 확인해 본다.

model.wv.most_similar(positive=['코로나'], negative=['조선', '7시간', '네이버뉴스', 'TV', '6시간', '화','Corp','군', '같다', '간'])

 

728x90
반응형