给定 2 个句子字符串计算余弦相似度

2025-01-10 08:47:00
admin
原创
112
摘要:问题描述:从Python:tf-idf-cosine:查找文档相似度,可以使用 tf-idf 余弦计算文档相似度。如果不导入外部库,有什么方法可以计算两个字符串之间的余弦相似度吗?s1 = "This is a foo bar sentence ." s2 = "This sen...

问题描述:

从Python:tf-idf-cosine:查找文档相似度,可以使用 tf-idf 余弦计算文档相似度。如果不导入外部库,有什么方法可以计算两个字符串之间的余弦相似度吗?

s1 = "This is a foo bar sentence ."
s2 = "This sentence is similar to a foo bar sentence ."
s3 = "What is this string ? Totally not related to the other two lines ."

cosine_sim(s1, s2) # Should give high cosine similarity
cosine_sim(s1, s3) # Shouldn't give high cosine similarity value
cosine_sim(s2, s3) # Shouldn't give high cosine similarity value

解决方案 1:

一个简单的纯 Python 实现是:

import math
import re
from collections import Counter

WORD = re.compile(r"w+")


def get_cosine(vec1, vec2):
    intersection = set(vec1.keys()) & set(vec2.keys())
    numerator = sum([vec1[x] * vec2[x] for x in intersection])

    sum1 = sum([vec1[x] ** 2 for x in list(vec1.keys())])
    sum2 = sum([vec2[x] ** 2 for x in list(vec2.keys())])
    denominator = math.sqrt(sum1) * math.sqrt(sum2)

    if not denominator:
        return 0.0
    else:
        return float(numerator) / denominator


def text_to_vector(text):
    words = WORD.findall(text)
    return Counter(words)


text1 = "This is a foo bar sentence ."
text2 = "This sentence is similar to a foo bar sentence ."

vector1 = text_to_vector(text1)
vector2 = text_to_vector(text2)

cosine = get_cosine(vector1, vector2)

print("Cosine:", cosine)

印刷:

Cosine: 0.861640436855

这里使用的余弦公式描述如下。

这不包括通过 tf-idf 对单词进行加权,但是为了使用 tf-idf,您需要有一个相当大的语料库来估计 tfidf 权重。

您还可以进一步开发它,通过使用更复杂的方法从一段文本中提取单词、对其进行词干或词形还原等。

解决方案 2:

简短的回答是“不,不可能以有原则的方式做到这一点,甚至效果也不太好”。这是自然语言处理研究中尚未解决的问题,也是我博士论文的主题。我将非常简要地总结一下我们目前的情况,并向您介绍一些出版物:

词语含义

这里最重要的假设是,有可能获得一个表示问题句子中每个单词的向量。通常选择这个向量来捕获单词可能出现的上下文。例如,如果我们只考虑三个上下文“吃”、“红色”和“毛茸茸的”,单词“猫”可能表示为 [98, 1, 87],因为如果你要阅读一段非常长的文本(按今天的标准,几十亿个单词并不罕见),单词“猫”会经常出现在“毛茸茸的”和“吃”的上下文中,但在“红色”的上下文中出现的频率并不高。同样,“狗”可能表示为 [87,2,34],“雨伞”可能表示为 [1,13,0]。将这些向量想象成 3D 空间中的点,“猫”显然更接近“狗”而不是“雨伞”,因此“猫”的意思也更类似于“狗”而不是“雨伞”。

这项工作自 20 世纪 90 年代初开始被研究(例如Greffenstette 的这项工作),并取得了一些令人惊讶的成果。例如,这是我最近通过计算机阅读维基百科建立的同义词库中的一些随机条目:

theory -> analysis, concept, approach, idea, method
voice -> vocal, tone, sound, melody, singing
james -> william, john, thomas, robert, george, charles

这些相似词汇的列表完全是在没有人工干预的情况下获得的 - 您输入文本然后在几个小时后返回。

短语的问题

您可能会问,为什么我们不对较长的短语(例如“姜狐狸爱水果”)做同样的事情。这是因为我们没有足够的文本。为了可靠地确定 X 与什么相似,我们需要看到许多 X 在上下文中使用的示例。当 X 是一个单词(例如“声音”)时,这并不太难。但是,随着 X 越来越长,找到 X 自然出现的机会会呈指数级下降。相比之下,Google 有大约 10 亿个页面包含单词“fox”,而没有一个页面包含“姜狐狸爱水果”,尽管这是一个完全有效的英语句子,我们都明白它的意思。

作品

为了解决数据稀疏性问题,我们希望进行组合,即获取单词向量(这些向量很容易从真实文本中获得),然后以能够捕捉其含义的方式将它们组合在一起。坏消息是,到目前为止,还没有人能够很好地做到这一点。

最简单、最明显的方法是将各个词向量相加或相乘。这会导致不良的副作用,即“猫追狗”和“狗追猫”对您的系统来说意味着相同。此外,如果您要进行乘法运算,则必须格外小心,否则每个句子最终都会由 [0,0,0,...,0] 表示,这违背了要点。

进一步阅读

我不会讨论迄今为止提出的更复杂的组合方法。我建议你阅读 Katrin Erk 的“词义和短语义的向量空间模型:调查”。这是一篇非常好的高级调查,可以帮助你入门。不幸的是,在出版商的网站上没有免费提供,请直接给作者发送电子邮件以获取副本。在那篇论文中,你会找到许多更具体方法的参考。更易理解的是Mitchel 和 Lapata (2008)和Baroni 和 Zamparelli (2010)的论文。


在@vpekar 评论后进行编辑:这个答案的底线是强调这样一个事实:虽然确实存在简单的方法(例如加法、乘法、表面相似性等),但这些方法从根本上是有缺陷的,一般来说,不要指望它们有很好的性能。

解决方案 3:

我有类似的解决方案,但可能对熊猫有用

import math
import re
from collections import Counter
import pandas as pd

WORD = re.compile(r"w+")


def get_cosine(vec1, vec2):
    intersection = set(vec1.keys()) & set(vec2.keys())
    numerator = sum([vec1[x] * vec2[x] for x in intersection])

    sum1 = sum([vec1[x] ** 2 for x in list(vec1.keys())])
    sum2 = sum([vec2[x] ** 2 for x in list(vec2.keys())])
    denominator = math.sqrt(sum1) * math.sqrt(sum2)

    if not denominator:
        return 0.0
    else:
        return float(numerator) / denominator


def text_to_vector(text):
    words = WORD.findall(text)
    return Counter(words)

df=pd.read_csv('/content/drive/article.csv')
df['vector1']=df['headline'].apply(lambda x: text_to_vector(x)) 
df['vector2']=df['snippet'].apply(lambda x: text_to_vector(x)) 
df['simscore']=df.apply(lambda x: get_cosine(x['vector1'],x['vector2']),axis=1)

解决方案 4:

试试这个。从https://conceptnet.s3.amazonaws.com/downloads/2017/numberbatch/numberbatch-en-17.06.txt.gz下载文件“numberbatch-en-17.06.txt”并解压。函数“get_sentence_vector”使用词向量的简单和。但是,可以使用加权和来改进它,其中权重与每个单词的 Tf-Idf 成比例。

import math
import numpy as np

std_embeddings_index = {}
with open('path/to/numberbatch-en-17.06.txt') as f:
    for line in f:
        values = line.split(' ')
        word = values[0]
        embedding = np.asarray(values[1:], dtype='float32')
        std_embeddings_index[word] = embedding

def cosineValue(v1,v2):
    "compute cosine similarity of v1 to v2: (v1 dot v2)/{||v1||*||v2||)"
    sumxx, sumxy, sumyy = 0, 0, 0
    for i in range(len(v1)):
        x = v1[i]; y = v2[i]
        sumxx += x*x
        sumyy += y*y
        sumxy += x*y
    return sumxy/math.sqrt(sumxx*sumyy)


def get_sentence_vector(sentence, std_embeddings_index = std_embeddings_index ):
    sent_vector = 0
    for word in sentence.lower().split():
        if word not in std_embeddings_index :
            word_vector = np.array(np.random.uniform(-1.0, 1.0, 300))
            std_embeddings_index[word] = word_vector
        else:
            word_vector = std_embeddings_index[word]
        sent_vector = sent_vector + word_vector

    return sent_vector

def cosine_sim(sent1, sent2):
    return cosineValue(get_sentence_vector(sent1), get_sentence_vector(sent2))

我确实运行了给定的句子并发现了以下结果

s1 = "This is a foo bar sentence ."
s2 = "This sentence is similar to a foo bar sentence ."
s3 = "What is this string ? Totally not related to the other two lines ."

print cosine_sim(s1, s2) # Should give high cosine similarity
print cosine_sim(s1, s3) # Shouldn't give high cosine similarity value
print cosine_sim(s2, s3) # Shouldn't give high cosine similarity value

0.9851735249068168
0.6570885718962608
0.6589335425458225

解决方案 5:

我能想到的最简单的答案包括 CounterVectorizer。

假设我们有 3 段文本。

text_1 = """ """

text_2 = """ """

text_3 = """ """

documents = [text_1, text_2, text_3]
  1. 为了计算余弦相似度,我们需要每个文档的单词计数矩阵

import pandas as pd

# Create the Document Term Matrix
count_vectorizer = CountVectorizer(stop_words='english')
count_vectorizer = CountVectorizer()
sparse_matrix = count_vectorizer.fit_transform(documents)

# OPTIONAL: Convert Sparse Matrix to Pandas Dataframe if you want to see the word frequencies.
doc_term_matrix = sparse_matrix.todense()
df = pd.DataFrame(doc_term_matrix, 
                  columns=count_vectorizer.get_feature_names(), 
                  index=['text_1', 'text_2', 'text_3'])
df
  1. 只需使用 sklearn 中的余弦相似度函数即可完成这项工作。

from sklearn.metrics.pairwise import cosine_similarity
print(cosine_similarity(df, df))

解决方案 6:

好吧,如果您知道Glove/Word2Vec/Numberbatch 之类的词嵌入,那么您的工作就完成了一半。如果不了解,让我来解释如何解决这个问题。将每个句子转换为单词标记,并将每个标记表示为高维向量(使用预先训练的词嵌入,或者您甚至可以自己训练它们!)。所以,现在您不仅要捕捉它们的表面相似性,还要提取构成整个句子的每个单词的含义。在此之后,计算它们的余弦相似性,您就大​​功告成了。

解决方案 7:

感谢@vpekar 的实现。它帮了大忙。我刚刚发现它在计算余弦相似度时遗漏了 tf-idf 权重。Counter(word) 返回一个字典,其中包含单词列表及其出现次数。

cos(q, d) = sim(q, d) = (q · d)/(|q||d|) = (sum(qi, di)/(sqrt(sum(qi2)))*(sqrt(sum(vi2))) 其中 i = 1 至 v)

  • qi 是查询中术语 i 的 tf-idf 权重。

  • di 是 tf-idf

  • 文档中术语 i 的权重。|q| 和 |d| 是 q 和 d 的长度。

  • 这是 q 和 d 的余弦相似度......或者,等效地,q 和 d 之间角度的余弦。

请随意在此处查看我的代码。但首先您必须下载 anaconda 包。它将自动在 Windows 中设置您的 python 路径。在 Eclipse 中添加此 python 解释器。

解决方案 8:

如果不依赖外部库,你可以尝试 BLEU 或者它的替代品。你可以参考它的标准实现:SACREBLEU。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用