减少在语料库中计算单词频率的计算时间(python)

时间:2017-10-25 04:54:04

标签: python nlp

def foo(self, n):
    wordFreqDict = defaultdict(int)
    resultList = []

    for sentence in self.allSentences:
        for word in self.wordSet:
            if word in sentence:
                wordFreqDict[word] += 1

    for candidateWord in wordFreqDict:
        if wordFreqDict[candidateWord] >= n:
            resultList.append(candidateWord)

    return resultList

我的函数基本上返回单词列表中的单词列表,如果它出现在至少n个句子中。我想要做的就是遍历self.allSentences是一个单词列表(句子)并迭代self.wordSet(语料库中的所有独特单词)并将每个单词的频率添加到字典中( wordFreqDict)。

然后遍历wordFreqDict并将一个频率为> = n的单词添加到resultList中。

我认为这会有效,但检查结果的时间太长。

有没有办法让它更有效率并缩短计算时间?

编辑:

以下是self.allSentences的计算方法

def storeAllSentences(self, corpus):
    for sentence in corpus:
        self.allSentences.append(sentence)

和self.wordSet:

def getUniqueWordSet(self, corpus):
    for sentence in self.allSentences:
        for word in sentence:
            self.wordSet.append(word)

    self.wordSet = set(self.wordSet)

2 个答案:

答案 0 :(得分:1)

这里的假设是,如果一个单词唯一地出现在至少 n个句子中,则会选择该单词。所以,即使它在一个句子中出现10次,那仍然是一次。

一些明显的问题是您的嵌套循环和in检查字符串。这实际上是复杂的立方体。应该可以使用set + Counter来大幅减少这种情况。

from collections import Counter
from itertools import takewhile

def foo(self, n):
    c = Counter()
    for sent in self.allSentences:
        c.update(set(sent))

    resultSet = list(itertools.takewhile(lambda x: x[1] >= n, c.most_common()))

    return resultSet

在这里,我使用正则表达式删除特殊字符和标点符号,然后我拆分并检索句子中的所有唯一单词。然后更新Counter

最后,使用itertools.takewhile提取所需频率(或更多)的所有单词并返回。

如果sent是一个字符串句子,您可以使用基于re的过滤来删除标点符号,然后拆分:

import re

tempWordSet = set(re.sub('[^\w\s]+', '', sent).split())  
c.update(tempWordSet)

这不考虑单词是否属于self.wordSet。因此,如果您也想要这样,您可以稍微修改第一个循环以包含filter步骤:

 c.update(set(filter(lambda x: x in self.wordSet, sent)))

或者,使用第二种技术:

 tempWordSet = set(filter(lambda x: x in self.wordSet, 
                         re.sub('[^\w\s]+', '', sent).split()))

在一个不相关的说明中,您是否尝试执行文本挖掘?您可能有兴趣研究TFIDF

答案 1 :(得分:1)

集合 wordSet 可能比单个句子中的单词大至少两个数量级。因此,它通过句子中的单词循环有意义。但是,这要求拆分句子并不是一个非常慢的操作。如果是,则应该在getUniqueWordSet中执行整个过程。这里只改变了第一个for循环:

def foo(self, n):
wordFreqDict = defaultdict(int)
resultList = []

for sentence in self.allSentences:
   for word in sentence: 
      # This if may be left out if allSentences is guaranteed to stay the same after storing them
      if word in self.wordSet:  
          wordFreqDict[word] += 1

for candidateWord in wordFreqDict:
    if wordFreqDict[candidateWord] >= n:
        resultList.append(candidateWord)

return resultList