SequenceMatcher-查找两个或多个数据列表中两个最相似的元素

时间:2019-01-03 17:51:53

标签: python python-3.x algorithm difflib sequencematcher

我正在尝试将一组字符串与一组已定义的字符串进行比较。 例如,您要查找信件的收件人,该信件的文本通过OCR进行数字化。

有一系列地址,其中有字典作为元素。 每个元素都是唯一的,包含ID,名称,街道,邮政编码和城市。此列表的长度为1000个条目。

由于OCR扫描的文本可能不准确,因此我们需要在包含地址的列表中找到最匹配的字符串候选。

文本长750个字。我们使用适当的过滤功能来减少单词的数量,该功能首先按空格分隔,从每个元素中剥离更多的空格,删除所有少于5个字符的单词,并删除重复项;结果列表长200个字。

由于每个收件人都有4个字符串(名称街道,邮政编码和城市),其余字母长度为200个字,因此我的同志必须运行4 * 1000 * 200  = 80万次。

我使用python取得了中等成功。已正确找到匹配项。但是,该算法需要很长时间才能处理大量字母(每1500个字母最多需要50个小时)。列表理解已被应用。有没有办法正确(而不是不必要的)实现多线程?如果此应用程序需要在低规格服务器上运行怎么办?我的6核心CPU并没有抱怨这些任务,但是,我不知道在一个小型AWS实例上处理大量文档将花费多少时间。

>> len(addressees)
1000
>> addressees[0]
{"Name": "John Doe", "Zip": 12345, "Street": "Boulevard of broken dreams 2", "City": "Stockholm"}
>> letter[:5] # already filtered
["Insurance", "Taxation", "Identification", "1592212", "St0ckhlm", "Mozart"]
>> from difflib import SequenceMatcher
>> def get_similarity_per_element(addressees, letter):
    """compare the similarity of each word in the letter with the addressees"""
    ratios = []
    for l in letter:
        for a in addressee.items():
            ratios.append(int(100 * SequenceMatcher(None, a, l).ratio())) # using ints for faster arithmatic
    return max(ratios)
>> get_similarity_per_element(addressees[0], letter[:5]) # percentage of the most matching word in the letter with anything from the addressee
82
>> # then use this method to find all addressents with the max matching ratio
>> # if only one is greater then the others -> Done
>> # if more then one, but less then 3 are equal -> Interactive Promt -> Done
>> # else -> mark as not sortable -> Done.

我希望每个文档的处理速度更快。 (最多1分钟),而不是每1500个字母50小时。我确信这是瓶颈,因为其他任务正在快速且完美地工作。

是否有更好(更快)的方法?

2 个答案:

答案 0 :(得分:1)

您想识别类似于字典单词的输入,例如“ St0ckholm”->“斯德哥尔摩”。应处理换位错字。好吧。

可能您希望设置autojunk=False。但是如果您急着想,二次或三次算法听起来很麻烦。

考虑Anagram问题,询问您输入词和词典词是否是彼此的字词。直接的解决方案是比较排序后的字符串是否相等。让我们看看是否可以将这个想法改编成适合您问题的数据结构。

将字典中的单词预处理为易于查找的规范键,然后在每个键上悬挂一个或多个单词的列表。使用排序形成关键字。例如,我们将有:

    'dgo' -> ['dog', 'god']

存储按键排序的地图。

给出输入的单词,您想知道该单词是否确切出现在词典中,或者编辑距离有限的版本是否出现在词典中。对输入的单词进行排序,并在地图上查找大于或等于该单词的第一个条目。检索(非常短的)候选词列表,并评估每个候选词与输入词之间的距离。输出最佳匹配。这很快发生。

对于模糊匹配,请同时使用第1个条目和第2个条目>=目标,再加上前面的条目,因此候选集更大。而且,到目前为止,由于升序排序,该方法对于删除“ a”或“ b”之类的“小”字母很敏感。因此,请另外使用降序排列的键,并针对这两种类型的键探查地图。

如果您愿意使用pip安装软件包,请考虑使用import soundex(故意从单词中丢弃信息)或import fuzzywuzzy

答案 1 :(得分:1)

一些快速提示:

1)让我知道执行quick_ratio()或real_quick_ratio()而不是ratio()需要多长时间

2)反转循环顺序,并使用set_seq2和set_seq1,以便SequenceMatcher重用信息

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        WebView webView = (WebView) findViewById(R.id.webview);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.getSettings().setLoadWithOverviewMode(true);
        webView.getSettings().setUseWideViewPort(true);


        webView.loadUrl("https://socindonesia.com");


    }
}

但是更好的解决方案是类似@J_H描述