alv*_*vas 69 python string nlp similarity cosine-similarity
从Python:tf-idf-cosine:为了找到文档相似性,可以使用tf-idf余弦计算文档相似度.没有导入外部库,是否有任何方法可以计算2个字符串之间的余弦相似度?
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
Run Code Online (Sandbox Code Playgroud)
vpe*_*kar 154
一个简单的纯Python实现将是:
import re, math
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 vec1.keys()])
sum2 = sum([vec2[x]**2 for x in 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
Run Code Online (Sandbox Code Playgroud)
打印:
Cosine: 0.861640436855
Run Code Online (Sandbox Code Playgroud)
这里所用的余弦公式描述这里.
这不包括tf-idf对单词的加权,但是为了使用tf-idf,你需要有一个相当大的语料库来估计tfidf权重.
您还可以通过使用更复杂的方法从一段文本中提取单词,词干或对其进行词干化等来进一步开发它.
mba*_*rov 51
简短的回答是"不,不可能以有原则的方式做到这一点,甚至可以很好地工作".这是自然语言处理研究中尚未解决的问题,也恰好是我博士工作的主题.我将简要总结一下我们所处的位置并指出一些出版物:
词义
这里最重要的假设是有可能获得一个代表句子中每个单词的向量.通常选择此向量来捕获单词可以出现的上下文.例如,如果我们只考虑三个上下文"吃","红色"和"蓬松",单词"cat"可能表示为[98,1 ,87,因为如果你要阅读一段非常长的文本(按照今天的标准,几十亿字并不少见),"cat"这个词经常出现在"蓬松"和"吃"的语境中,但不是经常在"红色"的背景下.以同样的方式,"狗"可能表示为[87,2,34],"伞"可能表示为[1,13,0].将这些矢量成像为3D空间中的点,"猫"显然更接近"狗"而不是"伞",因此"猫"也意味着更类似于"狗"而不是"伞".
自90年代初以来,这项工作已经进行了调查(例如,Greffenstette的这项工作),并取得了一些令人惊讶的好结果.例如,这里是我最近通过让我的计算机阅读维基百科建立的词库中的一些随机条目:
theory -> analysis, concept, approach, idea, method
voice -> vocal, tone, sound, melody, singing
james -> william, john, thomas, robert, george, charles
Run Code Online (Sandbox Code Playgroud)
这些类似单词的列表完全是在没有人为干预的情况下获得的 - 您将文本输入并在几小时后返回.
短语的问题
你可能会问为什么我们不会对更长的短语做同样的事情,比如"生姜狐狸爱水果".这是因为我们没有足够的文字.为了让我们可靠地确定X 与之类似,我们需要看到许多X在上下文中使用的例子.当X是像"语音"这样的单个词时,这并不太难.然而,随着X越来越长,找到X的自然出现的几率会以指数方式变慢.相比之下,谷歌有大约1B页包含"狐狸"这个词,而不是包含"生姜爱水果"的单页,尽管它是一个完全有效的英语句子,我们都明白这意味着什么.
组成
为了解决数据稀疏性问题,我们希望执行组合,即采用易于从真实文本中获取的单词的向量,并以一种捕获其含义的方式组合在一起.坏消息是到目前为止还没有人能够做到这一点.
最简单和最明显的方法是将各个单词向量相加或相乘.这导致了不良的副作用,"猫追狗"和"狗追猫"对你的系统意味着相同.此外,如果你正在成倍增加,你必须要格外小心,否则每个句子最终都会被[0,0,0,...,0]表示,这会使得这一点失败.
进一步阅读
我不会讨论到目前为止提出的更复杂的构图方法.我建议你阅读Katrin Erk的"矢量空间模型的词义和短语含义:一项调查".这是一个非常好的高级调查,可以帮助您入门.不幸的是,发布者的网站上没有免费提供,请直接通过电子邮件发送给作者以获取副本.在该论文中,您将找到更多具体方法的参考.更容易理解的是Mitchel和Lapata(2008)以及Baroni和Zamparelli(2010).
@vpekar评论后编辑:这个答案的底线是强调这样一个事实:虽然天真的方法确实存在(例如加法,乘法,表面相似性等),但这些基本上是有缺陷的,一般来说不应该期望从他们.
我有类似的解决方案,但可能对熊猫有用
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)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
86820 次 |
| 最近记录: |