马尔可夫链实现NLG

马尔可夫链是最早用于语言生成的算法。

马尔科夫链通过当前单词预测句子中的下一个单词。举个例子,模型通过下面两个句子进行训练,“I drink coffee in the morning”和“I eat sandwiches with tea”。“drink”后面出现“coffee”的概率是100%,“I”后面出现“eat”和“drink”的概率分别为50%。马尔可夫链在计算下一个单词出现概率的时候,会把每个单词之间的关系考虑进去。该模型最早用于为智能手机输入句子提供下一个单词生成建议。

但由于仅注意当前单词,马尔可夫模型无法探测当前单词与句子中其它单词的关系以及句子的结构,使得预测结果不够准确,在许多应用场景中受限。其实,隐马尔可夫模型和马尔科夫链之间没有关系,隐马尔可夫模型记住一下内容。

隐马尔科夫模型是关于时序的概率模型,描述由一个隐藏的马尔科夫链随机生成不可观测的状态随机序列,再由各个状态生成一个观测而产生观测序列的过程。隐藏的马尔科夫链随机生成的状态的序列,称为状态序列;每个状态生成一个观测,而由此产生的观测的随机序列,称为观测序列。马尔科夫链由初始概率分布、状态转移概率分布以及观测概率分布确定,其表达式为:λ=(A,B,π)其中,A表示状态转移概率分布,B表示观测概率分布,π表示初始概率分布。

import random
#训练模型
model={
    
    'START': ['I', 'you'], 'I': ['like'], 'like': ['to'], 'to': ['eat'], 'you': ['eat'], 'eat': ['apples','oranges'],'END': ['apples','oranges']}
#上面的模型词典中还有两个术语:“起始”(START)和“结束”(END),它们表示一个生成的句子的起始词和结束词,中文的jieba分词中可以加入自己的字典。而自己的字典的建立可以通过关键词的提取算法,提取后建立自己的特殊领域的字典。
#生成鸡汤句
generated = []
while True:
    if not generated:
        words = model['START']#['I', 'you']
    elif generated[-1] in model['END']:
        break
    else:
        words = model[generated[-1]]
    generated.append(random.choice(words))
	print(generated)

# 生成器部分包含一个循环。它首先会选取一个随机的起始词并将其添加至一个列表,
# 然后会在词典中所搜包含潜在跟随词的列表,并随机选取一个列表,将新的选取的词添加至该列表。
# 生成器#会一直选择随机的潜在跟随词直到找到结束词,然后会停止循环,输出生成的句子或所谓的“名言”

打印的结果如下两种情况:

D:\JC\envs\NLP\python.exe C:/Users/wangyao/Desktop/MachineLearning-master/MachineLearning-master/rnn/dataset/MakoverModel.py
['you']
['you', 'eat']
['you', 'eat', 'apples']

进程已结束,退出代码0
D:\JC\envs\NLP\python.exe C:/Users/wangyao/Desktop/MachineLearning-master/MachineLearning-master/rnn/dataset/MakoverModel.py
['I']
['I', 'like']
['I', 'like', 'to']
['I', 'like', 'to', 'eat']
['I', 'like', 'to', 'eat', 'oranges']

进程已结束,退出代码0

以上是根据两个句子之间做的马尔科夫链最后生成的结果,也可以根据已有的语料库,首先对语料库中的语料做出字典的序列,然后生成以上所述的字典模型,再根据字典模型和马尔科夫链进行预测下一个要生成的词语。


import nltk
import random
# 读取文件内容
file = open('vocab.txt', 'r',encoding='utf-8')
walden = file.read()
#对文件内容按照空格进行划分,其实划分之前对于一般的文章可以首先进行分词,然后将分词后的内容进行分割,得到分割后的结果
walden = walden.split()

def makePairs(arr):
    pairs = [ ]
    for i in range(len(arr)):
        if i < len(arr) - 1:
            temp = (arr[i], arr[ i + 1 ])
            pairs.append(temp)
    return pairs

def generate(cfd, word='三', num=100):
    for i in range(num):
        arr = [ ]  # make an array with the words shown by proper count
        for j in cfd[word]:
            for k in range(cfd[word][j]):
                arr.append(j)
        print(word, end=' ')
        word = arr[int((len(arr)) * random.random()) ]

pairs = makePairs(walden)
cfd = nltk.ConditionalFreqDist(pairs)
generate(cfd)

马尔可夫模型有个很酷的应用是一种语言模型,在这个模型中,我们根据当前的一个或几个词预测下一个词是什么。如果我们只是根据上一个词预测,则它是一个一阶马尔可夫模型。如果我们用上两个词预测,则它是一个二阶马尔可夫模型。首先我们引入NLTK,它是Python中最好的NLP库。我想说,虽然我们这里做的自然语言处理很简单,但NLTK的内置函数还是帮我节省了很多代码。然后我们利用split()函数将字符串(从文本文件中获得的)转换成一个数组。

首先我们引入NLTK,它是Python中最好的NLP库。我想说,虽然我们这里做的自然语言处理很简单,但NLTK的内置函数还是帮我节省了很多代码。然后我们利用split()函数将字符串(从文本文件中获得的)转换成一个数组。上边两个函数是代码的基本函数。我们最终要使用的NLTK中的“条件频率字典(nltk.ConditionalFreqDist()函数)”必须以成对数组作为输入,所以短语“Hi my name is Alex”需要变为[(“Hi”, “my”), (“my, “name”), (“name”, “is”), (“is”, “Alex”)]。函数makePairs以一个数组(以词分割字符串得到)作为输入,输出符合上边格式的数组。

生成文章的方法,需要一个条件频率分布作为输入。想想看,“农场”的后边每一个词出现的次数是多少?这是一个“条件频率分布”的输出(对于所有的词,而不只是“农场”)。生成函数的其余部分是根据训练数据中观察到的分布输出文本。我通过创建一个出现在当前词后边的每一个词组成的数组实现这一点。数组中也有正确的计数,因此,接下来我只需要随机选择数组中的一个词即可,而这个过程也是服从分布的。

可待研究的其他内容:1.nltk.ConditionalFreqDist()函数。 2.Jieba分词自定义词典的加入。3.自定义词典的高频词提取。

猜你喜欢

转载自blog.csdn.net/u014114763/article/details/94450531