Python FuzzyWuzzy实现模糊匹配


Posted in Python onApril 28, 2022

在日常开发工作中,经常会遇到这样的一个问题:要对数据中的某个字段进行匹配,但这个字段有可能会有微小的差异。比如同样是招聘岗位的数据,里面省份一栏有的写“广西”,有的写“广西壮族自治区”,甚至还有写“广西省”……为此不得不增加许多代码来处理这些情况。

今天跟大家分享FuzzyWuzzy一个简单易用的模糊字符串匹配工具包。让你轻松解决烦恼的匹配问题!

1. 前言

在处理数据的过程中,难免会遇到下面类似的场景,自己手里头获得的是简化版的数据字段,但是要比对的或者要合并的却是完整版的数据(有时候也会反过来)

最常见的一个例子就是:在进行地理可视化中,自己收集的数据只保留的缩写,比如北京,广西,新疆,西藏等,但是待匹配的字段数据却是北京市,广西壮族自治区,新疆维吾尔自治区,西藏自治区等,如下。因此就需要有没有一种方式可以很快速便捷的直接进行对应字段的匹配并将结果单独生成一列,就可以用到FuzzyWuzzy库。

Python FuzzyWuzzy实现模糊匹配

2. FuzzyWuzzy库介绍

FuzzyWuzzy 是一个简单易用的模糊字符串匹配工具包。它依据 Levenshtein Distance 算法,计算两个序列之间的差异。

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

这里使用的是Anaconda下的jupyter notebook编程环境,因此在Anaconda的命令行中输入一下指令进行第三方库安装。

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple FuzzyWuzzy

2.1 fuzz模块

该模块下主要介绍四个函数(方法),分别为:简单匹配(Ratio)、非完全匹配(Partial Ratio)、忽略顺序匹配(Token Sort Ratio)和去重子集匹配(Token Set Ratio)

注意: 如果直接导入这个模块的话,系统会提示warning,当然这不代表报错,程序依旧可以运行(使用的默认算法,执行速度较慢),可以按照系统的提示安装python-Levenshtein库进行辅助,这有利于提高计算的速度。

Python FuzzyWuzzy实现模糊匹配

2.1.1 简单匹配(Ratio)

简单的了解一下就行,这个不怎么精确,也不常用

fuzz.ratio("河南省", "河南省")
>>> 100
>
fuzz.ratio("河南", "河南省")
>>> 80

2.1.2 非完全匹配(Partial Ratio)

尽量使用非完全匹配,精度较高

fuzz.partial_ratio("河南省", "河南省")
>>> 100

fuzz.partial_ratio("河南", "河南省")
>>> 100

2.1.3 忽略顺序匹配(Token Sort Ratio)

原理在于:以 空格 为分隔符,小写 化所有字母,无视空格外的其它标点符号

fuzz.ratio("西藏 自治区", "自治区 西藏")
>>> 50
fuzz.ratio('I love YOU','YOU LOVE I')
>>> 30

fuzz.token_sort_ratio("西藏 自治区", "自治区 西藏") 
>>> 100
fuzz.token_sort_ratio('I love YOU','YOU LOVE I') 
>>> 100

2.1.4 去重子集匹配(Token Set Ratio)

相当于比对之前有一个集合去重的过程,注意最后两个,可理解为该方法是在token_sort_ratio方法的基础上添加了集合去重的功能,下面三个匹配的都是倒序

fuzz.ratio("西藏 西藏 自治区", "自治区 西藏")
>>> 40

fuzz.token_sort_ratio("西藏 西藏 自治区", "自治区 西藏")
>>> 80

fuzz.token_set_ratio("西藏 西藏 自治区", "自治区 西藏")
>>> 100

fuzz这几个ratio()函数(方法)最后得到的结果都是数字,如果需要获得匹配度最高的字符串结果,还需要依旧自己的数据类型选择不同的函数,然后再进行结果提取,如果但看文本数据的匹配程度使用这种方式是可以量化的,但是对于我们要提取匹配的结果来说就不是很方便了,因此就有了process模块。

2.2 process模块

用于处理备选答案有限的情况,返回模糊匹配的字符串和相似度。

2.2.1 extract提取多条数据

类似于爬虫中select,返回的是列表,其中会包含很多匹配的数据

choices = ["河南省", "郑州市", "湖北省", "武汉市"]
process.extract("郑州", choices, limit=2)
>>> [('郑州市', 90), ('河南省', 0)]
# extract之后的数据类型是列表,即使limit=1,最后还是列表,注意和下面extractOne的区别

2.2.2 extractOne提取一条数据

如果要提取匹配度最大的结果,可以使用extractOne,注意这里返回的是 元组 类型, 还有就是匹配度最大的结果不一定是我们想要的数据,可以通过下面的示例和两个实战应用体会一下

process.extractOne("郑州", choices)
>>> ('郑州市', 90)

process.extractOne("北京", choices)
>>> ('湖北省', 45)

3. 实战应用

这里举两个实战应用的小例子,第一个是公司名称字段的模糊匹配,第二个是省市字段的模糊匹配

3.1 公司名称字段模糊匹配

数据及待匹配的数据样式如下:自己获取到的数据字段的名称很简洁,并不是公司的全称,因此需要进行两个字段的合并

Python FuzzyWuzzy实现模糊匹配

直接将代码封装为函数,主要是为了方便日后的调用,这里参数设置的比较详细,执行结果如下:

Python FuzzyWuzzy实现模糊匹配

3.1.1 参数讲解:

① 第一个参数df_1是自己获取的欲合并的左侧数据(这里是data变量);

② 第二个参数df_2是待匹配的欲合并的右侧数据(这里是company变量);

③ 第三个参数key1是df_1中要处理的字段名称(这里是data变量里的‘公司名称’字段)

④ 第四个参数key2是df_2中要匹配的字段名称(这里是company变量里的‘公司名称’字段)

⑤ 第五个参数threshold是设定提取结果匹配度的标准。注意这里就是对extractOne方法的完善,提取到的最大匹配度的结果并不一定是我们需要的,所以需要设定一个阈值来评判,这个值就为90,只有是大于等于90,这个匹配结果我们才可以接受

⑥ 第六个参数,默认参数就是只返回两个匹配成功的结果

⑦ 返回值:为df_1添加‘matches’字段后的新的DataFrame数据

3.1.2 核心代码讲解

第一部分代码如下,可以参考上面讲解process.extract方法,这里就是直接使用,所以返回的结果m就是列表中嵌套元祖的数据格式,样式为: [(‘郑州市’, 90), (‘河南省’, 0)],因此第一次写入到’matches’字段中的数据也就是这种格式

注意,注意: 元祖中的第一个是匹配成功的字符串,第二个就是设置的threshold参数比对的数字对象

s = df_2[key2].tolist()
m = df_1[key1].apply(lambda x: process.extract(x, s, limit=limit))    
df_1['matches'] = m

第二部分的核心代码如下,有了上面的梳理,明确了‘matches’字段中的数据类型,然后就是进行数据的提取了,需要处理的部分有两点需要注意的:

① 提取匹配成功的字符串,并对阈值小于90的数据填充空值

② 最后把数据添加到‘matches’字段

m2 = df_1['matches'].apply(lambda x: [i[0] for i in x if i[1] >= threshold][0] if len([i[0] for i in x if i[1] >= threshold]) > 0 else '')
#要理解第一个‘matches'字段返回的数据类型是什么样子的,就不难理解这行代码了
#参考一下这个格式:[('郑州市', 90), ('河南省', 0)]
df_1['matches'] = m2

return df_1

3.2 省份字段模糊匹配

自己的数据和待匹配的数据背景介绍中已经有图片显示了,上面也已经封装了模糊匹配的函数,这里直接调用上面的函数,输入相应的参数即可,代码以及执行结果如下:

Python FuzzyWuzzy实现模糊匹配

数据处理完成,经过封装后的函数可以直接放在自己自定义的模块名文件下面,以后可以方便直接导入函数名即可,可以参考将自定义常用的一些函数封装成可以直接调用的模块方法。

4. 全部函数代码

#模糊匹配

def fuzzy_merge(df_1, df_2, key1, key2, threshold=90, limit=2):
    """
    :param df_1: the left table to join
    :param df_2: the right table to join
    :param key1: key column of the left table
    :param key2: key column of the right table
    :param threshold: how close the matches should be to return a match, based on Levenshtein distance
    :param limit: the amount of matches that will get returned, these are sorted high to low
    :return: dataframe with boths keys and matches
    """
    s = df_2[key2].tolist()

    m = df_1[key1].apply(lambda x: process.extract(x, s, limit=limit))    
    df_1['matches'] = m

    m2 = df_1['matches'].apply(lambda x: [i[0] for i in x if i[1] >= threshold][0] if len([i[0] for i in x if i[1] >= threshold]) > 0 else '')
    df_1['matches'] = m2

    return df_1

from fuzzywuzzy import fuzz
from fuzzywuzzy import process

df = fuzzy_merge(data, company, '公司名称', '公司名称', threshold=90)
df

以上就是Python+FuzzyWuzzy实现模糊匹配的示例详解的详细内容!


Tags in this post...

Python 相关文章推荐
python使用reportlab实现图片转换成pdf的方法
May 22 Python
Python使用面向对象方式创建线程实现12306售票系统
Dec 24 Python
python实现按行切分文本文件的方法
Apr 18 Python
详解Python命令行解析工具Argparse
Apr 20 Python
Python正则简单实例分析
Mar 21 Python
Python基于matplotlib实现绘制三维图形功能示例
Jan 18 Python
python版opencv摄像头人脸实时检测方法
Aug 03 Python
浅谈python多进程共享变量Value的使用tips
Jul 16 Python
解决Django中修改js css文件但浏览器无法及时与之改变的问题
Aug 31 Python
Python yield生成器和return对比代码实例
Apr 20 Python
解决django 向mysql中写入中文字符出错的问题
May 18 Python
python神经网络学习 使用Keras进行回归运算
May 04 Python
PYTHON基于Pyecharts绘制常见的直角坐标系图表
PYTHON 使用 Pandas 删除某列指定值所在的行
Apr 28 #Python
详解PyTorch模型保存与加载
Apr 28 #Python
Python 图片添加美颜效果
Python 视频画质增强
python 单机五子棋对战游戏
python井字棋游戏实现人机对战
Apr 28 #Python
You might like
CodeIgniter框架提示Disallowed Key Characters的解决办法
2014/04/21 PHP
PHP面试常用算法(推荐)
2016/07/22 PHP
PHP正则判断一个变量是否为正整数的方法
2019/02/27 PHP
Laravel Eloquent分表方法并使用模型关联的实现
2019/11/25 PHP
Html中JS脚本执行顺序简单举例说明
2010/06/19 Javascript
如何确保JavaScript的执行顺序 之jQuery.html深度分析
2011/03/03 Javascript
使用jquery的ajax需要注意的地方dataType的设置
2013/08/12 Javascript
js形成页面的一种遮罩效果实例代码
2014/01/04 Javascript
JQuery记住用户名和密码的具体实现
2014/04/04 Javascript
使用upstart把nodejs应用封装为系统服务实例
2014/06/01 NodeJs
Jquery实现由下向上展开效果的例子
2014/12/08 Javascript
JavaScript匿名函数用法分析
2015/02/13 Javascript
JavaScript动态修改网页元素内容的方法
2015/03/21 Javascript
Bootstrap table分页问题汇总
2016/05/30 Javascript
jquery判断对象是否为空并遍历对象的简单实例
2016/07/26 Javascript
js中的事件委托或是事件代理使用详解
2017/06/23 Javascript
vue中使用sessionStorage记住密码功能
2018/07/24 Javascript
ES6 Class中实现私有属性的一些方法总结
2019/07/08 Javascript
如何给element添加一个抽屉组件的方法步骤
2019/07/14 Javascript
python实现将汉字转换成汉语拼音的库
2015/05/05 Python
python遍历文件夹下所有excel文件
2018/01/03 Python
scrapy spider的几种爬取方式实例代码
2018/01/25 Python
Python获取指定字符前面的所有字符方法
2018/05/02 Python
在Pycharm中使用GitHub的方法步骤
2019/06/13 Python
Python读取ini配置文件传参的简单示例
2021/01/05 Python
Python的Tqdm模块实现进度条配置
2021/02/24 Python
pyx文件 生成pyd 文件用于 cython调用的实现
2021/03/04 Python
水果花束:Fruit Bouquets
2017/12/20 全球购物
仓库班组长岗位职责
2013/12/12 职场文书
面试必备的求职信
2014/05/25 职场文书
教师节倡议书
2014/08/30 职场文书
机关干部作风建设剖析材料
2014/10/23 职场文书
2014年测量员工作总结
2014/12/12 职场文书
2015年七夕情人节活动方案
2015/05/06 职场文书
三严三实·严以修身心得体会
2016/01/15 职场文书
MSSQL基本语法操作
2022/04/11 SQL Server