我想计算一个文本文件中所有单词的频率。
>>> countInFile('test.txt')
{'aaa':1, 'bbb': 2, 'ccc':1}如果目标文本文件如下所示,则应返回:
{'aaa':1, 'bbb': 2, 'ccc':1}
# test.txt aaa bbb ccc bbb
在一些帖子之后,我已经用纯python实现了它。但是,我发现由于巨大的文件大小(> 1GB),纯python方法是不够的。
我认为借用sklearn的能力是一个候选人。
如果让CountVectorizer为每一行计数频率,我想您将通过累加每一列来获得字频率。但是,这听起来有点间接。
用python计算文件中单词的最有效,最直接的方法是什么?
我的代码(很慢)在这里:
from collections import Counter def get_term_frequency_in_file(source_file_path): wordcount = {} with open(source_file_path) as f: for line in f: line = line.lower().translate(None, string.punctuation) this_wordcount = Counter(line.split()) wordcount = add_merge_two_dict(wordcount, this_wordcount) return wordcount def add_merge_two_dict(x, y): return { k: x.get(k, 0) + y.get(k, 0) for k in set(x) | set(y) }
最简洁的方法是使用Python提供的工具。
from future_builtins import map # Only on Python 2 from collections import Counter from itertools import chain def countInFile(filename): with open(filename) as f: return Counter(chain.from_iterable(map(str.split, f)))
而已。map(str.split, f)使生成器list从每一行返回s个单词。包装chain.from_iterable将其转换为单个生成器,一次生成一个单词。Counter接受一个可迭代的输入,并计算其中的所有唯一值。最后,您return是一个类似 dict的对象(a Counter),用于存储所有唯一单词及其计数,并且在创建期间,您一次只存储一行数据和总计数,而不是一次存储整个文件。
map(str.split, f)
list
chain.from_iterable
Counter
return
dict
从理论上讲,在Python 2.7和3.1上,您可以自己更好地循环使用链结结果,并使用dict或collections.defaultdict(int)进行计数(因为Counter在Python中实现,在某些情况下会使其变慢),但让Counter工作更简单以及更多自我记录(我的意思是,整个目标都在计算,因此请使用Counter)。除此之外,在CPython(参考解释器)3.2和更高版本上,Counter还具有C级加速器,用于对可迭代的输入进行计数,其运行速度比纯Python中编写的任何代码都要快。
collections.defaultdict(int)
更新: 您似乎想删除标点符号并且不区分大小写,所以这是我以前的代码的一种变体,它可以做到:
from string import punctuation def countInFile(filename): with open(filename) as f: linewords = (line.translate(None, punctuation).lower().split() for line in f) return Counter(chain.from_iterable(linewords))
你的代码的运行速度要慢得多,因为它创建和销毁许多小型Counter和set对象,而不是.update-ing单Counter每行(其中,而稍比我在更新的代码块给速度较慢,至少会在比例因子算法类似的一次)。
set
.update