用FuzzyWuzzy匹配模糊字符串

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

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

一、安装

1
2
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple FuzzyWuzzy
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple python-Levenshtein

二、fuzz模块

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

1、简单匹配(Ratio)

这个不怎么精确,也不常用。

1
2
3
4
5
6
from fuzzywuzzy import fuzz

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

2、非完全匹配(Partial Ratio)

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

1
2
3
4
5
6
from fuzzywuzzy import fuzz

print(fuzz.partial_ratio("河南省", "河南省"))
# 100
print(fuzz.partial_ratio("河南", "河南省"))
# 100

3、忽略顺序匹配(Token Sort Ratio)

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

1
2
3
4
5
6
7
8
9
10
11
from fuzzywuzzy import fuzz

print(fuzz.partial_ratio("西藏 自治区", "自治区 西藏"))
# 50
print(fuzz.partial_ratio("I love YOU", "YOU LOVE I"))
# 30

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

4、去重子集匹配(Token Set Ratio)

可理解为该方法是在token_sort_ratio方法的基础上添加了集合去重的功能。

1
2
3
4
5
6
from fuzzywuzzy import fuzz

print(fuzz.token_sort_ratio("西藏 西藏 自治区", "自治区 西藏"))
# 80
print(fuzz.token_set_ratio("西藏 西藏 自治区", "自治区 西藏"))
# 100

三、process模块

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

1、extract提取多条数据

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

1
2
3
4
from fuzzywuzzy import process

choices = ["河南省", "郑州市", "湖北省", "武汉市"]
print(process.extract("郑州", choices, limit=2))

2、extractOne提取一条数据

如果要提取匹配度最大的结果,可以使用extractOne,注意这里返回的是元组类型,还有就是匹配度最大的结果不一定是我们想要的数据。

1
2
3
4
5
from fuzzywuzzy import process

choices = ["河南省", "郑州市", "湖北省", "武汉市"]
print(process.extractOne("郑州", choices))
print(process.extractOne("北京", choices))

四、示例

公司名称匹配,设置相似度阈值为90。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def fuzzy_merge(df_1, df_2, key1, key2, threshold=90, limit=2):
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)
0%