두번째 프로젝트는 가짜 뉴스 구별하기이다.
우선 프로젝트의 목적은 이름처럼 가짜뉴스와 진짜뉴스데이터로 학습시킨뒤에 우리가 어떤 뉴스데이터를 가져왔을 때 그게 가짜인지 진짜인지 구별하는 것이다. 우리는 영어뉴스로 프로젝트를 시작했는데, 그 이유는 한국어로 하면 너무 분류가 어렵기 때문이다..데이터를 정제하는 것도 어렵고, 의미파악 등등 한국어는 너무 어려웠다.
오늘은 자연어처리 중 첫번째인 전처리에 대해서 간략하게 설명하고 뉴스데이터에 대한 전처리까지 진행해보겠다.
[데이터]
데이터는 캐글에 있는 데이터를 가져왔다.
데이터는 우선 가짜뉴스 파일과 진짜뉴스 파일이 따로 포함되어있다.
import pandas as pd
import numpy as np
fdata=pd.read_csv("/content/drive/MyDrive/Personal Project/Classify_fake-news/Fake.csv")
tdata=pd.read_csv("/content/drive/MyDrive/Personal Project/Classify_fake-news/True.csv")
우선 가짜뉴스와 진짜뉴스 데이터를 pandas의 데이터프레임 형태로 가져오고, 데이터를 출력해보면 아래와같다.
데이터의 형태는 title,text,subject,date 컬럼으로 이루어져있다.(가짜,뉴스 둘 다 동일하다.)
[데이터 정제]
[자연어처리]
우선 이번 프로젝트 분류의 대주제는 자연어처리이기 때문에 처음이니만큼 자연어처리에 대해서 간략하게 설명하겠다. 자연어란 우리가 일상 생활에서 사용하는 언어인데, 이러한 자연어의 의미를 분석하여 컴퓨터가 처리할 수 있도록 하는 것을 자연어 처리라고 한다.
자연어 처리를 적용할 수 있는 것들에는 [감성분석], [텍스트분류], [내용요약],[챗봇] 등이 있다.
감성분석: 텍스트(자연어)를 분석해서 감성/의견/감정/기분등을 파악하여 다양한 분야에 적용하는 것
텍스트분류:스팸메일 분류처럼 단순 텍스트를 가지고 분류를 하는 것
내용요약 문장에서 중요한 언어들을 뽑아내서 요약하거나 그 단어들을 이용해서 새로운 요약을 만드는 것
챗봇은 사용자와의 말을 분석해서 대화하듯 하는 인공지는 기술
자연어처리는 Preprocessing, Tokenization, Embedding, Modeling 크게 4가지 과정으로 이루어진다.
Preprocessing ->불용어 제거(Stopwords removing), 형태소 분석(Stemming), 표제어 추출(Lemmatization))
Vectorization-> One-hot Encoding, Count vectorization, Tfidf, Padding
Embedding-> Word2vec, Doc2vec, Glove, Fasttext
Modeling-> GRU, LSTM, Attention
우선 Preprocessing은 전처리 과정으로 불용어(문장에서 큰 의미가 없다고 파악되는 언어) 제거, 형태소 분석, 표제어 추출등으로 이루어져있다. 아래는 Preprocessing을 실습해보는 과정이다.
[Preprocessing]
우선 형태소를 분석한다. 형태소를 분석하면 형태소 단위로 의미있는 단어들을 가져올 수 있고 또한 품사별로 언어들을 추출해 낼 수 있다. 형태소 분석기(모듈)에는 여러가지가 있는데 아래에서 살펴보겠다(실습환경은 google colab)이다.
형태소 분석기들을 사용하려면 install을 해야하는데 나머지 분석기들은 그냥 konlpy를 설치하기만 하면된다.
pip install konlpy
위 코드로 install을 하고나면 konlpy안의 분석기들을 사용할 수 있다. 아래 여러가지 종류가 있다.
[Kkma]
from konlpy.tag import Kkma
kkma=Kkma()
sentence="다양한 데이터 분석을 해보자."
print("형태소 단위로 문자 분리")
print(kkma.morphs(sentence))
print("-----------------------")
print("문장에서 명사 추출")
print(kkma.nouns(sentence))
print("-----------------------")
print("품사 태킹(Pos")
print(kkma.pos(sentence))
print("-----------------------")
형태소 단위로 문자 분리
['자연어', '처리', '에', '관하', 'ㄴ', '다양', '하', 'ㄴ', '데이터', '분석', '을', '해보', '자']
-----------------------
문장에서 명사 추출
['자연어', '처리', '다양', '데이터', '분석']
-----------------------
품사 태킹(Pos
[('자연어', 'NNG'), ('처리', 'NNG'), ('에', 'JKM'), ('관하', 'VV'), ('ㄴ', 'ETD'), ('다양', 'NNG'), ('하', 'XSV'), ('ㄴ', 'ETD'), ('데이터', 'NNG'), ('분석', 'NNG'), ('을', 'JKO'), ('해보', 'VV'), ('자', 'ECE')]
[Okt]
from konlpy.tag import Okt
Okt=Okt()
sentence="다양한 데이터 분석을 해보자"
print("형태소 단위로 문자 분리")
print(Okt.morphs(sentence))
print("-----------------------")
print("문장에서 명사 추출")
print(Okt.nouns(sentence))
print("-----------------------")
print("품사 태킹(Pos")
print(Okt.pos(sentence))
print("-----------------------")
형태소 단위로 문자 분리
['자연어', '처리', '에', '관', '한', '다양한', '데이터', '분석', '을', '해보자']
-----------------------
문장에서 명사 추출
['자연어', '처리', '관', '데이터', '분석']
-----------------------
품사 태킹(Pos
[('자연어', 'Noun'), ('처리', 'Noun'), ('에', 'Josa'), ('관', 'Noun'), ('한', 'Josa'), ('다양한', 'Adjective'), ('데이터', 'Noun'), ('분석', 'Noun'), ('을', 'Josa'), ('해보자', 'Verb')]
[Mecab]
마지막으로 Mecab을 사용해 볼건데 Mecab은 원래는 윈도우에서 돌아가지 않아서 따로 설치를 해줘야된다. 나는 goole colab에서 분석을 하고 있어서 비교적 쉬운 방법으로 설치했는데 그냥 자기 윈도우에서 설치하는 분들은 따로 찾아보고 설치해야할 것이다. 나는 아래 블로그분의 글을 참고해서 설치했다.
! git clone https://github.com/SOMJANG/Mecab-ko-for-Google-Colab.git
cd Mecab-ko-for-Google-Colab
!bash install_mecab-ko_on_colab_light_220111.sh
위 코드를 실행해야 mecab 분석기를 사용할 수 있다.(윈도우 & goole colab 환경)
from konlpy.tag import Mecab
mecab = Mecab()
sentence="다양한 데이터 분석을 해보자"
print("형태소 단위로 문자 분리")
print(mecab.morphs(sentence))
print("-----------------------")
print("문장에서 명사 추출")
print(mecab.nouns(sentence))
print("-----------------------")
print("품사 태킹(Pos")
print(mecab.pos(sentence))
print("-----------------------")
형태소 단위로 문자 분리
['다양', '한', '데이터', '분석', '을', '해', '보', '자']
-----------------------
문장에서 명사 추출
['데이터', '분석']
-----------------------
품사 태킹(Pos
[('다양', 'XR'), ('한', 'XSA+ETM'), ('데이터', 'NNG'), ('분석', 'NNG'), ('을', 'JKO'), ('해', 'VV+EC'), ('보', 'VX'), ('자', 'EC')]
-----------------------
위에서 보면 알 수 있듯이 형태소 분석기마다 결과가 다르게 나온다. 분리, 추출, 태깅 결과 모두 다르게 나오는 것을 알 수 있다. 이외에도 여러가지 분석기가 있는데 각각 분석기의 특징을 설명하면,
Mecab:굉장히 속도가 빠르고 좋은 결과를 보여준다
Komoran: 댓글과 같이 정제되지 않은 글에 대해서 먼저 사용해보면 좋다(오탈자 어느정도 처리해줌)
Kkma: 분석시간이 오래걸려서 잘 사용하지 않는다
Okt: 품사태깅결과를 noun,verb 같이 알아보기 쉽게 변환해준다
khaill: 카카오에서 공개한 분석기로 성능이 좋다고 알려져있으며 다양한 실험이 필요하다.
이렇게 전처리에 대해서 간략하게 설명해봤고, 이제 뉴스데이터에 대해서 정리해보겠다.
import nltk
from nltk.corpus import stopwords
nltk.download('stopwords')
우선 위에서 설명 한 방법대로 mecab을 설치해주고, nltk라는 패키지를 설치했는데, 이 모듈은 자연어처리를 위한 다양한 모듈들을 포함한 패키지이다. 우리는 nltk에서 불용어만 사용할 것이다. 우선 stopwords(불용어)를 다운로드해준다.
tokenizer = Mecab()
def text_preprocessing(text,tokenizer):
stop_words = list(stopwords.words('english'))
txt = re.sub('[^a-zA-Z]', ' ', text)
token = tokenizer.morphs(txt)
token = [t for t in token if t not in stop_words]
return token
for i in range(len(fdata['text'])):
tmp=text_preprocessing(fdata['text'][i].lower(),tokenizer)
fdata['text_token'][i]=tmp
for i in range(len(tdata['text'])):
tmp=text_preprocessing(tdata['text'][i].lower(),tokenizer)
tdata['text_token'][i]=tmp
이후 tokenizer을 mecab으로 설정한뒤 전처리 함수를 만들었다.
1. 영어뉴스를 분류할 것이기 때문에 stop_words(불용어)를 영어로 설정해준다. 불용어란, 자주 등장하지만 분석을 하는 것에 있어서는 큰 도움이 되지 않는 단어이다. 위 처럼 패키지에서 불러오지 않고, 불용어를 직접만드는 방법도 있지만 패키지에 다양한 불용어가 있기 때문에 사용하였다.
2. 이후 txt를 영어를 제외하고는 전부 없앤다.
3. 다음으로 tokenizer을 이용해서 전처리를 해준다.
4. 이후 이 함수를 가짜뉴스, 진짜뉴스 데이터의 text(본문)데이터에 적용을 해주고 text_token이라는 컬럼에 넣어준다.
우리 뉴스 분류 시스템은 불용어까지만 제거해줘도 충분한 결과를 얻을 수 있을 것 같아서 여기까지만 전처리를 해줬다.
다음 글에는 벡터화 및 임배딩 과정을 진행하겠다.
아래 부분은 굳이 안읽어도 되지만 프로젝트를 진행하면서 내가 해봤던 과정들이다.
-----------------------------------------------------------------------------------------------------
import re
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
from nltk.stem import PorterStemmer 어간
from nltk.stem import WordNetLemmatizer
nltk.download('tagsets')
nltk.download('averaged_perceptron_tagger')
nltk.download('wordnet')
# 표제어 추출하기(실패작)
porter_stemmer = PorterStemmer() 어간
lemma = WordNetLemmatizer()
for i in range(len(fdata['title'])):
tmp=text_preprocessing(fdata['title'][i].lower(),tokenizer)
# 품사태깅
tmp=pos_tag(tmp)
print(tmp)
tmp2=[]
#pos_tag에는 형용사가 jj로 시작해서 lemmatize하기 위해서 a로 바꿔줌
func_j2a = lambda x : x if x != 'J' else 'a'
for j in tmp:
if(j[1][0] in ['V', 'J', 'N', 'R']):
tmp2.append([j[0],j[1]])
tmp=[lemma.lemmatize(w[0],func_j2a(w[1][0]).lower()) for w in tmp2]
fdata['title_token'][i]=tmp
break
# 표제어 추출하기(성공작)
for i in range(len(fdata['title'])):
tmp=text_preprocessing(fdata['title'][i].lower(),tokenizer)
tmp3=[]
for j in tmp:
tmp2=[]
for k in ['v', 'a', 'n', 'r']:
if(lemma.lemmatize(j,k)):
tmp2.append(lemma.lemmatize(j,k))
break
tmp3.append(tmp2)
fdata['title_token'][i]=tmp3
우선 위 코드는 불용어를 제거한뒤에 표제어까지 추출해내는 코드였다. 불용어 제거 이후 어간으로 분리할지 표제어로 분리할지 고민했었다. 표제어와 어간의 차이점을 보면,
표제어(Lemma)는 한글로는 '기본 사전형 단어라고 말할 수 있다. 예를 들어 was,were등을 be라는 원형으로 나타내는 것이다.
어간추출(stemming) 정해진 규칙만 보고 단어의 어미를 자르는 어림짐작의 작업이다. 예를 들어 복수형 끝에 s가 들어간다는 일반적인규칙으로 단어들에서 마지막 s를 없애버리는? 작업이다. 더 자세한 어간/표제어 설명은 링크를 첨부해두겠다.
위 코드에서 실패작, 성공작이 있는데 그걸 설명해보도록 하겠다.
우선 lemmatize()안에 인자를 단어만 넣으면 그냥 알아서 표제어를 구분해준다.
예를 들어 lemmatize(lives)를 넣으면 life가 출력된다. 그러나 has같은 것을 넣으면 자동으로 구분을 못해 ha같은 이상한 단어가 추출된다. 이를 막기위해 lemmatize안에 단어,품사를 넣어주면 그 품사로 표제어가 출력된다.
여기서 문제가 생겼는데, 우선 나는 표제어를 구분하는 목적은 눈으로 봤을 때는 서로 다른 단어들이지만, 하나의 단어로 일반화시킬 수 있다면 일반화시켜서 문서 내의 단어 수를 줄이는 것이므로, cleaning도 명사, cleaner도 명사지만 이는 모두 clean이 되어야한다.
[원하지않던 방향]
우선 nltk의 pos_tag라는 함수를 통해서 단어의 품사를 추출한뒤 lemmatize(단어, 추출한 품사)로 결과를 출력하는데 이때 dying을 넣으면 dying은 pos_tag에서 형용사로 나오고 lemmatize하면 형용사형태 그대로 dying이 출력된다.
[원하던 방향]
dying이 아니라 원형 형태인 die가 출력되어야 한다고 생각했고 이 때문에 pos_tag 함수를 쓰지 않고, 그냥 lemmatize에 v,a,n,r을 다 넣어보고 그 단어가 존재하는 단어면 그 결과를 출력하고 존재하지 않으면 출력하지 않게 만들었다. 순서는 v동사 형태가 제일 중요하다고 판단해서 반복문을 v로시작하게 만들었다. 예를들면 lemmatize("dying",v)를 실행하고 없으면 lemmatize("dying",a) 없으면 lemmatize("dying",n) 이런식으로 해서 dying을 pos_tag로 한 형용사로 출력하는 것과 다르게dying을 넣었을 떄 die가 나오도록 만들었다.
요약하면, dying(형용사)와 death(명사)와 die(동사) 가 같게 일반화되길 원하면 나처럼 인자를 직접넣어주면 되고 구분하고 싶지않다면 pos_tag를 이용해서 인자에 넣으면 될 것 같다.
'프로젝트 > 가짜 뉴스 분류' 카테고리의 다른 글
[가짜뉴스구별]-Final (0) | 2022.06.28 |
---|---|
[가짜뉴스구별]-Day 3(모델적용) (0) | 2022.05.03 |
[가짜뉴스구별]-Day 2(임베딩구현) (0) | 2022.04.02 |
[가짜뉴스구별]-Day 1(임베딩 설명) (0) | 2022.04.02 |