当前位置:首页 > 技术杂坛 > 正文内容

python计算字符串相似度总结

zhangchap3年前 (2021-08-20)技术杂坛668

1、距离计算

包的安装:

pip install python-Levenshtein


levenshtein

编辑距离(Edit Distance),又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。一般来说,编辑距离越小,两个串的相似度越大。

接下来重点介绍下保重几个方法的作用:

Levenshtein.distance(str1, str2)

计算编辑距离(也称Levenshtein距离)。是描述由一个字串转化成另一个字串最少的操作次数,在其中的操作包括插入、删除、替换。算法实现:动态规划。

Levenshtein.hamming(str1, str2)

计算汉明距离。要求str1和str2必须长度一致。是描述两个等长字串之间对应位置上不同字符的个数。

Levenshtein.ratio(str1, str2)

计算莱文斯坦比。计算公式 r = (sum – ldist) / sum, 其中sum是指str1 和 str2 字串的长度总和,ldist是类编辑距离。注意这里是类编辑距离,在类编辑距离中删除、插入依然+1,但是替换+2。

Levenshtein.jaro(s1, s2)

计算jaro距离,Jaro Distance据说是用来判定健康记录上两个名字是否相同,也有说是是用于人口普查,我们先来看一下Jaro Distance的定义。

两个给定字符串S1和S2的Jaro Distance为:

Levenshtein.jaro_winkler(s1, s2)

1.1实际应用

def gen_title(word,relates:set):
    rsw = ''
    presimi = 0.1
    for rs in relates:
        simi = Levenshtein.jaro_winkler(word,rs)
        print(f'{word}--{rs}-->与其相识度:{simi}')
        if simi < 0.6 or simi >0.95:
            continue
        if simi > presimi:
            rsw = rs
            presimi = simi
    if not rsw:
        return word
    return f'{word}_{rsw}'


2、余弦相似度

余弦相似度可用来计算两个向量的相似程度

对于如何计算两个向量的相似程度问题,可以把这它们想象成空间中的两条线段,都是从原点([0, 0, ...])出发,指向不同的方向。两条线段之间形成一个夹角,如果夹角为0度,意味着方向相同、线段重合;如果夹角为90度,意味着形成直角,方向完全不相似;如果夹角为180度,意味着方向正好相反。因此,我们可以通过夹角的大小,来判断向量的相似程度。夹角越小,就代表越相似。

2.1 实际应用

# -*- coding: utf-8 -*-
"""
余弦相似性算法beta2.0(本次修改主要是通过只计算主干词语来提高相关性,去掉无用的停止词)
用于计算两个文本字符串的相似度
需要用到结巴分词, 算法耗时取决于字典(或者缓存字典)的加载时间
因此字典不宜过大,使用默认的字典就可以了
因为不需要进行精确的分词只是做相似度计算而已
如果需要使用自定义词典,那么可以在分词之前使用
jieba.load_userdict(ditname) 加入自定义词典
如果要屏蔽掉烦人的, 结巴的初始化输出显示:
Building prefix dict from the default dictionary ...
Loading model from cache /var/folders/h9/5172d1757k90s7p3ngzzgllm0000gn/T/jieba.cache
Loading model cost 0.410 seconds.
Prefix dict has been built succesfully.
这些东西, 那么可以打开jieba的__init__.py 文件删除掉对应的信息或者将输出写入文件等(自行处理)
算法参考文档: http://baike.baidu.com/item/%E4%BD%99%E5%BC%A6%E7%9B%B8%E4%BC%BC%E5%BA%A6
作者: brooks
MQQ: 76231607
"""
import jieba
from jieba import posseg
import math
import time

jieba.initialize()


def simicos(str1, str2):
    # 对两个要计算的字符串进行分词, 使用隐马尔科夫模型(也可不用)
    # 由于不同的分词算法, 所以分出来的结果可能不一样
    # 也会导致相似度会有所误差, 但是一般影响不大
    cut_str1 = [w for w, t in posseg.lcut(str1) if 'n' in t or 'v' in t]
    cut_str2 = [w for w, t in posseg.lcut(str2) if 'n' in t or 'v' in t]
    # 列出所有词
    all_words = set(cut_str1 + cut_str2)
    # 计算词频
    freq_str1 = [cut_str1.count(x) for x in all_words]
    freq_str2 = [cut_str2.count(x) for x in all_words]
    # 计算相似度
    sum_all = sum(map(lambda z, y: z * y, freq_str1, freq_str2))
    sqrt_str1 = math.sqrt(sum(x ** 2 for x in freq_str1))
    sqrt_str2 = math.sqrt(sum(x ** 2 for x in freq_str2))
    try:
        return sum_all / (sqrt_str1 * sqrt_str2)
    except ZeroDivisionError:
        return 0.0


if __name__ == '__main__':
    case1 = "水仙不开花的歇后语是什么"
    case2 = "水仙不开花用歇后语怎么说"
    start = time.time()
    similarity = simicos(case1, case2)
    end = time.time()

    print("耗时: %.3fs" % (end - start))
    print("相似度: %.1f%%" % (similarity * 100))


3.基于集合交集算法计算

  • 集合交集算法是一个简单的逻辑:
    1. 先分别对两个字符串进行分词
    2. 进行求交集
    3. 计算交集的部分与原来关键词的占比,这个占比就是相似度

3.1 实际应用

# -*- coding: utf-8 -*-
"""
基于集合的方式来计算相似度
作者:brooks
"""
import time
from jieba.analyse import tfidf
import jieba

jieba.initialize()

def setsimilarity(str1, str2):
    # 1. 先分别对两个字符串进行分词
    str1_cut = jieba.lcut(str1)
    str2_cut = jieba.lcut(str2)
    # 2. 进行求交集
    set_str1 = set(str1_cut)
    set_str2 = set(str2_cut)
    union_words = set_str1 & set_str2
    # 3. 计算交集的部分与原来关键词的占比,这个占比就是相似度
    return len(union_words) / len(set_str1)


if __name__ == '__main__':
    case1 = "无货源电商怎么做,靠谱吗"
    case2 = "购买淘宝店铺靠不靠谱"

    start = time.time()
    similarity = setsimilarity(case1, case2)
    end = time.time()
    print(tfidf(case1))
    print(tfidf(case2))
    print("耗时: %.3fs" % (end - start))
    print("相似度: %.1f%%" % (similarity * 100))

总结:
三个算法各有优劣,推荐使用:余弦算法、集合相似度算法,编辑距离效果略差,主要是关键词长短不一,顺序改变的话,编辑距离的结果差别就会很大。

标签: python笔记
分享给朋友:

相关文章

python使用mongodb数据库

from pymongo import MongoClient,collection class KSpdier(Thread):   ...

python xpath语法总结

python xpath语法总结:常用的://1.从任意节点开始/2.从根节点开始//div/p3.div下的p标签//div[@class="hrzz_bottom"]/ul/l...

python 随机生成时间戳写入txt文件/运行sql语句

import time from random import randint with open('time.txt', ...

python fake_useragent 模块用法

我们每次发送requests请求时通过random从中随机获取一个随机UserAgent,两行代码即可完成UserAgent的不停更换 from fake_useragent i...

python列表排序(以字符串长度)

M = ['a', 'sss', 'bb'] 第一种: m = M.sort(key&n...

python 获取当前的路径并切换

import os curdir = os.path.dirname(__file__) #获取当前的路径,若运行在当前文件夹,是获取不到当前路径的,最保险的...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。