|
1 |
| -import os |
2 |
| -import re |
| 1 | +# 1. preprocess.py :데이터불러오고가공 |
| 2 | +# 2. Preprocess.ipynb :사전구성과 학습에사용될데이터로 구성 |
| 3 | +# 3. seq2seq.ipynb :모델구성과 학습,평가,실행 할수있는파일 |
| 4 | + |
| 5 | + |
| 6 | +import os # 운영체제기능사용 |
| 7 | +import re # 정규표현식사용 |
3 | 8 | import json
|
4 | 9 |
|
5 | 10 | import numpy as np
|
6 | 11 | import pandas as pd
|
7 | 12 | from tqdm import tqdm
|
8 | 13 |
|
9 |
| -from konlpy.tag import Okt |
| 14 | +from konlpy.tag import Okt # 한글형태소활용 |
10 | 15 |
|
11 | 16 |
|
12 | 17 | FILTERS = "([~.,!?\"':;)(])"
|
13 |
| -PAD = "<PAD>" |
14 |
| -STD = "<SOS>" |
15 |
| -END = "<END>" |
16 |
| -UNK = "<UNK>" |
| 18 | +PAD = "<PAD>" # 아무의미없는 패딩토큰 |
| 19 | +STD = "<SOS>" # 시작토큰의미 |
| 20 | +END = "<END>" # 종료토큰의미 |
| 21 | +UNK = "<UNK>" # 사전에없는단어를의미 |
17 | 22 |
|
18 | 23 | PAD_INDEX = 0
|
19 | 24 | STD_INDEX = 1
|
|
25 | 30 |
|
26 | 31 | MAX_SEQUENCE = 25
|
27 | 32 |
|
28 |
| - |
29 |
| -def load_data(path): |
30 |
| - # 판다스를 통해서 데이터를 불러온다. |
31 |
| - data_df = pd.read_csv(path, header=0) |
32 |
| - # 질문과 답변 열을 가져와 question과 answer에 넣는다. |
33 |
| - question, answer = list(data_df['Q']), list(data_df['A']) |
34 |
| - |
| 33 | + # 1데이터를 판다스를통해 불러와서 데이터프레임형태로만듬 /question,answer반환 |
| 34 | +def load_data(path): |
| 35 | + data_df = pd.read_csv(path, header=0) |
| 36 | + question, answer = list(data_df['Q']), list(data_df['A']) |
35 | 37 | return question, answer
|
36 | 38 |
|
37 |
| - |
| 39 | + # 2데이터를 단어리스트로만듬 |
38 | 40 | def data_tokenizer(data):
|
39 | 41 | # 토크나이징 해서 담을 배열 생성
|
40 | 42 | words = []
|
41 | 43 | for sentence in data:
|
42 | 44 | # FILTERS = "([~.,!?\"':;)(])"
|
43 |
| - # 위 필터와 같은 값들을 정규화 표현식을 |
44 |
| - # 통해서 모두 "" 으로 변환 해주는 부분이다. |
45 |
| - sentence = re.sub(CHANGE_FILTER, "", sentence) |
| 45 | + # 위 필터와 같은 값들을 정규화 표현식을 통해서 모두 "" 으로 변환 해주는 부분이다. |
| 46 | + sentence = re.sub(CHANGE_FILTER, "", sentence) # 정규표현식을사용해 특수기호제거, 공백문자기준으로 단어를나눠 전체데이터의 모든단어를 포함하는 단어리스트로 만듬 |
46 | 47 | for word in sentence.split():
|
47 | 48 | words.append(word)
|
48 |
| - # 토그나이징과 정규표현식을 통해 만들어진 |
49 |
| - # 값들을 넘겨 준다. |
| 49 | + # 토그나이징과 정규표현식을 통해 만들어진값들을 넘겨 준다. |
50 | 50 | return [word for word in words if word]
|
51 | 51 |
|
52 |
| - |
| 52 | + # 3텍스트를 형태소로 분리 |
53 | 53 | def prepro_like_morphlized(data):
|
54 | 54 | morph_analyzer = Okt()
|
55 | 55 | result_data = list()
|
56 | 56 | for seq in tqdm(data):
|
57 | 57 | morphlized_seq = " ".join(morph_analyzer.morphs(seq.replace(' ', '')))
|
58 | 58 | result_data.append(morphlized_seq)
|
59 |
| - |
60 | 59 | return result_data
|
61 | 60 |
|
62 |
| - |
63 |
| -def load_vocabulary(path, vocab_path, tokenize_as_morph=False): |
64 |
| - # 사전을 담을 배열 준비한다. |
65 |
| - vocabulary_list = [] |
66 |
| - # 사전을 구성한 후 파일로 저장 진행한다. |
67 |
| - # 그 파일의 존재 유무를 확인한다. |
68 |
| - if not os.path.exists(vocab_path): |
69 |
| - # 이미 생성된 사전 파일이 존재하지 않으므로 |
70 |
| - # 데이터를 가지고 만들어야 한다. |
71 |
| - # 그래서 데이터가 존재 하면 사전을 만들기 위해서 |
72 |
| - # 데이터 파일의 존재 유무를 확인한다. |
73 |
| - if (os.path.exists(path)): |
74 |
| - # 데이터가 존재하니 판단스를 통해서 |
75 |
| - # 데이터를 불러오자 |
| 61 | + # 4단어사전을 만드는함수 |
| 62 | +def load_vocabulary(path, vocab_path, tokenize_as_morph=False): |
| 63 | + vocabulary_list = [] # 사전을담을배열 |
| 64 | + |
| 65 | + # 사전을 구성한 후 파일로 저장 진행한다. |
| 66 | + if not os.path.exists(vocab_path): # 이미생성된 사전파일이 존재하지않음. 데이터를가지고 만든다. 데이터존재시 사전만듬 |
| 67 | + if (os.path.exists(path)): # 데이터존재함. 판다스로 데이터불러옴 |
76 | 68 | data_df = pd.read_csv(path, encoding='utf-8')
|
77 |
| - # 판다스의 데이터 프레임을 통해서 |
78 |
| - # 질문과 답에 대한 열을 가져 온다. |
| 69 | + |
| 70 | + # 판다스의 데이터 프레임을통해서 질문과 답에 대한 열을 가져 온다. |
79 | 71 | question, answer = list(data_df['Q']), list(data_df['A'])
|
80 |
| - if tokenize_as_morph: # 형태소에 따른 토크나이져 처리 |
81 |
| - question = prepro_like_morphlized(question) |
82 |
| - answer = prepro_like_morphlized(answer) |
| 72 | + if tokenize_as_morph: # 형태소에따른 토크나이져 처리 |
| 73 | + question = prepro_like_morphlized(question) # 텍스트를형태소로분리(앞의함수) |
| 74 | + answer = prepro_like_morphlized(answer) # 텍스트를형태소로분리(앞의함수) |
| 75 | + |
83 | 76 | data = []
|
84 |
| - # 질문과 답변을 extend을 |
85 |
| - # 통해서 구조가 없는 배열로 만든다. |
86 |
| - data.extend(question) |
87 |
| - data.extend(answer) |
88 |
| - # 토큰나이져 처리 하는 부분이다. |
89 |
| - words = data_tokenizer(data) |
90 |
| - # 공통적인 단어에 대해서는 모두 |
91 |
| - # 필요 없으므로 한개로 만들어 주기 위해서 |
92 |
| - # set해주고 이것들을 리스트로 만들어 준다. |
93 |
| - words = list(set(words)) |
94 |
| - # 데이터 없는 내용중에 MARKER를 사전에 |
95 |
| - # 추가 하기 위해서 아래와 같이 처리 한다. |
96 |
| - # 아래는 MARKER 값이며 리스트의 첫번째 부터 |
97 |
| - # 순서대로 넣기 위해서 인덱스 0에 추가한다. |
98 |
| - # PAD = "<PADDING>" |
| 77 | + # 질문과 답변을 extend을 통해서 구조가 없는 배열로 만든다. |
| 78 | + data.extend(question) |
| 79 | + data.extend(answer) |
| 80 | + words = data_tokenizer(data) # 데이터를단어리스트로만듬(앞의함수) |
| 81 | + words = list(set(words)) # 공통적인 단어에 대해서 한개로 만들어 주기 위해서 set해주고 이것들을 리스트로 만들어 준다. |
| 82 | + # PAD = "<PADDING>" # 데이터 없는 내용중에 MARKER를 사전에 추가 하기 위해서 아래와 같이 처리 한다. |
99 | 83 | # STD = "<START>"
|
100 | 84 | # END = "<END>"
|
101 | 85 | # UNK = "<UNKNWON>"
|
102 |
| - words[:0] = MARKER |
103 |
| - # 사전을 리스트로 만들었으니 이 내용을 |
104 |
| - # 사전 파일을 만들어 넣는다. |
| 86 | + words[:0] = MARKER # 아래는 MARKER 값이며 리스트의 첫번째부터 순서대로 넣기 위해서 인덱스 0에 추가한다. |
| 87 | + |
| 88 | + # 사전을 리스트로 만들었으니 이 내용을 사전 파일을 만들어 넣는다. |
105 | 89 | with open(vocab_path, 'w', encoding='utf-8') as vocabulary_file:
|
106 | 90 | for word in words:
|
107 | 91 | vocabulary_file.write(word + '\n')
|
108 | 92 |
|
109 |
| - # 사전 파일이 존재하면 여기에서 |
110 |
| - # 그 파일을 불러서 배열에 넣어 준다. |
| 93 | + # 사전 파일이 존재하면 여기에서 그 파일을 불러서 배열에 넣어 준다. |
111 | 94 | with open(vocab_path, 'r', encoding='utf-8') as vocabulary_file:
|
112 | 95 | for line in vocabulary_file:
|
113 | 96 | vocabulary_list.append(line.strip())
|
114 | 97 |
|
115 |
| - # 배열에 내용을 키와 값이 있는 |
116 |
| - # 딕셔너리 구조로 만든다. |
| 98 | + # 배열에 내용을 키와 값이 있는 딕셔너리 구조로 만든다. |
117 | 99 | char2idx, idx2char = make_vocabulary(vocabulary_list)
|
118 |
| - # 두가지 형태의 키와 값이 있는 형태를 리턴한다. |
119 |
| - # (예) 단어: 인덱스 , 인덱스: 단어) |
| 100 | + # 두가지 형태의 키와 값이 있는 형태를 리턴한다. (예) 단어: 인덱스 , 인덱스: 단어) |
120 | 101 | return char2idx, idx2char, len(char2idx)
|
121 | 102 |
|
122 | 103 |
|
123 |
| -def make_vocabulary(vocabulary_list): |
124 |
| - # 리스트를 키가 단어이고 값이 인덱스인 |
125 |
| - # 딕셔너리를 만든다. |
| 104 | +# 5단어리스트를 인자로 두개의 딕셔너리를만듬 |
| 105 | +def make_vocabulary(vocabulary_list): |
| 106 | + # vocabulary_list에 [안녕,너는,누구야] 들어있다면 word2idx에는 key가 안녕,너는,누구야/value는 0,1,2 이고, idx2word는 key,value가반대이다. |
| 107 | + # 리스트를 키가 단어이고 값이 인덱스인 딕셔너리를 만든다. |
126 | 108 | char2idx = {char: idx for idx, char in enumerate(vocabulary_list)}
|
127 |
| - # 리스트를 키가 인덱스이고 값이 단어인 |
128 |
| - # 딕셔너리를 만든다. |
| 109 | + # 리스트를 키가 인덱스이고 값이 단어인 딕셔너리를 만든다. |
129 | 110 | idx2char = {idx: char for idx, char in enumerate(vocabulary_list)}
|
130 | 111 | # 두개의 딕셔너리를 넘겨 준다.
|
131 | 112 | return char2idx, idx2char
|
132 | 113 |
|
133 |
| - |
| 114 | + # 6인코더적용 입력값 만듬 |
134 | 115 | def enc_processing(value, dictionary, tokenize_as_morph=False):
|
135 | 116 | # 인덱스 값들을 가지고 있는
|
136 | 117 | # 배열이다.(누적된다.)
|
@@ -180,7 +161,7 @@ def enc_processing(value, dictionary, tokenize_as_morph=False):
|
180 | 161 | # 그 길이를 넘겨준다.
|
181 | 162 | return np.asarray(sequences_input_index), sequences_length
|
182 | 163 |
|
183 |
| - |
| 164 | +# 7디코더의 입력값을 만드는함수 |
184 | 165 | def dec_output_processing(value, dictionary, tokenize_as_morph=False):
|
185 | 166 | # 인덱스 값들을 가지고 있는
|
186 | 167 | # 배열이다.(누적된다)
|
@@ -222,22 +203,19 @@ def dec_output_processing(value, dictionary, tokenize_as_morph=False):
|
222 | 203 | # 넘파이 배열에 인덱스화된 배열과 그 길이를 넘겨준다.
|
223 | 204 | return np.asarray(sequences_output_index), sequences_length
|
224 | 205 |
|
225 |
| - |
| 206 | +# 8디코더의 타깃값을 만드는 전처리함수 |
226 | 207 | def dec_target_processing(value, dictionary, tokenize_as_morph=False):
|
227 |
| - # 인덱스 값들을 가지고 있는 |
228 |
| - # 배열이다.(누적된다) |
| 208 | + # 인덱스 값들을 가지고 있는 배열이다.(누적된다) |
229 | 209 | sequences_target_index = []
|
230 | 210 | # 형태소 토크나이징 사용 유무
|
231 | 211 | if tokenize_as_morph:
|
232 | 212 | value = prepro_like_morphlized(value)
|
233 | 213 | # 한줄씩 불어온다.
|
234 | 214 | for sequence in value:
|
235 | 215 | # FILTERS = "([~.,!?\"':;)(])"
|
236 |
| - # 정규화를 사용하여 필터에 들어 있는 |
237 |
| - # 값들을 "" 으로 치환 한다. |
| 216 | + # 정규화를 사용하여 필터에 들어 있는값들을 "" 으로 치환 한다. |
238 | 217 | sequence = re.sub(CHANGE_FILTER, "", sequence)
|
239 |
| - # 문장에서 스페이스 단위별로 단어를 가져와서 |
240 |
| - # 딕셔너리의 값인 인덱스를 넣어 준다. |
| 218 | + # 문장에서 스페이스 단위별로 단어를 가져와서 딕셔너리의 값인 인덱스를 넣어 준다. |
241 | 219 | # 디코딩 출력의 마지막에 END를 넣어 준다.
|
242 | 220 | sequence_index = [dictionary[word] if word in dictionary else dictionary[UNK] for word in sequence.split()]
|
243 | 221 | # 문장 제한 길이보다 길어질 경우 뒤에 토큰을 자르고 있다.
|
|
0 commit comments