챗봇구축(AI학습 55)

이유진·2024년 7월 8일

--36.전처리&사전구축.ipynb--

챗봇엔진의 전처리

  • 토크나이징 (형태소 분석기 사용)
  • 불용어 제거

!pip install konlpy

base_path = r'/content/drive/MyDrive/dataset/chatbot'

전처리 모듈

  • ./utils/Preprocess.py

전처리 모듈은 챗봇 엔진 내에서 '자주' 사용하기 때문에 클래스로 설계해 둘겁니다.

from konlpy.tag import Komoran

class Preprocess:
def init(self, userdic=None): # 생성자 (userdic=사용자 사전)

# ① 형태소 분석기 초기화
self.komoran = Komoran(userdic=userdic)   # 사용자 정의 사전 파일의 경로 입력

# ② 제외할 품사 (불용어 제거)
# 참조 : https://docs.komoran.kr/firststep/postypes.html
# 관계언 제거, 기호 제거
# 어미 제거
# 접미사 제거
self.exclusion_tags = [
        'JKS', 'JKC', 'JKG', 'JKO', 'JKB', 'JKV', 'JKQ',
        'JX', 'JC',
        'SF', 'SP', 'SS', 'SE', 'SO',
        'EP', 'EF', 'EC', 'ETN', 'ETM',
        'XSN', 'XSV', 'XSA'
]

형태소 분석기 POS 태거

def pos(self, sentence):
return self.komoran.pos(sentence)

불용어 제거후 , 필요한 품사 정보만 가져오기

def get_keywords(self, pos, without_tag=False):
f = lambda x : x in self.exclusion_tags
word_list = []
for p in pos:
if f(p[1]) is False:
word_list.append(p if without_tag is False else p[0])
return word_list

전처리 모듈 테스트

import os

sent = "내일 오전 10시에 탕수육 주문하고 싶어"

전처리 객체 생성

p = Preprocess(userdic = os.path.join(base_path, 'user_dic.tsv'))

형태소 분석기 실행 (품사 태깅)

pos = p.pos(sent)

pos

불용어 제거후 품사 태그과 같이 단어(키워드) 출력

ret = p.get_keywords(pos, without_tag=False)

print(ret)

불용어 제거후 품사 태그 없이 단어(키워드) 출력

ret = p.get_keywords(pos, without_tag=True)

print(ret)

단어사전 구축 및 시퀀스 생성

챗봇엔진에서 '의도분류' 및 '개체명 인식모델' 의 학습을 하려면 단어사전을 구축해야 한다

말뭉치(데이터) 데이터 : corpus.txt

출처) 네이버 영화 리뷰 말뭉치 데이터

(기본적으로 \t 으로 id, comment, label 컬럼으로 구분되어 있다)

from tensorflow.keras import preprocessing
import pickle

말뭉치 데이터 읽어오기

말뭉치 데이터 읽어오기

def read_corpus_data(filename):
with open(filename, 'r', encoding='utf-8') as f:
data = [line.split('\t') for line in f.read().splitlines()]
return data

corpus_data = read_corpus_data(os.path.join(base_path, 'corpus.txt'))

len(corpus_data)

corpus_data[:10]

POS 태깅하기

위에서 불러온 말뭉치 데이터 리스트에서 문장을 하나씩 불러와 POS 태깅

p = Preprocess()
dic = []

for c in corpus_data:
pos = p.pos(c[1])
for k in pos:
dic.append(k[0])

len(dic)

dic[:20]

단어 인덱스(사전) 생성. OOV

Tokenizer 를 이용해서 위에서 만든 dict 를 단어 인덱스 딕셔너리(word_index) 데이터로 만든다

사전의 첫번째 인덱스는 OOV

tokenizer = preprocessing.text.Tokenizer(oov_token='OOV') # 어휘에 없으면 'OOV'로 Token 대체
tokenizer.fit_on_texts(dic)
word_index = tokenizer.word_index # 여기서 인덱스가 만들어진다.

print(word_index)

사전을 파일로 저장

f = open(os.path.join(base_path, 'out', 'chatbot_dict.bin'), 'wb')
try :
pickle.dump(word_index, f)
except Exception as e :
print(e)
finally :
f.close()

단어 사전 테스트

단어사전 불러오기

word_index = None
f = open(os.path.join(base_path, 'out', 'chatbot_dict.bin'), 'rb')
word_index = pickle.load(f)
f.close()

전처리 객체 생성

p = Preprocess(userdic = os.path.join(base_path, 'user_dict.tsv'))

sent = '내일 오전 10시에 탕수육 주문하고 싶어 ㅋㅋ'

pos = p.pos(sent)

for word in p.get_keywords(pos, without_tag=True) :
try :
print(word, word_index[word])
except KeyError :

# 해당 단어가 사전에 없는경우 OOV 처리
print(word, word_index['OOV'])

단어인덱스 시퀀스 변환 메소드 추가

Preprocess.py

전처리 모듈은 챗봇 엔진 내에서 '자주' 사용하기 때문에 클래스로 설계해 둘겁니다.

from konlpy.tag import Komoran
import pickle
import jpype # 자바와 파이썬 간의 데이터 통신을 위한 모듈

class Preprocess:
def init(self, word2index_dic = '', userdic=None): # 생성자 (word2index_dic=단어사전, userdic=사용자 사전)

# 단어인덱스 사전 불러오기
if(word2index_dic != '') :
  f = open(word2index_dic, 'rb')
  self.word_index = pickle.load(f)
  f.close()
else :
  self.word_index = None

# ① 형태소 분석기 초기화
self.komoran = Komoran(userdic=userdic)   # 사용자 정의 사전 파일의 경로 입력

# ② 제외할 품사 (불용어 제거)
# 참조 : https://docs.komoran.kr/firststep/postypes.html
# 관계언 제거, 기호 제거
# 어미 제거
# 접미사 제거
self.exclusion_tags = [
        'JKS', 'JKC', 'JKG', 'JKO', 'JKB', 'JKV', 'JKQ',
        'JX', 'JC',
        'SF', 'SP', 'SS', 'SE', 'SO',
        'EP', 'EF', 'EC', 'ETN', 'ETM',
        'XSN', 'XSV', 'XSA'
]

형태소 분석기 POS 태거

def pos(self, sentence):
jpype.attachThreadToJVM()
return self.komoran.pos(sentence)

불용어 제거후 , 필요한 품사 정보만 가져오기

def get_keywords(self, pos, without_tag=False):
f = lambda x : x in self.exclusion_tags
word_list = []
for p in pos:
if f(p[1]) is False:
word_list.append(p if without_tag is False else p[0])
return word_list

키워드를 단어 인덱스 시퀀스로 변환

def get_wordidx_sequence(self, keywords) :
if self.word_index is None :
return []

w2i = []
for word in keywords :
  try :
    w2i.append(self.word_index[word])
  except KeyError :
    w2i.append(self.word_index['OOV'])
return w2i
profile
독해지자

0개의 댓글