質問編集履歴
2
インデントの修正
test
CHANGED
File without changes
|
test
CHANGED
@@ -86,37 +86,39 @@
|
|
86
86
|
|
87
87
|
|
88
88
|
|
89
|
+
#不要な部分の削除
|
90
|
+
|
89
91
|
def trim_doc(doc):
|
90
92
|
|
91
|
-
lines = doc.splitlines()
|
93
|
+
lines = doc.splitlines()
|
92
|
-
|
94
|
+
|
93
|
-
valid_lines = []
|
95
|
+
valid_lines = []
|
94
|
-
|
96
|
+
|
95
|
-
is_valid = False
|
97
|
+
is_valid = False
|
96
|
-
|
98
|
+
|
97
|
-
horizontal_rule_cnt = 0
|
99
|
+
horizontal_rule_cnt = 0
|
98
|
-
|
100
|
+
|
99
|
-
break_cnt = 0
|
101
|
+
break_cnt = 0
|
100
|
-
|
102
|
+
|
101
|
-
for line in lines:
|
103
|
+
for line in lines:
|
102
|
-
|
104
|
+
|
103
|
-
if horizontal_rule_cnt < 2 and 'Reply-to:' in line:
|
105
|
+
if horizontal_rule_cnt < 2 and 'Reply-to:' in line:
|
104
|
-
|
106
|
+
|
105
|
-
horizontal_rule_cnt += 1
|
107
|
+
horizontal_rule_cnt += 1
|
106
|
-
|
108
|
+
|
107
|
-
is_valid = horizontal_rule_cnt == 2
|
109
|
+
is_valid = horizontal_rule_cnt == 2
|
108
|
-
|
110
|
+
|
109
|
-
continue
|
111
|
+
continue
|
110
|
-
|
112
|
+
|
111
|
-
if not(is_valid):
|
113
|
+
if not(is_valid):
|
112
|
-
|
114
|
+
|
113
|
-
continue
|
115
|
+
continue
|
114
|
-
|
116
|
+
|
115
|
-
break_cnt = 0
|
117
|
+
break_cnt = 0
|
116
|
-
|
118
|
+
|
117
|
-
valid_lines.append(line)
|
119
|
+
valid_lines.append(line)
|
118
|
-
|
120
|
+
|
119
|
-
return ''.join(valid_lines)
|
121
|
+
return ''.join(valid_lines)
|
120
122
|
|
121
123
|
|
122
124
|
|
@@ -140,7 +142,7 @@
|
|
140
142
|
|
141
143
|
words.append(chunks[0])
|
142
144
|
|
143
|
-
return LabeledSentence(words=words, tags=[name])
|
145
|
+
return LabeledSentence(words=words, tags=[name])
|
144
146
|
|
145
147
|
|
146
148
|
|
1
書式の改善
test
CHANGED
File without changes
|
test
CHANGED
@@ -1,27 +1,255 @@
|
|
1
|
+
###前提・実現したいこと
|
2
|
+
|
1
|
-
doc2vecを
|
3
|
+
doc2vecを用いて
|
2
4
|
|
3
5
|
VirtualBoxのcentOS上で、python3.6を使ってdoc2vecを動かしています。
|
4
6
|
|
5
7
|
|
6
8
|
|
9
|
+
実現したいプログラムは
|
10
|
+
|
11
|
+
・類似する単語の検索機能
|
12
|
+
|
13
|
+
です。
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
参考にしたプログラムはこちらのサイトにあったものです。
|
18
|
+
|
7
19
|
https://qiita.com/akira_/items/f9bb46cad6834da32367
|
8
20
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
21
|
+
文書を学習するプログラムと検索するプログラムは分かれていて、
|
22
|
+
|
23
|
+
学習するプログラムに問題が発生しました。
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
与えたプログラムは電子メールをプレーンテキストにしたもので、
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
```
|
32
|
+
|
33
|
+
def trim_doc(doc):
|
34
|
+
|
35
|
+
```
|
36
|
+
|
37
|
+
で不要な部分を削除してから与えました。
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
実際に書いたコードがこちらです。
|
42
|
+
|
43
|
+
```
|
44
|
+
|
45
|
+
import os
|
46
|
+
|
47
|
+
import sys
|
48
|
+
|
49
|
+
import MeCab
|
50
|
+
|
51
|
+
import collections
|
52
|
+
|
53
|
+
from gensim import models
|
54
|
+
|
55
|
+
from gensim.models.doc2vec import LabeledSentence
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
INPUT_DOC_DIR = './mail'
|
60
|
+
|
61
|
+
OUTPUT_MODEL = 'doc2vec.model'
|
62
|
+
|
63
|
+
PASSING_PRECISION = 93
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
#すべてのファイルのリストを取得
|
68
|
+
|
69
|
+
def get_all_files(directory):
|
70
|
+
|
71
|
+
for root, dirs, files in os.walk(directory):
|
72
|
+
|
73
|
+
for file in files:
|
74
|
+
|
75
|
+
yield os.path.join(root, file)
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
#ファイルから文章を返す
|
80
|
+
|
81
|
+
def read_document(path):
|
82
|
+
|
83
|
+
with open(path, 'r', errors='ignore') as f:
|
84
|
+
|
85
|
+
return f.read()
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
def trim_doc(doc):
|
90
|
+
|
91
|
+
lines = doc.splitlines()
|
92
|
+
|
93
|
+
valid_lines = []
|
94
|
+
|
95
|
+
is_valid = Falseadsf
|
96
|
+
|
97
|
+
horizontal_rule_cnt = 0
|
98
|
+
|
99
|
+
break_cnt = 0
|
100
|
+
|
101
|
+
for line in lines:
|
102
|
+
|
103
|
+
if horizontal_rule_cnt < 2 and 'Reply-to:' in line:
|
104
|
+
|
105
|
+
horizontal_rule_cnt += 1
|
106
|
+
|
107
|
+
is_valid = horizontal_rule_cnt == 2
|
108
|
+
|
109
|
+
continue
|
110
|
+
|
111
|
+
if not(is_valid):
|
112
|
+
|
113
|
+
continue
|
114
|
+
|
115
|
+
break_cnt = 0asfd
|
116
|
+
|
117
|
+
valid_lines.append(line)
|
118
|
+
|
119
|
+
return ''.join(valid_lines)
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
#文章から単語に分割して返す
|
124
|
+
|
125
|
+
def split_into_words(doc, name=''):
|
126
|
+
|
127
|
+
mecab = MeCab.Tagger("-Ochasen")
|
128
|
+
|
129
|
+
valid_doc = trim_doc(doc)
|
130
|
+
|
131
|
+
lines = mecab.parse(doc).splitlines()
|
132
|
+
|
133
|
+
words = []
|
134
|
+
|
135
|
+
for line in lines:
|
136
|
+
|
137
|
+
chunks = line.split("\t")
|
138
|
+
|
139
|
+
if len(chunks) > 3 and (chunks[3].startswith('動詞') or chunks[3].startswith('形容詞') or (chunks[3].startswith('名詞') and not chunks[3].startswith('名詞-数'))):
|
140
|
+
|
141
|
+
words.append(chunks[0])
|
142
|
+
|
143
|
+
return LabeledSentence(words=words, tags=[name])
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
#ファイルから単語のリストを取得
|
148
|
+
|
149
|
+
def corpus_to_sentences(corpus):
|
150
|
+
|
151
|
+
docs=[read_document(x) for x in corpus]
|
152
|
+
|
153
|
+
for idx, (doc, name) in enumerate(zip(docs, corpus)):
|
154
|
+
|
155
|
+
sys.stdout.write('\r前処理{}/{}'.format(idx, len(corpus)))
|
156
|
+
|
157
|
+
yield split_into_words(doc, name)
|
158
|
+
|
159
|
+
|
160
|
+
|
161
|
+
#学習
|
162
|
+
|
163
|
+
def train(sentences):
|
164
|
+
|
165
|
+
model = models.Doc2Vec(alpha=0.0015, sample=1e-4, min_count=1, workers=4)
|
166
|
+
|
167
|
+
model.build_vocab(sentences)
|
168
|
+
|
169
|
+
for x in range(30):
|
170
|
+
|
171
|
+
print(x)
|
172
|
+
|
173
|
+
model.train(sentences, total_examples=model.corpus_count, epochs=model.iter)
|
174
|
+
|
175
|
+
ranks = []
|
176
|
+
|
177
|
+
for doc_id in range(100):
|
178
|
+
|
179
|
+
inferred_vector = model.infer_vector(sentences[doc_id].words)
|
180
|
+
|
181
|
+
sims = model.docvecs.most_similar([inferred_vector], topn=len(model.docvecs))
|
182
|
+
|
183
|
+
rank = [docid for docid, sim in sims].index(sentences[doc_id].tags[0])
|
184
|
+
|
185
|
+
ranks.append(rank)
|
186
|
+
|
187
|
+
print(collections.Counter(ranks))
|
188
|
+
|
189
|
+
if collections.Counter(ranks)[0] >= PASSING_PRECISION:
|
190
|
+
|
191
|
+
break
|
192
|
+
|
193
|
+
return model
|
194
|
+
|
195
|
+
|
196
|
+
|
197
|
+
if __name__ == '__main__':
|
198
|
+
|
199
|
+
corpus = list(get_all_files(INPUT_DOC_DIR))
|
200
|
+
|
201
|
+
sentences = list(corpus_to_sentences(corpus))
|
202
|
+
|
203
|
+
print()
|
204
|
+
|
205
|
+
model = train(sentences)
|
206
|
+
|
207
|
+
model.save(OUTPUT_MODEL)
|
208
|
+
|
209
|
+
```
|
210
|
+
|
211
|
+
|
212
|
+
|
213
|
+
下の部分で学習と評価を行っています。
|
214
|
+
|
215
|
+
```
|
216
|
+
|
217
|
+
for x in range(30):
|
218
|
+
|
219
|
+
print(x)
|
220
|
+
|
221
|
+
model.train(sentences, total_examples=model.corpus_count, epochs=model.iter)
|
222
|
+
|
223
|
+
ranks = []
|
224
|
+
|
225
|
+
for doc_id in range(100):
|
226
|
+
|
227
|
+
inferred_vector = model.infer_vector(sentences[doc_id].words)
|
228
|
+
|
229
|
+
sims = model.docvecs.most_similar([inferred_vector], topn=len(model.docvecs))
|
230
|
+
|
231
|
+
rank = [docid for docid, sim in sims].index(sentences[doc_id].tags[0])
|
232
|
+
|
233
|
+
ranks.append(rank)
|
234
|
+
|
235
|
+
print(collections.Counter(ranks))
|
236
|
+
|
237
|
+
if collections.Counter(ranks)[0] >= PASSING_PRECISION:
|
238
|
+
|
239
|
+
break
|
240
|
+
|
241
|
+
```
|
242
|
+
|
243
|
+
評価は、学習した文章のうち100個で類似の文章を検索し、最も類似度の高い文章が自分自身だった回数で行います。
|
244
|
+
|
245
|
+
|
246
|
+
|
247
|
+
評価の出力結果は以下の通りです。
|
248
|
+
|
249
|
+
```
|
20
250
|
|
21
251
|
$python3.6 program_v1.py
|
22
252
|
|
23
|
-
前処理 3950/3951
|
24
|
-
|
25
253
|
0
|
26
254
|
|
27
255
|
Counter({0: 36, 2: 8, 1: 5, 3: 3, 62: 2, 8: 2, 3721: 1, 2457: 1, 296: 1,(以下略)})
|
@@ -40,18 +268,26 @@
|
|
40
268
|
|
41
269
|
以下略
|
42
270
|
|
43
|
-
|
271
|
+
```
|
272
|
+
|
44
|
-
|
273
|
+
2行目の0,4行目の1 などの数字は学習回数で、
|
274
|
+
|
275
|
+
Counterはの:の左は文書、右は最も類似度の高い文書が自分自身だった回数を表しています。
|
276
|
+
|
277
|
+
|
278
|
+
|
45
|
-
|
279
|
+
###発生している問題
|
280
|
+
|
46
|
-
|
281
|
+
学習を繰り返すたびに自分自身を示す回数が減ってしまうのは何が原因なのでしょうか。
|
282
|
+
|
283
|
+
|
284
|
+
|
47
|
-
|
285
|
+
また、初めてプログラムを実行したとき、評価で自分自信だった回数は最大36回でした。
|
48
|
-
|
286
|
+
|
49
|
-
|
287
|
+
その後、作成されたモデルを削除して、再びプログラムを実行したところ、評価で自分自身だった回数は多くても4回くらいです。
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
288
|
+
|
54
|
-
|
55
|
-
|
289
|
+
なぜ、モデルを作り直したはずなのに、最初に実行した時と似た結果にならないのでしょうか。
|
290
|
+
|
291
|
+
|
56
292
|
|
57
293
|
よろしくお願いします。
|