文本相似度查询html代码,常见文本相似度计算方式及代码

常见文本相似度计算方式及代码

文本相似度的计算广泛的运用在信息检索,搜索引擎, 文档复制等处:

因此在各种不同的情况与任务中,有不同的文本相似度计算。

近期在处理搜索引擎的相关项目

下面介绍一下我们主要使用的相似度计算方式及其实现 Github

余弦相似度:

余弦相似度是纯数学中的概念,首先,将进行计算的两个str中的word抽取出来,用作非重复词库。

遍历词库,将两个句子的表示向量化: 每个向量长度为 词库大小

import numpy as np

def cosine_similarity(sentence1: str, sentence2: str) -> float:

"""

compute normalized COSINE similarity.

:param sentence1: English sentence.

:param sentence2: English sentence.

:return: normalized similarity of two input sentences.

"""

seg1 = sentence1.strip(" ").split(" ")

seg2 = sentence2.strip(" ").split(" ")

word_list = list(set([word for word in seg1 + seg2]))

word_count_vec_1 = []

word_count_vec_2 = []

for word in word_list:

word_count_vec_1.append(seg1.count(word))

word_count_vec_2.append(seg2.count(word))

vec_1 = np.array(word_count_vec_1)

vec_2 = np.array(word_count_vec_2)

num = vec_1.dot(vec_2.T)

denom = np.linalg.norm(vec_1) * np.linalg.norm(vec_2)

cos = num / denom

sim = 0.5 + 0.5 * cos

return sim

编辑距离:

编辑距离是指文本A变为文本B的处理次数

处理包含:

删除一个字符

增加一个字符

修改一个字符

例如:

A: requiremant

B: requirements

step1: requiremant -> requirement

step2: requirement -> requirements

所以编辑距离为2

# Using difflib is python 3.6 default package

import difflib

def compute_levenshtein_distance(sentence1: str, sentence2: str) -> int:

"""

compute levenshtein distance.

"""

leven_cost = 0

s = difflib.SequenceMatcher(None, sentence1, sentence2)

for tag, i1, i2, j1, j2 in s.get_opcodes():

if tag == 'replace':

leven_cost += max(i2 - i1, j2 - j1)

elif tag == 'insert':

leven_cost += (j2 - j1)

elif tag == 'delete':

leven_cost += (i2 - i1)

return leven_cost

利文斯顿相似度

利文斯顿距离即为编辑距离

而做相似度度量时,所需要的范围为0-1之间浮点数

因此需要将上述的编辑距离整数值转换为normalize的分数

def compute_levenshtein_similarity(sentence1: str, sentence2: str) -> float:

"""Compute the hamming similarity."""

leven_cost = compute_levenshtein_distance(sentence1, sentence2)

return 1 - (leven_cost / len(sentence2))

Simhash & 汉明距离

计算字符串之间的相似度,步骤如下:

分词 :将字符串之间分词(中文需要分词,英文本身具有空格)

HASH :将每个单词进行hash,生成长度相同的01序列

加权 :计算每个单词本身的权重,例如 -4, 5 等等不同的权重,与0/1字符串相乘,1为正, 0为负, 例如:

W(清华) = 100101*4 = 4 -4 -4 4 -4 4

W(大学)=101011*5 = 5 -5 5 -5 5 5

合并 : 将上述各个词语,与权重相乘之后的hash数值相加

W(清华大学) = (4+5) (-4-5) (-4+5) (4-5) (-4+5) (4+5) = 9 -9 1 -1 1 9

降维: 将上述数值进行降维, ≥1\ge 1≥1的转换为1, ≤0\le 0≤0的转换为0

W(清华大学) = 1 0 1 0 1 1

则可以计算出 句子的代表数值,同样长度的句子0/1数值对应位置进行与运算,true值数量与句子总长度比例,则可以得出hamming distance.

此处代码使用了 python simHash package.

安装与使用tutorial

import re

from simhash import Simhash

def compute_simhash_hamming_similarity(sentence1: str, sentence2: str) -> float:

"""need to normalize after compute!"""

def get_features(s):

width = 3

s = s.lower()

s = re.sub(r'[^\w]+', '', s)

return [s[i:i + width] for i in range(max(len(s) - width + 1, 1))]

hash_value1 = Simhash(get_features(sentence1)).value

hash_value2 = Simhash(get_features(sentence2)).value

return compute_levenshtein_similarity(str(hash_value1), str(hash_value2))

Jaccard系数

SaS_aSa​ 是sentence A

SbS_bSb​ 是sentence B

其单词交集与单词并集的比例即为杰卡德相似系数

(若遇见相同单词,则需要看数量重复是否占比很高,具体情况而定。两项处理均可。)

Sa∩SbSa∪Sb\frac{S_a \cap S_b}{S_a \cup S_b}Sa​∪Sb​Sa​∩Sb​​

def compute_jaccard_similarity(sentence1: str, sentence2: str) -> float:

word_set1 = set(sentence1.strip(" ").split(" "))

word_set2 = set(sentence2.strip(" ").split(" "))

return len(word_set1 & word_set2) / len(word_set1 | word_set2)

TF-IDF

TF其实由两项组成:

TF: Term Frequency

IDF: Inverse Document Frequency

TF 代表了词语在文档中出现的频率,当进行索引的时候,词语出现频率较高的文本,匹配度也会较高,但是某些停止词,例如 to 在文本中会出现相当多的次数,但这对匹配并没有起到很好的索引作用,因此需要引入另一个度量值 IDF(逆文本频率)

IDF=logNN(x)IDF = log\frac{N}{N(x)}IDF=logN(x)N​

其中NNN为语料库中文本的总数,N(x)N(x)N(x)为文本中出现单词xxx的文本数量。

次可以度量该单词的重要程度。

某些特殊情况下,xxx并未出现在语料库中(所有文本),则需要考虑将公式平滑为:

IDF=logN+1N(x)+1+1IDF = log\frac{N+1}{N(x)+1}+1IDF=logN(x)+1N+1​+1

最终的TF-IDF值为:

TF−IDF(x)=TF(x)∗IDF(x)TF-IDF(x) = TF(x) * IDF(x)TF−IDF(x)=TF(x)∗IDF(x)

此处我们调用了nltk工具库来实现TF-IDF计算:

由于query可能有2-3个单词同时建立索引,此处采用了平均值。

from nltk.text import TextCollection

from nltk.tokenize import word_tokenize

def compute_tf_idf_similarity(query: str, content: str, type: str) -> float:

"""

Compute the mean tf-idf or tf

similarity for one sentence with multi query words.

:param query: a string contain all key word split by one space

:param content: string list with every content relevent to this query.

:return: average tf-idf or tf similarity.

"""

sents = [word_tokenize(content), word_tokenize("")] # add one empty file to smooth.

corpus = TextCollection(sents) # 构建语料库

result_list = []

for key_word in query.strip(" ").split(" "):

if type == "tf_idf":

result_list.append(corpus.tf_idf(key_word, corpus))

elif type == "tf":

result_list.append(corpus.tf(key_word, corpus))

else:

raise KeyError

return sum(result_list) / len(result_list)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值