Python 2.7 合并生成器对象以计算NLTK中的频率

Python 2.7 合并生成器对象以计算NLTK中的频率,python-2.7,nltk,generator,word-frequency,Python 2.7,Nltk,Generator,Word Frequency,我正在尝试使用nltk中的ngram和freqDist函数计算各种ngram的频率。 由于ngram函数输出是一个generator对象,我想在计算频率之前合并每个ngram的输出。 但是,我在合并各种生成器对象时遇到了问题 我尝试了itertools.chain,它创建了一个itertools对象,而不是合并生成器。 我最终决定使用置换,但之后解析对象似乎是多余的 迄今为止的工作守则是: import nltk from nltk import word_tokenize, pos_tag f

我正在尝试使用
nltk
中的
ngram
freqDist
函数计算各种
ngram
的频率。 由于
ngram
函数输出是一个
generator
对象,我想在计算频率之前合并每个ngram的输出。 但是,我在合并各种生成器对象时遇到了问题

我尝试了
itertools.chain
,它创建了一个
itertools
对象,而不是合并生成器。 我最终决定使用
置换
,但之后解析对象似乎是多余的

迄今为止的工作守则是:

import nltk
from nltk import word_tokenize, pos_tag
from nltk.collocations import *
from itertools import *
from nltk.util import ngrams
import re
corpus = 'testing sentences to see if if if this works'
token = word_tokenize(corpus)
unigrams = ngrams(token,1)
bigrams = ngrams(token,2)
trigrams = ngrams(token,3)


perms = list(permutations([unigrams,bigrams,trigrams]))
fdist = nltk.FreqDist(perms)
for x,y in fdist.items():
    for k in x:
        for v in k:
            words = '_'.join(v)
            print words, y
正如您在结果中所看到的,freq dist没有正确计算来自各个生成器对象的单词,因为每个对象的频率为1。 有没有一种更符合python的方法来正确地执行此操作?

使用,它返回给定n范围的所有n-gram

>>> from nltk import everygrams
>>> from nltk import FreqDist
>>> corpus = 'testing sentences to see if if if this works'
>>> everygrams(corpus.split(), 1, 3)
<generator object everygrams at 0x7f4e272e9730>
>>> list(everygrams(corpus.split(), 1, 3))
[('testing',), ('sentences',), ('to',), ('see',), ('if',), ('if',), ('if',), ('this',), ('works',), ('testing', 'sentences'), ('sentences', 'to'), ('to', 'see'), ('see', 'if'), ('if', 'if'), ('if', 'if'), ('if', 'this'), ('this', 'works'), ('testing', 'sentences', 'to'), ('sentences', 'to', 'see'), ('to', 'see', 'if'), ('see', 'if', 'if'), ('if', 'if', 'if'), ('if', 'if', 'this'), ('if', 'this', 'works')]

或者,您可以将计数器组合为:

>>> from collections import Counter
>>> x = Counter([1,2,3,4,4,5,5,5])
>>> y = Counter([1,1,1,2,2])
>>> x + y
Counter({1: 4, 2: 3, 5: 3, 4: 2, 3: 1})
>>> x

>>> from nltk import FreqDist
>>> FreqDist(['a', 'a', 'b'])
FreqDist({'a': 2, 'b': 1})
>>> a = FreqDist(['a', 'a', 'b'])
>>> b = FreqDist(['b', 'b', 'c', 'd', 'e'])
>>> a + b
FreqDist({'b': 3, 'a': 2, 'c': 1, 'e': 1, 'd': 1})

Alvas是对的,
nltk。everygrams
是这项工作的完美工具。但是合并几个迭代器并不是那么难,也不是那么少见,所以您应该知道如何做到这一点。关键是任何迭代器都可以转换为列表,但最好只转换一次:

列出几个迭代器
  • 仅使用列表(简单但效率低下)

  • 或者正确地建立一个列表

    allgrams = list(unigrams)
    allgrams.extend(bigrams)
    allgrams.extend(trigrams)
    
  • 或者使用
    itertools.chain()
    ,然后列出一个列表

    allgrams = list(itertools.chain(unigrams, bigrams, trigrams))
    
  • 上述方法产生了相同的结果(只要您不尝试重用迭代器
    unigram
    等——您需要在示例之间重新定义迭代器)

    使用迭代器本身 不要与迭代器对抗,要学会使用迭代器。许多Python函数接受它们而不是列表,从而节省了大量空间和时间

  • 您可以形成一个迭代器并将其传递给
    nltk.FreqDist()

  • 您可以使用多个迭代器
    FreqDist
    Counter
    一样,有一个
    update()
    方法,可用于递增计数:

    fdist = nltk.FreqDist(unigrams)
    fdist.update(bigrams)
    fdist.update(trigrams)
    

  • 虽然我接受了上述答案,因为它是这份工作的正确工具,但感谢您提供的极其相关的信息和解释。我一直在努力使用生成器,现在我对使用和连接生成器的不同方法有了更清晰的认识。
    allgrams = list(itertools.chain(unigrams, bigrams, trigrams))
    
    fdist = nltk.FreqDist(itertools.chain(unigrams, bigrams, trigrams))
    
    fdist = nltk.FreqDist(unigrams)
    fdist.update(bigrams)
    fdist.update(trigrams)