在Python的NLTK中从自定义文本生成随机句子?

8 投票
5 回答
26594 浏览
提问于 2025-04-15 13:00

我在使用Python的NLTK库时遇到了一些麻烦,特别是在使用.generate()这个方法的时候。

generate(self, length=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

再次以相同的文本开始,但接着会有所变化。我还尝试过使用奥威尔的《1984》的第一章。结果也是总是从前面三个词开始(其中一个在这个情况下是空格),然后随机生成文本。

我到底哪里做错了呢?

5 个回答

1

你的样本数据可能太少了。我不太清楚nltk是怎么构建三元组模型的,但通常在处理句子时,开头和结尾会有一些特别的处理。因为在你的数据中只有一个句子的开头,这可能就是为什么每个句子都以相同的方式开始的原因。

7

你应该用多个序列来“训练”马尔可夫模型,这样才能准确地采样起始状态的概率(在马尔可夫的术语中叫“pi”)。如果只用一个序列,那你每次都会从同一个状态开始。

以奥威尔的《1984》为例,你首先需要进行句子分割(NLTK在这方面做得很好),然后再进行单词分割(这样会得到一个包含多个列表的列表,而不仅仅是一个单一的单词列表),最后把每个句子单独输入到马尔可夫模型中。这样可以让模型更好地模拟序列的开始,而不是总是从同一种方式开始每个序列。

13

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

实现这个功能的代码可以在这里找到:从这里

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生成伪随机文本的马尔可夫链

撰写回答