워드 임베딩(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 |