使用 doc2vec 嵌入的相似性得分是很远的
similarity score is way off using doc2vec embedding
我正在尝试对最近准备的 NY-Times 语料库进行文档去重。它包含与金融欺诈相关的数据。
首先,我将文章片段转换为 TaggedDocument
个对象的列表。
nlp = spacy.load("en_core_web_sm")
def create_tagged_doc(doc, nlp):
toks = nlp(doc)
lemmatized_toks = [tok.lemma_ for tok in toks if not tok.is_stop]
return lemmatized_toks
df_fraud = pd.read_csv('...local_path...')
df_fraud_list = df_fraud['snippet'].to_list()
documents = [TaggedDocument(create_tagged_doc(doc, nlp), [i]) for i, doc in enumerate(df_fraud_list)]
示例 TaggedDocument
如下所示:
TaggedDocument(words=['Chicago', 'woman', 'fall', 'mortgage', 'payment',
'victim', 'common', 'fraud', 'know', 'equity', 'strip', '.'], tags=[1])
现在我编译并训练 Doc2Vec 模型。
cores = multiprocessing.cpu_count()
model_dbow = Doc2Vec(dm=0, vector_size=100, negative=5, hs=0, min_count=2, sample = 0, workers=cores)
model_dbow.build_vocab(documents)
model_dbow.train(documents,
total_examples=model_dbow.corpus_count,
epochs=model_dbow.epochs)
让我们定义余弦相似度:
cosine_sim = lambda x, y: np.inner(x, y) / (norm(x) * norm(y))
现在,问题是,如果我定义两个几乎相似的句子并计算它们的余弦相似度分数,它会变得非常低。例如
a = model_dbow.infer_vector(create_tagged_doc('That was a fradulent transaction.', nlp))
b = model_dbow.infer_vector(create_tagged_doc('That transaction was fradulant.', nlp))
print(cosine_sim(a, b)) # 0.07102317
为了确定,我重复检查了完全相同的向量,它是正确的。
a = model_dbow.infer_vector(create_tagged_doc('That was a fradulent transaction.', nlp))
b = model_dbow.infer_vector(create_tagged_doc('That was a fradulent transaction.', nlp))
print(cosine_sim(a, b)) # 0.9980062
这里出了什么问题?
看来是纪元数的问题。在不指定纪元数的情况下创建 Doc2Vec 实例时,例如model_dbow = Doc2Vec(dm=0, vector_size=100, negative=5, hs=0, min_count=2, sample = 0, workers=cores)
,默认设置为5。显然这对我的语料库来说还不够。我将 epochs 设置为 50,然后重新训练模型,瞧!成功了。
让我们看看您传递给 infer_vector()
的实际令牌:
In [4]: create_tagged_doc('That was a fradulent transaction.', nlp)
Out[4]: ['fradulent', 'transaction', '.']
In [5]: create_tagged_doc('That transaction was fradulant.', nlp)
Out[5]: ['transaction', 'fradulant', '.']
拼写错误 'fraudulant'
可能不在您的 NYT 语料库中,因此 Doc2Vec
模型可能不知道,因此会被忽略。所以你真的在计算文档向量:
['fradulent', 'transaction', '.']
对比 ['transaction', '.']
此外,'.'
可能不是很重要 - 特别是如果它出现在 所有 训练示例中。请注意,微小的例子(一到几个词)没有很多微妙的对比影响来平衡——它们是直截了当的话语,可能与大部分训练数据不同,并且推理将相对较短且平衡最小影响(与较长的文本相比)。
例如,在单词和向量共同训练和比较的 Doc2Vec
模型中,如 PV-DM 模型 (dm=1
),我不确定是否对于单个 -像 ['transaction']
这样的单词文档,更有用的向量是对该标记列表的推断,或者只是 'transaction'
.
的单词向量
最后,由于相似度的范围是 -1.0
到 1.0
,0.07
可能 那 对于一个有效的['fradulent', 'transaction', '.']
和 ['transaction', '.']
.
之间的比较
我正在尝试对最近准备的 NY-Times 语料库进行文档去重。它包含与金融欺诈相关的数据。
首先,我将文章片段转换为 TaggedDocument
个对象的列表。
nlp = spacy.load("en_core_web_sm")
def create_tagged_doc(doc, nlp):
toks = nlp(doc)
lemmatized_toks = [tok.lemma_ for tok in toks if not tok.is_stop]
return lemmatized_toks
df_fraud = pd.read_csv('...local_path...')
df_fraud_list = df_fraud['snippet'].to_list()
documents = [TaggedDocument(create_tagged_doc(doc, nlp), [i]) for i, doc in enumerate(df_fraud_list)]
示例 TaggedDocument
如下所示:
TaggedDocument(words=['Chicago', 'woman', 'fall', 'mortgage', 'payment',
'victim', 'common', 'fraud', 'know', 'equity', 'strip', '.'], tags=[1])
现在我编译并训练 Doc2Vec 模型。
cores = multiprocessing.cpu_count()
model_dbow = Doc2Vec(dm=0, vector_size=100, negative=5, hs=0, min_count=2, sample = 0, workers=cores)
model_dbow.build_vocab(documents)
model_dbow.train(documents,
total_examples=model_dbow.corpus_count,
epochs=model_dbow.epochs)
让我们定义余弦相似度:
cosine_sim = lambda x, y: np.inner(x, y) / (norm(x) * norm(y))
现在,问题是,如果我定义两个几乎相似的句子并计算它们的余弦相似度分数,它会变得非常低。例如
a = model_dbow.infer_vector(create_tagged_doc('That was a fradulent transaction.', nlp))
b = model_dbow.infer_vector(create_tagged_doc('That transaction was fradulant.', nlp))
print(cosine_sim(a, b)) # 0.07102317
为了确定,我重复检查了完全相同的向量,它是正确的。
a = model_dbow.infer_vector(create_tagged_doc('That was a fradulent transaction.', nlp))
b = model_dbow.infer_vector(create_tagged_doc('That was a fradulent transaction.', nlp))
print(cosine_sim(a, b)) # 0.9980062
这里出了什么问题?
看来是纪元数的问题。在不指定纪元数的情况下创建 Doc2Vec 实例时,例如model_dbow = Doc2Vec(dm=0, vector_size=100, negative=5, hs=0, min_count=2, sample = 0, workers=cores)
,默认设置为5。显然这对我的语料库来说还不够。我将 epochs 设置为 50,然后重新训练模型,瞧!成功了。
让我们看看您传递给 infer_vector()
的实际令牌:
In [4]: create_tagged_doc('That was a fradulent transaction.', nlp)
Out[4]: ['fradulent', 'transaction', '.']
In [5]: create_tagged_doc('That transaction was fradulant.', nlp)
Out[5]: ['transaction', 'fradulant', '.']
拼写错误 'fraudulant'
可能不在您的 NYT 语料库中,因此 Doc2Vec
模型可能不知道,因此会被忽略。所以你真的在计算文档向量:
['fradulent', 'transaction', '.']
对比 ['transaction', '.']
此外,'.'
可能不是很重要 - 特别是如果它出现在 所有 训练示例中。请注意,微小的例子(一到几个词)没有很多微妙的对比影响来平衡——它们是直截了当的话语,可能与大部分训练数据不同,并且推理将相对较短且平衡最小影响(与较长的文本相比)。
例如,在单词和向量共同训练和比较的 Doc2Vec
模型中,如 PV-DM 模型 (dm=1
),我不确定是否对于单个 -像 ['transaction']
这样的单词文档,更有用的向量是对该标记列表的推断,或者只是 'transaction'
.
最后,由于相似度的范围是 -1.0
到 1.0
,0.07
可能 那 对于一个有效的['fradulent', 'transaction', '.']
和 ['transaction', '.']
.