工作中经常遇到文本处理上的两个问题,一个是如何在长的文本串中找到跟短文本串最像的子串;另一个是如何将两个文本串进行对齐,忽略掉其中不同的部分。准备专门写一个工具来解决这些问题,因此先调研了模糊匹配和字符串对齐的工具。
参考:
https://zhuanlan.zhihu.com/p/53135935
https://www.thinbug.com/q/17740833
https://github.com/eseraygun/python-alignment
https://pypi.org/project/StringDist/
https://pypi.org/project/edlib/
https://pypi.org/project/strsimpy/
https://github.com/gfairchild/pyxDamerauLevenshtein
https://github.com/mbreese/swalign/
打印表格:https://pypi.org/project/tabulate/
https://pypi.org/project/weighted-levenshtein/
https://pypi.org/project/nwalign/
https://pypi.org/project/pyhacrf-datamade/
打印表格:https://pypi.org/project/Frmt/
difflib
参考:
https://blog.csdn.net/Lockey23/article/details/77913855
https://blog.csdn.net/gavin_john/article/details/78951698
https://docs.python.org/3.5/library/difflib.html
difflib模块提供的类和方法用来进行序列的差异化比较,它能够比对文件并生成差异结果文本或者html格式的差异化比较页面。
SequenceMatcher
SequenceMatcher类可以用来比较两个任意类型的数据,只要是可以哈希的。它使用一个算法来计算序列的最长连续子序列,并且忽略没有意义的“无用数据”。下面代码计算了模糊匹配的相似度:
1 | >>> import difflib |
其基本算法比Ratcliff和Obershelp在20世纪80年代末发表的“格式塔模式匹配”(gestalt pattern matching)算法更早,也更新奇。其思想是寻找不包含“垃圾”元素的最长连续匹配子序列;这些“垃圾”元素在某种意义上是无趣的,比如空白行或空白(垃圾信息处理是Ratcliff和Obershelp算法的扩展)。然后,将相同的思想递归地应用到匹配子序列的左子序列和右子序列。这不会产生最小的编辑序列,但是会产生人们“看起来正确”的匹配。
在时间复杂度上,基本的Ratcliff-Obershelp算法在最坏情况下是三次时间,在期望情况下是二次时间。SequenceMatcher是最坏情况下的二次时间,它的期望情况行为以一种复杂的方式依赖于序列有多少个公共元素;最好的情况是时间是线性的。
SequenceMatcher支持一种自动将某些序列项视为垃圾的启发式方法。启发式计算每个单独的项目在序列中出现的次数。如果一个项目的重复项(在第一个之后)占序列的1%以上,并且序列至少有200个项目长,则该项目将被标记为“popular”,并被视为垃圾,以便进行序列匹配。在创建SequenceMatcher时,可以通过将autojunk参数设置为False来关闭这种启发式。下面代码可以得到编辑距离的所有操作:
1 | import difflib |
输出结果:
1 | Replace [4] from s1[5:6] with [1] from s2[5:6] |
get_matching_blocks
返回匹配子序列的三元组列表。每个三元组的形式是(i, j, n),表示a[i:i+n] == b[j:j+n]。在i和j中,三元组是单调递增的。最后一个三元组是一个哑元,它的值是(len(a), len(b), 0),它是唯一一个n == 0的三元组。
1 | >>> s = SequenceMatcher(None, "abxcd", "abcd") |
如果想获得所有match的子串,可以这样写:
1 | import difflib |
结果:
1 | >>> print(list(matches(large_string, query_string, 0.8))) |
fuzzywuzzy
参考:
https://github.com/seatgeek/fuzzywuzzy
https://zhuanlan.zhihu.com/p/77166627
https://blog.csdn.net/laobai1015/article/details/80451371
https://stackoverflow.com/questions/48671270/use-sklearn-tfidfvectorizer-with-already-tokenized-inputs
https://github.com/ing-bank/sparse_dot_topn
FuzzyWuzzy 是一个简单易用的模糊字符串匹配工具包。它依据 Levenshtein Distance 算法 计算两个序列之间的差异。
1 | from fuzzywuzzy import fuzz |
上面方法可以用于在候选answers中找到最接近query的answer,但在面临大数据时,会遇到速度慢的问题。我们可以通过先确定一个候选answers的子集,再进行fuzzywuzzy的方式缩短运行时间。
首先,我们先将候选answers转换成tf-idf向量:
1 | from sklearn.feature_extraction.text import TfidfVectorizer |
其次使用sparse_dot_topn找到相似的字符串:
1 | import numpy as np |
alignment
alignment主要用于字符串之间对齐,其使用方法如下:
1 | from alignment.sequence import Sequence |
strsimpy
这是一个用于计算各种字符串距离的包。其使用方法如下:
1 | from strsimpy.levenshtein import Levenshtein |