8

我在使用 Python 下的 NLTK 时遇到问题,特别是 .generate() 方法。

生成(自我,长度=100)

打印使用三元语言模型生成的随机文本。

参数:

   * length (int) - The length of text to generate (default=100)

这是我正在尝试的简化版本。

import nltk

words = 'The quick brown fox jumps over the lazy dog'
tokens = nltk.word_tokenize(words)
text = nltk.Text(tokens)
print text.generate(3)

这将始终生成

Building ngram index...
The quick brown
None

与从单词中构建随机短语相反。

这是我的输出

print text.generate()

Building ngram index...
The quick brown fox jumps over the lazy dog fox jumps over the lazy
dog dog The quick brown fox jumps over the lazy dog dog brown fox
jumps over the lazy dog over the lazy dog The quick brown fox jumps
over the lazy dog fox jumps over the lazy dog lazy dog The quick brown
fox jumps over the lazy dog the lazy dog The quick brown fox jumps
over the lazy dog jumps over the lazy dog over the lazy dog brown fox
jumps over the lazy dog quick brown fox jumps over the lazy dog The
None

再次从相同的文本开始,然后改变它。我也尝试过使用 Orwell 1984 年的第一章。同样,它总是从前3 个标记(在这种情况下其中一个是空格)开始,然后继续随机生成文本。

我在这里做错了什么?

4

5 回答 5

12

要生成随机文本,需要使用马尔可夫链

执行此操作的代码:从这里

import random

class Markov(object):

  def __init__(self, open_file):
    self.cache = {}
    self.open_file = open_file
    self.words = self.file_to_words()
    self.word_size = len(self.words)
    self.database()


  def file_to_words(self):
    self.open_file.seek(0)
    data = self.open_file.read()
    words = data.split()
    return words


  def triples(self):
    """ Generates triples from the given data string. So if our string were
    "What a lovely day", we'd generate (What, a, lovely) and then
    (a, lovely, day).
    """

    if len(self.words) < 3:
      return

    for i in range(len(self.words) - 2):
      yield (self.words[i], self.words[i+1], self.words[i+2])

  def database(self):
    for w1, w2, w3 in self.triples():
      key = (w1, w2)
      if key in self.cache:
    self.cache[key].append(w3)
      else:
    self.cache[key] = [w3]

  def generate_markov_text(self, size=25):
    seed = random.randint(0, self.word_size-3)
    seed_word, next_word = self.words[seed], self.words[seed+1]
    w1, w2 = seed_word, next_word
    gen_words = []
    for i in xrange(size):
      gen_words.append(w1)
      w1, w2 = w2, random.choice(self.cache[(w1, w2)])
    gen_words.append(w2)
    return ' '.join(gen_words)

说明: 使用 Python 生成带有马尔可夫链的伪随机文本

于 2009-07-20T18:48:31.653 回答
7

您应该使用多个序列“训练”马尔可夫模型,以便您也可以准确地采样起始状态概率(在马尔科夫语中称为“pi”)。如果您使用单个序列,那么您将始终以相同的状态开始。

在 Orwell 的 1984 年的案例中,您可能希望首先使用句子标记化(NLTK 非常擅长),然后是单词标记化(生成标记列表列表,而不仅仅是单个标记列表),然后将每个句子分别提供给马尔可夫模型。这将允许它正确地模拟序列开始,而不是卡在单一的方式来开始每个序列。

于 2009-09-26T15:50:57.493 回答
1

您的样本语料库很可能太小。我不知道 nltk 究竟是如何构建它的 trigram 模型的,但通常的做法是以某种方式处理句子的开头和结尾。由于您的语料库中只有一个句子的开头,这可能是每个句子都有相同开头的原因。

于 2009-07-19T16:35:15.670 回答
0

您确定使用word_tokenize是正确的方法吗?

此 Google 群组页面有以下示例:

>>> import nltk
>>> text = nltk.Text(nltk.corpus.brown.words()) # Get text from brown
>>> text.generate() 

但我从未使用过 nltk,所以我不能说它是否按你想要的方式工作。

于 2009-07-19T16:07:12.310 回答
-1

也许您可以在生成句子之前对令牌数组进行随机排序。

于 2009-07-19T15:47:09.747 回答