[NLP]手把手教你使用Python實(shí)現(xiàn)一個(gè)句子生成器

本文主要介紹如何通過(guò)預(yù)先設(shè)定好的語(yǔ)法規(guī)則以及單詞,通過(guò)Python來(lái)自動(dòng)生成一些句子。

解析語(yǔ)法

在生成句子之前,我們需要先告訴機(jī)器生成句子的語(yǔ)法。

因此,我們先定義一個(gè)簡(jiǎn)單的語(yǔ)法:

simple_grammar = """
sentence => noun_phrase verb_phrase
noun_phrase => Article Adj* noun
Adj* => null | Adj Adj*
verb_phrase => verb noun_phrase
Article =>  一個(gè) | 這個(gè)
noun =>   女人 |  籃球 | 桌子 | 小貓
verb => 看著   |  坐在 |  聽(tīng)著 | 看見(jiàn)
Adj =>  藍(lán)色的 | 好看的 | 小小的
"""

上面的語(yǔ)法其實(shí)可以表示成一棵語(yǔ)法樹(shù)(Syntax Tree),對(duì)此感興趣的話可以參考以下文章:

語(yǔ)法說(shuō)明

  1. sentence => noun_phrase verb_phrase:表示一個(gè) sentencenoun_phraseverb_phrase 組成。
  2. Adj => 藍(lán)色的 | 好看的 | 小小的:表示 Adj 一共有 藍(lán)色的 | 好看的 | 小小的 3個(gè)選擇。

基于上面的兩條規(guī)說(shuō)明,我們就能夠讀懂上面的語(yǔ)法規(guī)則。

觀察上面的語(yǔ)法,我們可以發(fā)現(xiàn)一共有兩類(lèi)詞匯,左邊的詞匯是可以繼續(xù)拓展的,右邊的詞匯如果不在左邊,那么是不可拓展的。

我們先以adj為例,編寫(xiě)代碼。Adj語(yǔ)法如下:

adj_grammar = """
Adj* => null | Adj Adj*
Adj =>  藍(lán)色的 | 好看的 | 小小的

"""

根據(jù)上面的adj_grammar字符串語(yǔ)法規(guī)則,我們將其解析成字典格式:

# 解析語(yǔ)法
def create_grammar(grammar_str, split = '=>', line_split = '\n'):
    grammar = {}
    for line in grammar_str.split(line_split):
        if not line.strip():
            continue    # 跳過(guò)空行
        else:
            exp, stmt = line.split(split)
            grammar[exp.strip()] = [s.split() for s in stmt.split('|')]
    return grammar

結(jié)果如下:

接著我們?cè)賹⑸厦娴?code>simple_grammar語(yǔ)法規(guī)則解析成字典格式:

至此,我們已經(jīng)能夠使用代碼解析出上面的語(yǔ)法規(guī)則了。

生成句子

最后,我們編寫(xiě)代碼根據(jù)上面的語(yǔ)法規(guī)則,自動(dòng)生成句子:

# 生成句子
def generate(gram, target):
    if target not in gram:
        return target    # means target is a terminal expression
    # target in gram 意味著target是可以繼續(xù)拓展下去的
    else:
        expaned = [generate(gram, t) for t in random.choice(gram[target])]
        return ''.join([e if e!='/n' else '\n' for e in expaned if e != 'null'])

利用編寫(xiě)的代碼,隨機(jī)生成一個(gè)句子:

我們可以再定義兩個(gè)語(yǔ)法,看一下效果如何:

# 在西部世界里
# 一個(gè)”人類(lèi)“的語(yǔ)言可以定義為:

human = """
human = 自己 尋找 活動(dòng)
自己 = 我 | 俺 | 我們 
尋找 = 找找 | 想找點(diǎn) 
活動(dòng) = 樂(lè)子 | 玩的
"""


# 一個(gè)“接待員”的語(yǔ)言可以定義為

host = """
host = 寒暄 報(bào)數(shù) 詢問(wèn) 業(yè)務(wù)相關(guān) 結(jié)尾 
報(bào)數(shù) = 我是 數(shù)字 號(hào) ,
數(shù)字 = 單個(gè)數(shù)字 | 數(shù)字 單個(gè)數(shù)字 
單個(gè)數(shù)字 = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 
寒暄 = 稱(chēng)謂 打招呼 | 打招呼
稱(chēng)謂 = 人稱(chēng) ,
人稱(chēng) = 先生 | 女士 | 小朋友
打招呼 = 你好 | 您好 
詢問(wèn) = 請(qǐng)問(wèn)你要 | 您需要
業(yè)務(wù)相關(guān) = 玩玩 具體業(yè)務(wù)
玩玩 = null
具體業(yè)務(wù) = 喝酒 | 打牌 | 打獵 | 賭博
結(jié)尾 = 嗎?
"""

“人類(lèi)”和“接待員”各自隨機(jī)生成5個(gè)句子:

可以看到,我們已經(jīng)成功地通過(guò)自定義的語(yǔ)法規(guī)則來(lái)讓計(jì)算機(jī)自動(dòng)生成句子了。

小結(jié)

本文主要通過(guò)解析語(yǔ)法樹(shù),自動(dòng)生成句子等方法,實(shí)現(xiàn)了一個(gè)自動(dòng)生成句子的程序。

看完這篇文章,大家也可以設(shè)計(jì)實(shí)現(xiàn)自己的句子生成器。

上面生成了許多句子,但是,我們?nèi)绾闻袛嗄男┚渥痈鼮楹侠恚ǚ先祟?lèi)說(shuō)話習(xí)慣),哪些句子不合理?這時(shí)候就需要用到語(yǔ)言模型了,關(guān)于語(yǔ)言模型的相關(guān)概念及代碼實(shí)現(xiàn),將會(huì)在后面的文章講到,敬請(qǐng)期待。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容