Python 3.5-获取计数器以报告零频项目

ann*_*e_t 5 python counter word-frequency

我正在对文本进行文本分析,由于PDF到txt的转换错误,有时会把单词混在一起。因此,我想匹配字符串,而不是匹配单词。

例如,我有字符串:

mystring='The lossof our income made us go into debt but this is not too bad as we like some debts.'
Run Code Online (Sandbox Code Playgroud)

我寻找

key_words=['loss', 'debt', 'debts', 'elephant']
Run Code Online (Sandbox Code Playgroud)

输出应采用以下形式:

Filename Debt Debts Loss Elephant
mystring  2    1     1    0
Run Code Online (Sandbox Code Playgroud)

我所拥有的代码工作正常,除了一些小故障:1)它不报告零频单词的出现频率(因此输出中不会出现“大象”:2)key_words中单词的顺序似乎很重要(即,有时我对“债务”和“债务”各取1个计数,有时它只报告“债务”的2个计数,而“未报告债务”。如果我设法“打印”,我可以接受第二点”变量名称添加到数据集...但不确定如何操作。

以下是相关代码。谢谢!PS。不用说,它不是最优雅的代码,但是我正在慢慢学习。

bad=set(['debts', 'debt'])

csvfile=open("freq_10k_test.csv", "w", newline='', encoding='cp850', errors='replace')
writer=csv.writer(csvfile)
for filename in glob.glob('*.txt'):

    with open(filename, encoding='utf-8', errors='ignore') as f:
      file_name=[]
      file_name.append(filename)

      new_review=[f.read()]
      freq_all=[]
      rev=[]

      from collections import Counter

      for review in new_review:
        review_processed=review.lower()
        for p in list(punctuation):
           review_processed=review_processed.replace(p,'')
           pattern = re.compile("|".join(bad), flags = re.IGNORECASE)
           freq_iter=collections.Counter(pattern.findall(review_processed))           

        frequency=[value for (key,value) in sorted(freq_iter.items())]
        freq_all.append(frequency)
        freq=[v for v in freq_all]

    fulldata = [ [file_name[i]] + freq  for i, freq in enumerate(freq)]  

    writer=csv.writer(open("freq_10k_test.csv",'a',newline='', encoding='cp850', errors='replace'))
    writer.writerows(fulldata)
    csvfile.flush()
Run Code Online (Sandbox Code Playgroud)

Cor*_*man 6

您可以预先初始化计数器,如下所示:

freq_iter = collections.Counter()
freq_iter.update({x:0 for x in bad})
freq_iter.update(pattern.findall(review_processed))   
Run Code Online (Sandbox Code Playgroud)

一件好事Counter是您实际上不必预先初始化它 - 您可以只做c = Counter(); c['key'] += 1,但是如果您愿意,没有什么可以阻止您将某些值预先初始化为 0。

对于debt/debts事情 - 这只是一个未充分说明的问题。在这种情况下,您希望代码做什么?如果您希望它匹配匹配的最长模式,则需要对列表进行最长排序,这将解决它。如果您想同时报告两者,您可能需要进行多次搜索并保存所有结果。

更新以添加一些关于为什么找不到的信息debts:这与正则表达式 findall 的关系比其他任何事情都多。re.findall总是寻找最短的匹配项,但一旦找到,它就不会将其包含在后续匹配项中:

In [2]: re.findall('(debt|debts)', 'debtor debts my debt')
Out[2]: ['debt', 'debt', 'debt']
Run Code Online (Sandbox Code Playgroud)

如果您真的想找到每个单词的所有实例,则需要分别进行:

In [3]: re.findall('debt', 'debtor debts my debt')
Out[3]: ['debt', 'debt', 'debt']

In [4]: re.findall('debts', 'debtor debts my debt')
Out[4]: ['debts']
Run Code Online (Sandbox Code Playgroud)

但是,也许您真正要寻找的是words。在这种情况下,使用\b运算符来要求分词:

In [13]: re.findall(r'\bdebt\b', 'debtor debts my debt')
Out[13]: ['debt']

In [14]: re.findall(r'(\b(?:debt|debts)\b)', 'debtor debts my debt')
Out[14]: ['debts', 'debt']
Run Code Online (Sandbox Code Playgroud)

我不知道这是否是你想要的或不...在这种情况下,它能够区分debtdebts正确的,但错过了debtor,因为它只匹配字符串,我们要求它不要。

根据您的用例,您可能想要研究对文本进行词干处理...我相信 nltk 中有一个非常简单(只使用过一次,所以我不会尝试发布示例...这个问题在NLTK结合文本制止和拆除标点符号和scikit学习可能是有用的),就应减少debtdebts以及debtor所有的同根词debt,并为换句话说做类似的事情。这可能有帮助,也可能没有帮助;我不知道你用它做什么。