본문 바로가기
자연어처리(NLP) & CHAT GPT/NLP

[NLP] 워드 임베딩(Word Embedding), RNN - 실습

by 11car28z 2023. 8. 5.

워드 임베딩(Word Embedding)

워드투벡터, 글로브, 패스트텍스트, 엘모 -> 트랜스포머 => GPT/BERT

 

Word2Vec + 영어 데이터

import re
import urllib.request
from lxml import etree #구문 분석기
from nltk.tokenize import word_tokenize, sent_tokenize

 

#url주소주면 데이터를 찾아서 다운로드
urllib.request.urlretrieve("https://raw.githubusercontent.com/ukairia777/tensorflow-nlp-tutorial/main/09.%20Word%20Embedding/dataset/ted_en-20160408.xml", filename="ted_en-20160408.xml")

 

import nltk
nltk.download('punkt')
#punkt 모델을 활용하여 sentence tokenization을 진행하게 된다.
#punkt 또한 문장 구조를 학습한 일종의 모델

html: 텍스트들을 태그로 묶어서 단어 또는 문장에 대한 특징을 표현
웹페이지를 만들때 사용하는 언어, 비구조화 문서라 단어와 문장에 대한 의미를 파악하기 어려움

XML:의미 부여, 검색 할 수 있음. 좀더 지능화된 검색이 가능한 포맷

 

targetXML = open('ted_en-20160408.xml', 'r', encoding='UTF8')
target_text = etree.parse(targetXML)

# xml 파일로부터 <content>와 </content> 사이의 내용만 가져온다.
parse_text = '\n'.join(target_text.xpath('//content/text()'))

# 정규 표현식의 sub 모듈을 통해 content 중간에 등장하는 (Audio), (Laughter) 등의 배경음 부분을 제거.
# 해당 코드는 괄호로 구성된 내용을 제거.
#re.sub(패턴, 대체할 텍스트, 적용할 문장)******
content_text = re.sub(r'\([^)]*\)', '', parse_text)

# 입력 코퍼스에 대해서 NLTK를 이용하여 문장 토큰화를 수행.
sent_text = sent_tokenize(content_text)

# 각 문장에 대해서 구두점을 제거하고, 대문자를 소문자로 변환.
normalized_text = []
for string in sent_text:
     tokens = re.sub(r"[^a-z0-9]+", " ", string.lower())
     normalized_text.append(tokens)

# 각 문장에 대해서 NLTK를 이용하여 단어 토큰화를 수행.
result = [word_tokenize(sentence) for sentence in normalized_text]

 

import numpy as np

np.shape(result)
result[270000]#문장의 개수 27만개이상

from gensim.models import Word2Vec
from gensim.models import KeyedVectors
model = Word2Vec(sentences=result, vector_size=100, window=5, min_count=5, workers=4, sg=0)

gensim에 있는 Word2Vec 사용
vector_size=100     벡터 크기 100차원 -> 각단어가 100차원에 임베딩된다
min_count=5           5번이상 언급된것만 임베딩
workers=4               작업에 사용된 시피유
sg=0                        스킵그램이 아니다, c-bow 사용 -> 중심단어로 주변단어 예측하기

result에 있는 문장이 단어별로 쪼개지고 윈도우로 데이터 셋 만들어지고, 레이블링, 신경망으로 학습

 

model.wv.most_similar('man') #xml 안에있는 데이터로 학습해서 이런 결과 나왔음. 문장이 어떻게 구성되었는지 에 따라 다름


Word2Vec + 한글 데이터

1.데이터 가져오기

urllib.request.urlretrieve("https://raw.githubusercontent.com/e9t/nsmc/master/ratings.txt", filename="ratings.txt")

 

import pandas as pd

train_data = pd.read_table('ratings.txt')

train_data

2. 결측치 처리

train_data.info() #결측값이 여러개있음

 

train_data[train_data['document'].isnull()]

train_data = train_data.dropna()

 

train_data.info()

#열단위로 문자열 처리시 한열만 뽑아오면 시리즈로 인식해준다.
#시리즈에서는 문자열 함수를 직접사용할 수 없어서 str과 함께 적용하기
train_data['document'].str.replace("포켓","포겟")

#한글이 아닌 것을 모두 제거하기
train_data['document'] = train_data['document'].str.replace("[^ㄱ-하-ㅣ가-힣 ]","") #[^지정한 문자]: 지정한 문자 제외하고

 

train_data['document'].isnull().sum()

 

3. 전처리 작업(형태소, 불용어 제거)

pip install konlpy

#불용어 처리
stopwords = ['의','가','이','은','들','는','좀','잘','걍','과','도','를','으로','자','에','와','한','하다']

 

from konlpy.tag import Okt

okt=Okt()

tok_data=[]
for sent in train_data['document']:
  tok_sent = okt.morphs(sent) #토큰화: sent에 저장된 문장이 형태소 단위로 나뉘어 저장
  sw_rem_sent = [w for w in tok_sent if not w in stopwords]#불용어 처리
  tok_data.append(sw_rem_sent)

 

from matplotlib import pyplot as plt

#토큰화된 데이터 분포 찍어보기
print(max(len(r) for r in tok_data))# 리뷰최대길이
plt.hist([len(r) for r in tok_data], bins=50)

 

4. 워드 임베딩

#단어 사전에 없는 것은 잘 대처를 하지 못한다.
model = Word2Vec(sentences=tok_data, vector_size=100, window=5, min_count=5, workers=4, sg=0)

 

model.wv.vectors.shape #(26194, 100)

 

model.wv.most_similar("책상")#가장 유사한 벡터를 찾는 함수


FastText

from gensim.models import FastText

#FastText: 단어 사전에 없는 것도 잘 대처를 한다.
model = FastText(result, vector_size=10, window=5, min_count=5,workers=4, sg=1)

model.wv.most_similar('man')


LSTM기반 분류기 만들기

NLP 과정

1.전처리 하기 : 다의어 처리, 동음이의어 처리, 불용어 제거, 공백 제거, 특수문자 처리, 문장 구성 단어 개수기준 제거
2. 토큰화 : 하나의 리스트 안에 전처리된 단어들이 들어가 있음.
3. 인코딩 : 각각의 단어가 리스트 안에 있고 그것이 수치로 변환해야함.
4. 모델 생성
5. 모델 학습
6. 테스트

 

분류 모델(메일 제목이 스팸인가 햄인가)
머신러닝 분류 모델: 의사결정트리, 랜덤포레스트, SVM


자연어 처리에는 의사결정트리, 랜덤포레스트 사용X, 성능이 안좋음.


자연어처리는 베이즈 이론 기반의 나이브 베이즈 알고리즘사용 -> 자연어처리 신경망 기반으로 접근하기

 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import urllib.request #웹에서 데이터 긁어오기
from sklearn.model_selection import train_test_split
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences

1. 데이터 가져오기

#웹에있는 csv 파일 다운 받기
#urlretrieve("경로")
urllib.request.urlretrieve("https://raw.githubusercontent.com/ukairia777/tensorflow-nlp-tutorial/main/10.%20RNN%20Text%20Classification/dataset/spam.csv", filename="spam.csv")
data = pd.read_csv('spam.csv', encoding='latin1')
print('총 샘플의 수 :',len(data))

 

data

2. 데이터 전처리

del data['Unnamed: 2'] #열 삭제하기
del data['Unnamed: 3']
del data['Unnamed: 4']

 

data

#ham 0 , spam 1로 변경해주기
data['v1'] = data['v1'].replace(['ham','spam'],[0,1])

 

data[:5]

data.columns = ['label', 'title']

 

data

data.describe() #label 열에 대해 기술 통계
data.label.value_counts()# describe보다 value_counts 하는 것이 더 적합하다.

data['title'].nunique() #title열에서 중복을 제거한 샘플의 개수

 

data.drop_duplicates(subset=['title'], inplace=True)

 

data.drop_duplicates(subset=['title'], inplace=True)

 

len(data['title'])

 

xdata= data['title']
ydata=data['label']

 

#데이터 분리하기
#층화 추출 기법: 종류에 따라 균등하게 분리하여 추출하는 방법
xtrain, xtest, ytrain, ytest = train_test_split(xdata, ydata, test_size=0.2, random_state=20230728,
                                                stratify = ydata)
# x: 입력, y: 레이블
# random_state: 실행할때마다 다른 값으로 변경되기때문에 추출되는 데이터의 번호가 달라 모델이 좋아지는지 객관적으로 확인 불가능

 

len(xtrain)
xtrain.iloc[0]

 

xtrain

ytrain.value_counts()

3. 토큰화

tok = Tokenizer()
tok.fit_on_texts(xtrain)#xtrain을 코퍼스로하여 fitting(단어별로 인덱스 부여)
xtrain_enc = tok.texts_to_sequences(xtrain)#숫자 변환 작

 

xtrain_enc

 

tok.index_word

 

w2i=tok.word_index #빈도수가 가장 높은 단어 먼저 출력

 

vocab_size = len(w2i)+1
#단어 번호인 인덱스가 1부터 시작, pad_sequences한 것은 0번째 부터 시작해 1을 더해 단어 사전 크기 설정

 

xtrain.shape#(4135,)
xtest.shape#(1034,)

4. 패딩

#패딩하기 위해 최대 길이 찾기
#xtrain_enc가 하나씩 읽어지면서 len수행
sum(map(len, xtrain_enc))/len(xtrain_enc)# 메일의 평균 단어 개수

 

maxLen = max(map(len, xtrain_enc))# 메일의 최대 단어 개수 #map 사용시 for문 필요없음.

 

xtrain_padded = pad_sequences(xtrain_enc, maxlen=maxLen) #길이 121에 맞춰주기

 

xtrain_padded.shape

 

5. RNN

from tensorflow.keras.layers import SimpleRNN, Embedding, Dense, LSTM
from tensorflow.keras.models import Sequential

model=Sequential()
model.add(Embedding(vocab_size, 32))
model.add(SimpleRNN(100))
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
#분류에서는 accuracy, 회귀에서는 mse, rmse, r2, mae, mspe, mape, msle 등

history=model.fit(xtrain_padded, ytrain, epochs=5, batch_size=32, validation_split=0.2)
#x : 입력 데이터,
#y : 라벨값,
#batch_size = 몇 개의 샘플로 가중치를 갱신 할 것인지 지정,
#epochs : 학습 반복 횟수 를 의미한다.
#batch_size : 몇 개의 샘플로 가중치를 갱신할 것인지 설정, 배치 사이즈가 작을 수록 가중치 갱신이 자주 일어난다.

 

6. Test 데이터 셋 차원 똑같이 만들어서 테스트 해보기

xtest_enc = tok.texts_to_sequences(xtest)

xtest_padded=pad_sequences(xtest_enc, maxlen=maxLen)

#model.predict(xtest_padded)
model.evaluate(xtest_padded,ytest)

#model.evaluate : 학습에서 얻은 모델을 test데이터로 평가함.
#테스트 파일로 돌려서 얻은 손실값과, compile에서 요청한 'metrics' 을 반환함

#model.predict- 테스트 데이터에 대한 최종 예측을 함

#predict()는 테스트의 분류 결과를 예측합니다. 반환값이 예측 확률입니다. targetX
#evaluate()는 테스트 데이터 세트를 입력해서 성능 평가를 합니다. targetO

model.evaluate(xtest_padded,ytest)[1]

'자연어처리(NLP) & CHAT GPT > NLP' 카테고리의 다른 글

[NLP] Seq2Seq - 실습  (0) 2023.08.08
[NLP] Seq2eq에서 BERT까지  (0) 2023.08.07
[NLP] 워드 임베딩(Word Embedding) - 개념  (0) 2023.08.04
[NLP] LSTM  (0) 2023.08.03
[NLP] 신경망기반 텍스트 분류 - 실습  (0) 2023.08.02