【问题标题】:NLTK perceptron tagger "TypeError: 'LazySubsequence' object does not support item assignment"NLTK 感知器标记器“TypeError:'LazySubsequence' 对象不支持项目分配”
【发布时间】:2017-01-30 00:47:05
【问题描述】:

我想尝试在 Python 3.5 的 nltk 包中使用 PerceptronTagger,但我收到错误 TypeError: 'LazySubsequence' object does not support item assignment

我想用来自带有universal 标签集的棕色语料库的数据来训练它。

这是我遇到问题时正在运行的代码。

import nltk,math
tagged_sentences = nltk.corpus.brown.tagged_sents(categories='news',tagset='universal')
i = math.floor(len(tagged_sentences)*0.2)
testing_sentences = tagged_sentences[0:i]
training_sentences = tagged_sentences[i:]
perceptron_tagger = nltk.tag.perceptron.PerceptronTagger(load=False)
perceptron_tagger.train(training_sentences)

它不会正确训练,并给出以下堆栈跟踪。

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-10-61332d63d2c3> in <module>()
      1 perceptron_tagger = nltk.tag.perceptron.PerceptronTagger(load=False)
----> 2 perceptron_tagger.train(training_sentences)

/home/nathan/anaconda3/lib/python3.5/site-packages/nltk/tag/perceptron.py in train(self, sentences, save_loc, nr_iter)
    192                     c += guess == tags[i]
    193                     n += 1
--> 194             random.shuffle(sentences)
    195             logging.info("Iter {0}: {1}/{2}={3}".format(iter_, c, n, _pc(c, n)))
    196         self.model.average_weights()

/home/nathan/anaconda3/lib/python3.5/random.py in shuffle(self, x, random)
    270                 # pick an element in x[:i+1] with which to exchange x[i]
    271                 j = randbelow(i+1)
--> 272                 x[i], x[j] = x[j], x[i]
    273         else:
    274             _int = int

TypeError: 'LazySubsequence' object does not support item assignment

它似乎来自random 模块中的shuffle 函数,但这似乎并不正确。

还有其他可能导致问题的原因吗? 有人遇到过这个问题吗?

我在 Ubuntu 16.04.1 上使用 Anaconda Python 3.5 运行它。 nltk 版本是3.2.1

【问题讨论】:

    标签: classification nltk anaconda python-3.5 perceptron


    【解决方案1】:

    NLTK 有很多自定义的“惰性”类型,它们应该可以轻松处理大量数据,例如带注释的语料库。它们在许多方面表现得像标准列表、元组、字典等,但避免不必要地占用过多内存。

    其中一个实例是LazySubsequence,它是切片表达式tagged_sentences[i:] 的结果。如果tagged_sentences 是一个普通列表,则将数据划分为测试/训练将创建数据的完整副本。相反,这个LazySubsequence 是原始序列部分的视图

    虽然这对内存的好处可能是一件好事,但这里的问题是这个视图是只读的。 显然PerceptronTagger 想就地洗牌其输入数据,这是不允许的——因此例外。

    一个快速(但可能不是最优雅)的解决方案是为标记器提供数据的副本:

    perceptron_tagger.train(tuple(training_sentences))
    

    您可能必须对测试数据做同样的事情。

    【讨论】:

    • 看起来你在我写我的时候写了一个答案。我得出了同样的结论,所以我会标记你的正确,因为我很感激你的努力。
    • 很高兴您自己找到了解决方案!这些 NLTK 容器可能很难使用,有时......
    【解决方案2】:

    调试

    nltk源代码中做一些greping找到了答案。

    在文件site-packages/nltk/util.py 中声明了类。

    class LazySubsequence(AbstractLazySequence):
        """                                                                                                                                                                  
        A subsequence produced by slicing a lazy sequence.  This slice                                                                                                       
        keeps a reference to its source sequence, and generates its values                                                                                                   
        by looking them up in the source sequence.                                                                                                                           
        """
    

    在解释器的另一次快速测试之后,我看到了有关tagged_sentencestype() 的以下详细信息

    >>> import nltk
    >>> tagged_sentences = nltk.corpus.brown.tagged_sents(categories='news',tagset='universal')
    >>> type(tagged_sentences)
    <class 'nltk.corpus.reader.util.ConcatenatedCorpusView'>
    

    我在文件中看到site-packages/nltk/corpus/reader/util.py

    class ConcatenatedCorpusView(AbstractLazySequence):
        """                                                                                                                                                                  
        A 'view' of a corpus file that joins together one or more                                                                                                            
        ``StreamBackedCorpusViews<StreamBackedCorpusView>``.  At most                                                                                                        
        one file handle is left open at any time.                                                                                                                            
        """
    

    random 包的最终测试证明问题存在于我创建tagged_sentences 的方式中

    >>> import random
    >>> random.shuffle(training_sentences)
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-30-0b03f0366949> in <module>()
          1 import random
    ----> 2 random.shuffle(training_sentences)
          3 
          4 
          5 
    
    /home/nathan/anaconda3/lib/python3.5/random.py in shuffle(self, x, random)
        270                 # pick an element in x[:i+1] with which to exchange x[i]
        271                 j = randbelow(i+1)
    --> 272                 x[i], x[j] = x[j], x[i]
        273         else:
        274             _int = int
    
    TypeError: 'LazySubsequence' object does not support item assignment
    

    解决方案

    要解决该错误,只需从nltk.corpus.brown 包中显式创建句子列表,然后random 就可以正确打乱数据。

    import nltk,math
    # explicitly make list, then LazySequence will traverse all items
    tagged_sentences = [sentence for sentence in nltk.corpus.brown.tagged_sents(categories='news',tagset='universal')]
    i = math.floor(len(tagged_sentences)*0.2)
    testing_sentences = tagged_sentences[0:i]
    training_sentences = tagged_sentences[i:]
    perceptron_tagger = nltk.tag.perceptron.PerceptronTagger(load=False)
    perceptron_tagger.train(training_sentences)
    # no error, yea!
    

    现在标记可以正常工作了。

    >>> perceptron_tagger_preds = []
    >>> for test_sentence in testing_sentences:
    ...    perceptron_tagger_preds.append(perceptron_tagger.tag([word for word,_ in test_sentence]))
    >>> print(perceptron_tagger_preds[676])
    [('Formula', 'NOUN'), ('is', 'VERB'), ('due', 'ADJ'), ('this', 'DET'), ('week', 'NOUN')]
    

    【讨论】:

      猜你喜欢
      • 2016-07-31
      • 2014-02-18
      • 2017-03-26
      • 2021-08-05
      • 1970-01-01
      • 1970-01-01
      • 2022-08-08
      • 2013-08-16
      相关资源
      最近更新 更多