【问题标题】:Removing stopwords with Python - quickly and efficiently使用 Python 删除停用词 - 快速高效
【发布时间】:2014-06-22 09:46:56
【问题描述】:

我有大约 600 万个文档,每个文档都有相当大的停用词集要从每个文档中删除。

我学到的技巧是通过使用 re 编译模式来删除这些。但是现在我收到了一个溢出错误。

我按如下方式处理停用词:

states_string =r'\b(' + '|'.join(states) + r')\b'
states_pattern = re.compile(states_string)

states 显然是一个字符串列表,例如 ['NY', 'CA',...]

我得到的错误是:OverflowError: regular expression code size limit exceeded

很明显,我正在编译模式的字符串太长了。

有没有人对如何处理这个问题或替代方法有任何建议。

我知道的一个是:[word for word in words if not word in stopwords],但它会遍历每个单词,因此并不理想。

请注意,停用词的长度为 2500。

【问题讨论】:

  • 你能提供一个简化的例子吗?
  • 我可以提供一个状态示例,但不足以显示我正在使用的停用词的数量。在此处尝试:stackoverflow.com/questions/1998261/… 以获取创建此错误的方法。放置所有停用词将太长!
  • 文件有多大?

标签: regex python-2.7 stop-words


【解决方案1】:

据我所知,您有 3 个选项 - 拆分成更小的正则表达式,使用类似 python 集的东西,或者 shell out(到 sed 或 awk)。假设您有一个包含单词和停用词列表的文档,并且您想要一个不同的单词文档 - 停用词。

正则表达式:

stopwords_regex_list = []
chunk_size = 100  # can tweak depending on size
for i in xrange(0, len(stopwords), chunk_size):
    stopwords_slice = stopwords[i:i + chunk_size]
    stopwords_regex_list.append(re.compile('\b(' + '|'.join(stopwords_slice) + ')\b'))
    with open('document') as doc:
        words = doc.read()  # can read only a certain size if the files are massive
    with open('regex_document', 'w') as regex_doc:
        for regex in stopwords_regex_list:
            words = regex.sub('', words)
        regex_doc.write(words)

套装:

stopwords_set = set(stopwords)
with open('document') as doc:
    words = doc.read()
    with open('set_document', 'w') as set_doc:
        for word in words.split(' '):
            if not word in stopwords_set:
                set_doc.write(word + ' ')

Sed:

with open('document') as doc:
    with open('sed_script', 'w') as sed_script:
        sed_script.writelines(['s/\<{}\>//g\n'.format(word) for word in stopwords])
    with open('sed_document', 'w') as sed_doc:
        subprocess.call(['sed', '-f', 'sed_script'], stdout=sed_doc, stdin=doc)

我不是 sed 专家,所以可能有比这更好的方法。您可能需要对每种方法进行编码,看看哪种方法最适合您。

【讨论】:

  • 感谢您的回答。当我查看单词频率的结尾时,我最终做的有点不同,我从 nltk 调用 FreqDist,在文本列表中,然后删除单词,被认为是字典中的停用词。 FreqDist 相当快,创建后删除意味着我不必检查一长串停用词中的每个单词。但是您的建议很棒,因为我会定期删除停用词
【解决方案2】:

这似乎是 Python 正则表达式引擎实现的硬性限制:

~/py27 $ ack -C3 'regular expression code size'
Modules/_sre.c
2756-        if (value == (unsigned long)-1 && PyErr_Occurred()) {
2757-            if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
2758-                PyErr_SetString(PyExc_OverflowError,
2759:                                "regular expression code size limit exceeded");
2760-            }
2761-            break;
2762-        }
2763-        self->code[i] = (SRE_CODE) value;
2764-        if ((unsigned long) self->code[i] != value) {
2765-            PyErr_SetString(PyExc_OverflowError,
2766:                            "regular expression code size limit exceeded");
2767-            break;
2768-        }
2769-    }

要绕过限制,您可能需要一个备用引擎。我推荐使用 Python 生成一个sed 脚本。这里有一个粗略的想法可以帮助您入门:

stopwords = '''
the an of by
for but is why'''.split()

print '#!/bin/sed -f'
for word in stopwords:
    print '/%s/ d' % word

【讨论】:

    【解决方案3】:

    我已经运行了以下,效果很好:

    >>> states = ['AL', 'AK', 'AS', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'DC', 'FM', 'FL', 'GA', 'GU', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MH', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ', 'NM', 'NY', 'NC', 'ND', 'MP', 'OH', 'OK', 'OR', 'PW', 'PA', 'PR', 'RI', 'SC', 'SD', 'TN', 'TX', 'UT', 'VT', 'VI', 'VA', 'WA', 'WV', 'WI', 'WY', 'AE', 'AA', 'AP']
    >>> states_string = r'\b(' + '|'.join(states) + r')\b'
    >>> states_pattern = re.compile(states_string)
    >>> states_pattern
    <_sre.SRE_Pattern object at 0x00000000034D3C40>
    

    根据您提供的信息,这是我能做的最好的事情。请务必在您的问题中发布整个数组,否则我们无法知道您是否使用了除此 50-statecode 数组之外的任何东西来生成列表。

    PS:功劳归于功劳:我在这里使用的数组主要基于this gist comment

    【讨论】:

    • 尝试为整个数组创建一个要点,但太大以至于它不会发布!
    • 刚刚尝试将其添加到帖子中,没有运气!还是太大了
    • @redrubia 我想我可以大致了解您正在使用的数组的大小。我认为 Raymond Hettinger 的回答已经很好地涵盖了您的问题。感谢您至少尝试。
    猜你喜欢
    • 2019-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-02
    • 2016-11-11
    • 1970-01-01
    • 2013-12-17
    • 2018-02-25
    相关资源
    最近更新 更多