【问题标题】:efficient algorithm for finding co occurrence matrix of phrases寻找短语共现矩阵的有效算法
【发布时间】:2013-04-13 16:24:35
【问题描述】:

我有一个包含大约 40,000 个短语的列表 L 和一个大约 1000 万字的文档。我要检查的是这对短语中的哪对共同出现在 4 个单词的窗口中。例如,考虑 L=["brown fox","lazy dog"]。该文件包含“一只敏捷的棕色狐狸跳过懒狗”的文字。我想看看,棕色狐狸和懒狗在四个单词的窗口中出现了多少次,并将其存储在一个文件中。我有以下代码:

content=open("d.txt","r").read().replace("\n"," ");
for i in range(len(L)):
 for j in range(i+1,len(L)):
  wr=L[i]+"\W+(?:\w+\W+){1,4}"+L[j]
  wrev=L[j]+"\W+(?:\w+\W+){1,4}"+L[i]
  phrasecoccur=len(re.findall(wr, content))+len(re.findall(wrev,content))
  if (phrasecoccur>0):
    f.write(L[i]+", "+L[j]+", "+str(phrasecoccur)+"\n")

基本上,对于列表 L 中的每一对短语,我在文档内容中检查这些短语在 4 个单词的窗口内出现了多少次。但是,当列表 L 非常大(例如 40K 个元素)时,这种方法的计算效率很低。有没有更好的方法来做到这一点?

【问题讨论】:

  • 重写你的算法以在单词上实现滑动窗口迭代器,并尝试使用dicts 或sets 而不是列表,因为查找时间更短。

标签: python regex algorithm


【解决方案1】:

您可以使用类似于Aho-Corasick string matching algorithm 的内容。从您的短语列表中构建状态机。然后开始将单词输入状态机。每当发生匹配时,状态机都会告诉您匹配的短语和单词编号。所以你的输出会是这样的:

"brown fox", 3
"lazy dog", 8
etc.

您可以捕获所有输出并对其进行后处理,也可以在找到匹配项时对其进行处理。

构建状态机需要一点时间(40,000 个短语需要几秒钟),但之后输入标记的数量、短语的数量和匹配的数量是线性的。

我使用类似的方法将 5000 万个 YouTube 视频标题与 MusicBrainz 数据库中的数百万首歌曲标题和艺术家姓名进行匹配。工作得很好。而且速度非常快。

【讨论】:

    【解决方案2】:

    应该可以将您的 40000 个短语组合成一个大的正则表达式模式,并使用它来匹配您的文档。它可能没有更具体的工作那么快,但它确实有效。这是我的做法:

    import re
    
    class Matcher(object):
        def __init__(self, phrases):
            phrase_pattern = "|".join("(?:{})".format(phrase) for phrase in phrases)
            gap_pattern = r"\W+(?:\w+\W+){0,4}?"
            full_pattern = "({0}){1}({0})".format(phrase_pattern, gap_pattern)
    
            self.regex = re.compile(full_pattern)
    
        def match(self, doc):
            return self.regex.findall(doc) # or use finditer to generate match objs
    

    你可以这样使用它:

    >>> L = ["brown fox", "lazy dog"]
    >>> matcher = Matcher(L)
    >>> doc = "The quick brown fox jumps over the lazy dog."
    >>> matcher.match(doc)
    [('brown fox', 'lazy dog')]
    

    此解决方案确实有一些限制。一是它不会检测重叠的短语对。因此,在示例中,如果您将短语 "jumps over" 添加到短语列表中,您仍然只会得到一对匹配的 ("brown fox", "jumps over")。它会漏掉("brown fox", "lazy dog")("jumps over", "lazy dog"),因为它们包含一些相同的词。

    【讨论】:

      【解决方案3】:

      扩展 Joel 的答案,您的迭代器可能是这样的:

      def doc_iter(doc):
        words=doc[0:4]
        yield words
        for i in range(3,len(doc)):
          words=words[1:]
          words.append(doc[i])
          yield words
      

      将您的短语放入字典中并在文档上使用迭代器,在每次迭代时检查短语。这应该会给你 O(n) 和 O(n*log(n)) 之间的性能。

      【讨论】:

        猜你喜欢
        • 2016-06-30
        • 2019-08-31
        • 2020-12-29
        • 1970-01-01
        • 2017-05-30
        • 1970-01-01
        • 1970-01-01
        • 2013-12-15
        • 2021-02-02
        相关资源
        最近更新 更多