質問編集履歴
2
インデントの修正
title
CHANGED
File without changes
|
body
CHANGED
@@ -42,22 +42,23 @@
|
|
42
42
|
with open(path, 'r', errors='ignore') as f:
|
43
43
|
return f.read()
|
44
44
|
|
45
|
+
#不要な部分の削除
|
45
46
|
def trim_doc(doc):
|
46
|
-
lines = doc.splitlines()
|
47
|
+
lines = doc.splitlines()
|
47
|
-
valid_lines = []
|
48
|
+
valid_lines = []
|
48
|
-
is_valid =
|
49
|
+
is_valid = False
|
49
|
-
horizontal_rule_cnt = 0
|
50
|
+
horizontal_rule_cnt = 0
|
50
|
-
break_cnt = 0
|
51
|
+
break_cnt = 0
|
51
|
-
for line in lines:
|
52
|
+
for line in lines:
|
52
|
-
if horizontal_rule_cnt < 2 and 'Reply-to:' in line:
|
53
|
+
if horizontal_rule_cnt < 2 and 'Reply-to:' in line:
|
53
|
-
horizontal_rule_cnt += 1
|
54
|
+
horizontal_rule_cnt += 1
|
54
|
-
is_valid = horizontal_rule_cnt == 2
|
55
|
+
is_valid = horizontal_rule_cnt == 2
|
55
|
-
continue
|
56
|
+
continue
|
56
|
-
if not(is_valid):
|
57
|
+
if not(is_valid):
|
57
|
-
continue
|
58
|
+
continue
|
58
|
-
break_cnt =
|
59
|
+
break_cnt = 0
|
59
|
-
valid_lines.append(line)
|
60
|
+
valid_lines.append(line)
|
60
|
-
return ''.join(valid_lines)
|
61
|
+
return ''.join(valid_lines)
|
61
62
|
|
62
63
|
#文章から単語に分割して返す
|
63
64
|
def split_into_words(doc, name=''):
|
@@ -69,7 +70,7 @@
|
|
69
70
|
chunks = line.split("\t")
|
70
71
|
if len(chunks) > 3 and (chunks[3].startswith('動詞') or chunks[3].startswith('形容詞') or (chunks[3].startswith('名詞') and not chunks[3].startswith('名詞-数'))):
|
71
72
|
words.append(chunks[0])
|
72
|
-
return LabeledSentence(words=words, tags=[name])
|
73
|
+
return LabeledSentence(words=words, tags=[name])
|
73
74
|
|
74
75
|
#ファイルから単語のリストを取得
|
75
76
|
def corpus_to_sentences(corpus):
|
1
書式の改善
title
CHANGED
File without changes
|
body
CHANGED
@@ -1,15 +1,129 @@
|
|
1
|
+
###前提・実現したいこと
|
1
|
-
doc2vecを
|
2
|
+
doc2vecを用いて
|
2
3
|
VirtualBoxのcentOS上で、python3.6を使ってdoc2vecを動かしています。
|
3
4
|
|
5
|
+
実現したいプログラムは
|
6
|
+
・類似する単語の検索機能
|
7
|
+
です。
|
8
|
+
|
9
|
+
参考にしたプログラムはこちらのサイトにあったものです。
|
4
10
|
https://qiita.com/akira_/items/f9bb46cad6834da32367
|
11
|
+
文書を学習するプログラムと検索するプログラムは分かれていて、
|
5
|
-
|
12
|
+
学習するプログラムに問題が発生しました。
|
6
|
-
エラーが出るところは直して、ほとんど正常に動作するのですが、実行を繰り返すたびに精度が落ちていきます。
|
7
13
|
|
8
|
-
|
14
|
+
与えたプログラムは電子メールをプレーンテキストにしたもので、
|
9
15
|
|
16
|
+
```
|
17
|
+
def trim_doc(doc):
|
18
|
+
```
|
19
|
+
で不要な部分を削除してから与えました。
|
20
|
+
|
21
|
+
実際に書いたコードがこちらです。
|
22
|
+
```
|
23
|
+
import os
|
24
|
+
import sys
|
25
|
+
import MeCab
|
26
|
+
import collections
|
27
|
+
from gensim import models
|
28
|
+
from gensim.models.doc2vec import LabeledSentence
|
29
|
+
|
30
|
+
INPUT_DOC_DIR = './mail'
|
31
|
+
OUTPUT_MODEL = 'doc2vec.model'
|
32
|
+
PASSING_PRECISION = 93
|
33
|
+
|
10
|
-
|
34
|
+
#すべてのファイルのリストを取得
|
35
|
+
def get_all_files(directory):
|
36
|
+
for root, dirs, files in os.walk(directory):
|
37
|
+
for file in files:
|
38
|
+
yield os.path.join(root, file)
|
39
|
+
|
40
|
+
#ファイルから文章を返す
|
41
|
+
def read_document(path):
|
42
|
+
with open(path, 'r', errors='ignore') as f:
|
43
|
+
return f.read()
|
44
|
+
|
45
|
+
def trim_doc(doc):
|
46
|
+
lines = doc.splitlines()
|
47
|
+
valid_lines = []
|
48
|
+
is_valid = Falseadsf
|
49
|
+
horizontal_rule_cnt = 0
|
50
|
+
break_cnt = 0
|
51
|
+
for line in lines:
|
52
|
+
if horizontal_rule_cnt < 2 and 'Reply-to:' in line:
|
53
|
+
horizontal_rule_cnt += 1
|
54
|
+
is_valid = horizontal_rule_cnt == 2
|
55
|
+
continue
|
56
|
+
if not(is_valid):
|
57
|
+
continue
|
58
|
+
break_cnt = 0asfd
|
59
|
+
valid_lines.append(line)
|
60
|
+
return ''.join(valid_lines)
|
61
|
+
|
62
|
+
#文章から単語に分割して返す
|
63
|
+
def split_into_words(doc, name=''):
|
64
|
+
mecab = MeCab.Tagger("-Ochasen")
|
65
|
+
valid_doc = trim_doc(doc)
|
66
|
+
lines = mecab.parse(doc).splitlines()
|
67
|
+
words = []
|
68
|
+
for line in lines:
|
69
|
+
chunks = line.split("\t")
|
70
|
+
if len(chunks) > 3 and (chunks[3].startswith('動詞') or chunks[3].startswith('形容詞') or (chunks[3].startswith('名詞') and not chunks[3].startswith('名詞-数'))):
|
71
|
+
words.append(chunks[0])
|
72
|
+
return LabeledSentence(words=words, tags=[name])
|
73
|
+
|
74
|
+
#ファイルから単語のリストを取得
|
75
|
+
def corpus_to_sentences(corpus):
|
76
|
+
docs=[read_document(x) for x in corpus]
|
77
|
+
for idx, (doc, name) in enumerate(zip(docs, corpus)):
|
78
|
+
sys.stdout.write('\r前処理{}/{}'.format(idx, len(corpus)))
|
79
|
+
yield split_into_words(doc, name)
|
80
|
+
|
81
|
+
#学習
|
82
|
+
def train(sentences):
|
83
|
+
model = models.Doc2Vec(alpha=0.0015, sample=1e-4, min_count=1, workers=4)
|
84
|
+
model.build_vocab(sentences)
|
85
|
+
for x in range(30):
|
86
|
+
print(x)
|
87
|
+
model.train(sentences, total_examples=model.corpus_count, epochs=model.iter)
|
88
|
+
ranks = []
|
89
|
+
for doc_id in range(100):
|
90
|
+
inferred_vector = model.infer_vector(sentences[doc_id].words)
|
91
|
+
sims = model.docvecs.most_similar([inferred_vector], topn=len(model.docvecs))
|
92
|
+
rank = [docid for docid, sim in sims].index(sentences[doc_id].tags[0])
|
93
|
+
ranks.append(rank)
|
94
|
+
print(collections.Counter(ranks))
|
95
|
+
if collections.Counter(ranks)[0] >= PASSING_PRECISION:
|
96
|
+
break
|
97
|
+
return model
|
98
|
+
|
99
|
+
if __name__ == '__main__':
|
100
|
+
corpus = list(get_all_files(INPUT_DOC_DIR))
|
101
|
+
sentences = list(corpus_to_sentences(corpus))
|
102
|
+
print()
|
103
|
+
model = train(sentences)
|
104
|
+
model.save(OUTPUT_MODEL)
|
105
|
+
```
|
106
|
+
|
107
|
+
下の部分で学習と評価を行っています。
|
108
|
+
```
|
109
|
+
for x in range(30):
|
110
|
+
print(x)
|
111
|
+
model.train(sentences, total_examples=model.corpus_count, epochs=model.iter)
|
112
|
+
ranks = []
|
113
|
+
for doc_id in range(100):
|
114
|
+
inferred_vector = model.infer_vector(sentences[doc_id].words)
|
115
|
+
sims = model.docvecs.most_similar([inferred_vector], topn=len(model.docvecs))
|
116
|
+
rank = [docid for docid, sim in sims].index(sentences[doc_id].tags[0])
|
117
|
+
ranks.append(rank)
|
118
|
+
print(collections.Counter(ranks))
|
119
|
+
if collections.Counter(ranks)[0] >= PASSING_PRECISION:
|
120
|
+
break
|
121
|
+
```
|
122
|
+
評価は、学習した文章のうち100個で類似の文章を検索し、最も類似度の高い文章が自分自身だった回数で行います。
|
123
|
+
|
124
|
+
評価の出力結果は以下の通りです。
|
125
|
+
```
|
11
126
|
$python3.6 program_v1.py
|
12
|
-
前処理 3950/3951
|
13
127
|
0
|
14
128
|
Counter({0: 36, 2: 8, 1: 5, 3: 3, 62: 2, 8: 2, 3721: 1, 2457: 1, 296: 1,(以下略)})
|
15
129
|
1
|
@@ -19,11 +133,15 @@
|
|
19
133
|
3
|
20
134
|
Counter({1: 2, 3891: 2, 3941: 2, 5: 2, 2880: 2, 0: 2, 2057: 1, 1166: 1, 3399: 1,(以下略)})
|
21
135
|
以下略
|
136
|
+
```
|
137
|
+
2行目の0,4行目の1 などの数字は学習回数で、
|
138
|
+
Counterはの:の左は文書、右は最も類似度の高い文書が自分自身だった回数を表しています。
|
22
139
|
|
23
|
-
|
140
|
+
###発生している問題
|
141
|
+
学習を繰り返すたびに自分自身を示す回数が減ってしまうのは何が原因なのでしょうか。
|
24
142
|
|
143
|
+
また、初めてプログラムを実行したとき、評価で自分自信だった回数は最大36回でした。
|
25
|
-
|
144
|
+
その後、作成されたモデルを削除して、再びプログラムを実行したところ、評価で自分自身だった回数は多くても4回くらいです。
|
145
|
+
なぜ、モデルを作り直したはずなのに、最初に実行した時と似た結果にならないのでしょうか。
|
26
146
|
|
27
|
-
何が原因だと考えられるでしょうか。
|
28
|
-
また、どのような解決策があるでしょうか
|
29
147
|
よろしくお願いします。
|