我有一本字典,里面有将近一百万个多词词汇(包含空格的词汇)。这看起来像
[...,
'multilayer ceramic',
'multilayer ceramic capacitor',
'multilayer optical disk',
'multilayer perceptron',
...]
我想用千兆字节的文本来计算它们的频率
作为一个小例子,考虑在维基百科页面中计算这四个多词表达式:payload = {'action': 'query', 'titles': 'Ceramic_capacitor', 'explaintext':1, 'prop':'extracts', 'format': 'json'}
r = requests.get('https://en.wikipedia.org/w/api.php', params=payload)
sampletext = r.json()['query']['pages']['9221221']['extract'].lower()
sampledict = ['multilayer ceramic', 'multilayer ceramic capacitor', 'multilayer optical disk', 'multilayer perceptron']
termfreqdic = {}
for term in sampledict:
termfreqdic[term] = sampletext.count(term)
print(termfreqdic)
这给出了类似于{'multilayer ceramic': 7, 'multilayer ceramic capacitor': 2, 'multilayer optical disk': 0, 'multilayer perceptron': 0}
的结果,但如果字典包含一百万个条目,这似乎是次优的
我尝试过使用非常大的正则表达式:
termlist = [re.escape(w) for w in open('termlistfile.txt').read().strip().split('\n')]
termregex = re.compile(r'\b'+r'\b|\b'.join(termlist), re.I)
termfreqdic = {}
for i,li in enumerate(open(f)):
for m in termregex.finditer(li):
termfreqdic[m.group(0)]=termfreqdic.get(m.group(0),0)+1
open('counted.tsv','w').write('\n'.join([a+'\t'+v for a,v in termfreqdic.items()]))
这是非常慢的(在最近的i7上,1000行文字需要6分钟)。
但是如果我用regex
而不是re
替换前两行,则每1000行文本的速度会下降到12秒左右,这对于我的需求来说仍然非常缓慢:
termlist = open(termlistfile).read().strip().split('\n')
termregex = regex.compile(r"\L<options>", options=termlist)
...
请注意,这并不完全符合我的要求,因为一个术语可能是另一个术语的子术语,如示例“多层陶瓷”和“多层陶瓷电容器”(也不包括Find multi-word terms in a tokenized text in Python中的第一标记化方法)
这看起来像是一个常见的序列匹配问题,无论是在文本语料库中还是在遗传字符串中,都必须有众所周知的解决方案。也许可以用一些trie字来解决这个问题(我不介意术语表的初始编译速度太慢)?唉,我似乎没有找到合适的术语。也许有人能给我指出正确的方向
下面给出了一种NLTK方法,其效果相对较好。作者无法复制相同的sampledict,因此为了本练习,它是从sampletext创建的。 注:提问者给出的方法需要大约60倍的时间
来源数据:
按旧方法计时:
NLTK方法的时间:
通过将频率分布转换为数据帧来访问数据
@SidharthMacherla让我走上了正确的道路(NLTK和标记化),尽管他的解决方案没有解决多词表达的问题,而且可能会重叠
简而言之,我找到的最好的方法是将NLTK的
MWETokenizer
子类化,并添加一个函数,使用util.Trie计算多个单词:以下是带有速度测量的测试套件:
使用FreqMWETokenizer计算10m字符中的10k多字项需要2秒,使用MWETokenizer需要4秒(也提供了完整的标记化,但不计算重叠),使用simple count方法需要150秒,使用大型正则表达式需要1000秒。尝试100m字符中的100k多字术语仍然可以使用标记化器,而不使用计数或正则表达式
对于测试,请在https://mega.nz/file/PsVVWSzA#5-OHy-L7SO6fzsByiJzeBnAbtJKRVy95YFdjeF_7yxA找到两个大型示例文件
相关问题 更多 >
编程相关推荐