codeye
2022/10/31阅读:43主题:默认主题
用Python中的马尔科夫链模拟文本
用Python中的马尔科夫链模拟文本
在我的上一篇文章中,我在马尔科夫链蒙特卡洛方法的背景下介绍了马尔科夫链。这篇文章是那篇文章的一个小补充,展示了你可以用马尔科夫链做的一件有趣的事情:模拟文本。

马尔科夫链是一个模拟的事件序列。序列中的每个事件都来自一组相互依赖的结果。特别是,每个结果都决定了哪些结果可能会在接下来发生。在马尔科夫链中,预测下一个事件所需的所有信息都包含在最近的事件中。这意味着,了解马尔可夫链的全部历史并不能帮助你更好地预测下一个结果,而只是知道最后一个结果是什么。
马尔科夫链通常不是近期事件的可靠预测者,因为现实世界中的大多数过程比马尔科夫链允许的更复杂。然而,马尔科夫链被用来研究一系列事件的长期行为,这些事件之间有固定的概率关系。
对于世界上任何非独立事件的序列,在有限数量的结果可能发生的情况下,可以计算出每个结果之间的条件概率。通常情况下,这只是采取计算某些结果在观察到的序列中彼此相随的频率的形式。
要生成一个基于特定文本的模拟,计算每一个被使用的单词。然后,对于每一个词,存储接下来使用的词。这就是该文本中以前面的词为条件的词的分布。
为了模拟唐纳德-特朗普的一些文本,让我们使用他在2016年竞选中的演讲稿集,这里可以找到。
首先导入numpy和包含特朗普演讲稿的文本文件。
import numpy as np
trump = open('speeches.txt', encoding='utf8').read()
然后,将该文本文件分割成单个单词。注意我们要保留所有的标点符号,所以我们的模拟文本有标点符号。
corpus = trump.split()
然后,我们定义一个函数,给我们提供演讲稿中的所有词对。我们使用懒人评估,产生一个生成器对象,而不是用每一对词来填充我们的内存。
def make_pairs(corpus):
for i in range(len(corpus)-1):
yield (corpus[i], corpus[i+1])
pairs = make_pairs(corpus)
然后我们实例化一个空的字典,并从我们的对子中填充单词。如果对中的第一个词已经是字典中的一个键,则简单地将下一个词追加到该词后面的词的列表中。
否则,在字典中初始化一个新条目,其键值等于第一个词,其值为长度为 1 的列表。
word_dict = {}
for word_1, word_2 in pairs:
if word_1 in word_dict.keys():
word_dict[word_1].append(word_2)
else:
word_dict[word_1] = [word_2]
最后我们选取一些随机的词来启动这个链,并选择我们要模拟的词的数量。
first_word = np.random.choice(corpus)
chain = [first_word]
n_words = 30
在第一个词之后,链中的每个词都从特朗普的实际演讲中紧随其后的词列表中随机抽出。
for i in range(n_words):
chain.append(np.random.choice(word_dict[ chain[-1]]))
最后的join
命令将链作为一个字符串返回。
''.join(chain)
当我运行这段代码时,我的第一个结果是。
'我将能够投票。得到了他们的回复。我们要做一个完全的谎言,紧接着证明出来。"在相反的期间。我们有一些投票率。我的病人是真的'
这里很好的一点是,我们用一个字典来实际查找链中的下一个词。当然,你可以用一个函数来包装这一切,这一点我留给读者一个练习。
有很多工具可以对文本进行 "马尔可夫化",我鼓励你去找找它们。但是对于刚刚学习马尔科夫链的人来说,这里的代码是一个容易开始的地方。
但是有无穷无尽的改进余地。例如,你可以要求第一个词大写,这样你的文本就不会在句子中间开始。
while first_word.islower():
first_word = np.random.choice(corpus)
我希望这对那些刚开始接触马尔科夫链的人来说是有帮助的。如果这段代码可以在不影响清晰度的情况下进行改进,请留下评论!
import numpy as np
# Trump's speeches here: https://github.com/ryanmcdermott/trump-speeches
trump = open('speeches.txt', encoding='utf8').read()
corpus = trump.split()
def make_pairs(corpus):
for i in range(len(corpus)-1):
yield (corpus[i], corpus[i+1])
pairs = make_pairs(corpus)
word_dict = {}
for word_1, word_2 in pairs:
if word_1 in word_dict.keys():
word_dict[word_1].append(word_2)
else:
word_dict[word_1] = [word_2]
first_word = np.random.choice(corpus)
while first_word.islower():
first_word = np.random.choice(corpus)
chain = [first_word]
n_words = 50
for i in range(n_words):
chain.append(np.random.choice(word_dict[chain[-1]]))
' '.join(chain)
end.
作者介绍