[python] 基于RapidFuzz库实现字符串模糊匹配

RapidFuzz是一个用于快速字符串模糊匹配的Python库,它能够快速计算两个字符串之间的相似度,并提供与Fuzzywuzzy(已停用)TheFuzz(Fuzzywuzzy的升级版)类似的接口。RapidFuzz和TheFuzz功能相似,只是提供的接口不同。RapidFuzz和TheFuzz安装指令如下:

pip install rapidfuzz
pip install thefuzz

RapidFuzz库是一个经过高度优化的C++实现,为用户提供了以Python编写代码的速度和灵活性。该库还提供了一个与TheFuzz和Fuzzywuzzy中所有算法兼容的API,因此强烈推荐使用RapidFuzz库进行文本模糊匹配。

# 查看rapidfuzz版本
import rapidfuzz
rapidfuzz.__version__
'3.4.0'
# 查看thefuzz版本
import thefuzz
thefuzz.__version__
'0.20.0'

1 基础使用

在RapidFuzz3版本中,默认情况下不会对字符串进行预处理(删除所有非字母数字字符、修剪空白、将所有字符转换为小写)。这意味着,当比较具有相同字符但英文大小写不同的两个字符串时,它们的相似性分值可能不同。

1.1 字符串相似度对比

RapidFuzz提供了多种方法来比较字符串之间的相似度,包括ratiopartial_ratiopartial_ratio_alignmenttoken_set_ratiopartial_token_set_ratiotoken_sort_ratiopartial_token_sort_ratiotoken_ratiopartial_token_ratioWRatioQRatio

下面是对这些方法进行简要对比的说明:

  • ratio:计算两个字符串之间的相似度得分,返回一个介于0和100之间的浮点数。这个方法使用了Levenshtein距离来测量字符串之间的编辑距离。
  • partial_ratio:与ratio类似,但它只考虑其中一个字符串是否是另一个字符串的子集。
  • partial_ratio_alignment:计算两个字符串之间的相似度得分,并返回对齐后的字符串。该方法使用了Levenshtein距离和动态规划算法来对齐字符串。
  • token_set_ratio:将两个字符串拆分为单词或标记,并计算它们之间的相似度得分。它使用了集合操作和ratio方法来计算相似度。
  • partial_token_set_ratio:与token_set_ratio类似,但它只考虑其中一个字符串是否是另一个字符串的子集。
  • token_sort_ratio:将两个字符串拆分为单词或标记,并按字母顺序对它们进行排序,然后计算它们之间的相似度得分。它使用了排序和ratio方法来计算相似度。
  • partial_token_sort_ratio:与token_sort_ratio类似,但它只考虑其中一个字符串是否是另一个字符串的子集。
  • token_ratio:将两个字符串拆分为单词或标记,并计算它们之间的相似度得分。它使用了ratio方法来计算相似度。
  • partial_token_ratio:与token_ratio类似,但它只考虑其中一个字符串是否是另一个字符串的子集。
  • WRatio:使用了不同的权重来计算字符串之间的相似度得分。
  • QRatio:一个更快但不太准确的版本的ratio方法。

这些方法提供了不同的计算方式和适用场景,具体使用哪种方法取决于需求和数据特点,一般从ratio、partial_ratio、token_set_ratio、token_sort_ratio和token_ratio之间选择。TheFuzz模块也提供类似的接口。

# 导入模块
from rapidfuzz import fuzz
# ratio
fuzz.ratio("Hello hello 世界", "hello 世界!")
69.56521739130434
# partial_ratio
fuzz.partial_ratio("Hello hello 世界", "hello 世界!")
94.11764705882352
# partial_ratio_alignment
fuzz.partial_ratio_alignment("Hello hello 世界", "hello 世界!")
ScoreAlignment(score=94.11764705882352, src_start=6, src_end=14, dest_start=0, dest_end=9)
# token_set_ratio
fuzz.token_set_ratio("Hello hello 世界", "hello 世界!")
71.42857142857143
# partial_token_set_ratio
fuzz.partial_token_set_ratio("Hello hello 世界", "hello 世界!")
100.0
# token_sort_ratio
fuzz.token_sort_ratio("Hello hello 世界", "hello 世界!")
69.56521739130434
# partial_token_sort_ratio
fuzz.partial_token_sort_ratio("Hello hello 世界", "hello 世界!")
94.11764705882352
# token_ratio
fuzz.token_ratio("Hello hello 世界", "hello 世界!")
71.42857142857143
# partial_token_ratio
fuzz.partial_token_ratio("Hello hello 世界", "hello 世界!")
100.0
# WRatio
fuzz.WRatio("Hello hello 世界", "hello 世界!")
85.5
# QRatio
fuzz.QRatio("Hello hello 世界", "hello 世界!")
69.56521739130434

1.2 字符串搜索

RapidFuzz的extract模块提供了一种基于模糊匹配的字符串集合匹配方法,可以根据目标字符串以及一个或多个字符串集合,并返回与查询字符串匹配度高的多个候选字符串。extractOne模块也是基于模糊匹配的字符串匹配方法,但它只返回与目标字符串最相似的字符串,而不是一组匹配结果。TheFuzz模块也提供类似的接口。

from rapidfuzz import process

query = "世界 Hello"
choices = ["你好世界", "hello 世界", "世界你好", "你好Hello", "Hello", "你好"]
result = process.extract(query, choices)
# 默认返回前五相似结果
print(result)
[('Hello', 90.0, 4), ('hello 世界', 83.125, 1), ('你好Hello', 66.66666666666667, 3), ('你好世界', 60.00000000000001, 0), ('世界你好', 60.00000000000001, 2)]
from rapidfuzz import process

query = "世界 Hello"
choices = ["你好世界", "hello 世界", "世界你好", "你好Hello", "Hello", "你好"]
# 默认返回前三相似结果
result = process.extract(query, choices, limit=3)
print(result)
[('Hello', 90.0, 4), ('hello 世界', 83.125, 1), ('你好Hello', 66.66666666666667, 3)]
# 以下方法返回最匹配的结果
result = process.extractOne(query, choices)
# 类似于
# result = process.extract(query, choices, limit=3)
print(result)
('Hello', 90.0, 4)
# 指定匹配算法
result = process.extract(query, choices, scorer=fuzz.partial_token_ratio)
print(result)
[('hello 世界', 100.0, 1), ('Hello', 100.0, 4), ('你好Hello', 83.33333333333334, 3), ('你好世界', 66.66666666666667, 0), ('世界你好', 66.66666666666667, 2)]

1.3 距离计算

除了相似字符串查找,RapidFuzz也提供了几种字符串相似性度量的方法。下面是对其中几个主要函数的使用说明:

distance(s1, s2)

这个函数计算两个字符串s1和s2之间的Levenshtein距离(编辑距离)。编辑距离使用说明见: Levenshtein Distance算法与使用场景。简单来说Damerau-Levenshtein距离是一种编辑距离度量方法,用于计算将一个字符串转换为另一个字符串所需的最小编辑操作次数。这些编辑操作包括插入、删除、替换和相邻字符交换。Damerau-Levenshtein距离越小,表示两个字符串越相似或接近。

from rapidfuzz import distance

s1 = "你好 世界"
s2 = "你好 world!"

dist = distance.DamerauLevenshtein.distance(s1, s2)
print(dist)  # 输出结果为7
6

normalized_distance(s1, s2)

计算范围为[1,0]的归一化Damerau-Levenstein距离。

from rapidfuzz import distance

s1 = "你好 世界"
s2 = "你好 world!"

dist = distance.DamerauLevenshtein.normalized_distance(s1, s2)
print(dist)
0.6666666666666666

similarity(s1, s2)

计算范围为[max,0]的Damerau-Levenstein相似度。这被计算为max(len1,len2)-distance。

from rapidfuzz import distance

s1 = "你好 世界"
s2 = "你好 world!"

sim = distance.DamerauLevenshtein.similarity(s1, s2)
print(sim)
3

normalized_similarity(s1, s2)

计算在[0,1]范围内的归一化Damerau-Levenstein相似性。

from rapidfuzz import distance

s1 = "你好 世界"
s2 = "你好 world!"

sim = distance.DamerauLevenshtein.normalized_similarity(s1, s2)
print(sim)
0.33333333333333337

2 参考

posted @ 2024-01-25 11:41  落痕的寒假  阅读(1141)  评论(0编辑  收藏  举报