機械学習 マルコフ連鎖

import MeCab
import os,json,random

dict_file = "markov_dict.json"
dic = {}

# 辞書への登録 --- (*1)
def regist_dic(wordlist):
    global dic
    w1 = ""
    w2 = ""
    
    # 要素が3未満の場合は、何もしない
    if len(wordlist) < 3 : return
    
    for w in wordlist :
        word = w[0]
        if word == "" or  word == "\r\n" or word == "\n" : continue
        # 辞書に単語を設定
        if w1 and w2 :
            set_dic(dic,w1, w2, word)
        # 文末を表す語のの場合、連鎖をクリアする
        if word == "。" or word == "?" or  word == "?" :
            w1 = ""
            w2 = ""
            continue
        # 次の前後関係を登録するために、単語をスライド
        w1, w2 = w2, word
    
    # 辞書を保存
    json.dump(dic, open(dict_file,"w", encoding="utf-8"))

# 辞書に単語を設定 --- (*2)
def set_dic(dic, w1, w2, w3):
    # 新しい単語の場合は、新しい辞書オブジェクトを作成
    if w1 not in dic : dic[w1] = {}
    if w2 not in dic[w1] : dic[w1][w2] = {}
    if w3 not in dic[w1][w2]: dic[w1][w2][w3] = 0
    # 単語の出現数をインクリメントする
    dic[w1][w2][w3] += 1

# 応答文の作成 --- (*3)
def make_response(word):
    res = []
    
    # 「名詞」/「形容詞」/「動詞」は、文章の意図を示していることが多いと想定し、始点の単語とする。
    w1 = word
    res.append(w1)
    w2 = word_choice(dic[w1])
    res.append(w2)
    while True:
        # w1,w2の組み合わせから予想される、単語を選択
        if w1 in dic and w2 in dic[w1] : w3 = word_choice(dic[w1][w2])
        else : w3 = ""
        res.append(w3)
        # 文末を表す語の場合、作文を終了
        if w3 == "。" or w3 == "?" or  w3 == "?"  or w3 == "" :  break
        # 次の単語を選択するために、単語をスライド
        w1, w2 = w2, w3
    return "".join(res)
        
def word_choice(candidate):
    keys = candidate.keys()
    return random.choice(list(keys))

# メイン処理 --- (*4)

# 辞書がすでに存在する場合は、最初に読み込む
if os.path.exists(dict_file):
        dic = json.load(open(dict_file,"r"))
        
while True:
    # 標準入力から入力を受け付け、「さようなら」が入力されるまで続ける
    text = input("You -> ")
    if text == "" or text == "さようなら" : 
        print("Bot -> さようなら")
        break

    # 文章整形
    if text[-1] != "。" and text[-1] != "?" and text[-1] != "?" : text +="。"
    
    # 形態素解析
    tagger = MeCab.Tagger("-r /etc/mecabrc -d /var/lib/mecab/dic/ipadic-utf8")
    tagger.parse("") 
    node =  tagger.parseToNode(text)
    
    # 形態素解析の結果から、単語と品詞情報を抽出
    wordlist = []
    while node is not None:
        hinshi = node.feature.split(",")[0]
        if  hinshi not  in ["BOS/EOS"]:
            wordlist.append([node.surface,hinshi])
        node = node.next
    
    # マルコフ連鎖の辞書に登録
    regist_dic(wordlist)

    # 応答文の作成
    for w in wordlist:
        word = w[0]
        hinshi = w[1]
        # 品詞が「感動詞」の場合は、単語をそのまま返す
        if hinshi in [ "感動詞"] : 
            print("Bot -> " + word)
            break
        # 品詞が「名詞」「形容詞」「動詞」の場合で、かつ、辞書に単語が存在する場合は、作文して返す
        elif (hinshi in [ "名詞" ,"形容詞","動詞"]) and (word in dic):
            print("Bot -> " + make_response(word))
            break
You -> もしもし
Bot -> もしもし
You -> もしもし
Bot -> もしもし
You -> いちごとメロンはどちらが好きですか?
Bot -> いちごもメロンも好きですか?
You -> いいえ、私はいちごが好きです。
Bot -> いいえ
You -> あなたはいちごとメロンはどちらが好きですか?
Bot -> あなたはいちごが好きですか?
You -> はい、いちごが好きです。
Bot -> はい
You -> あなたはどちらが好きですか?
Bot -> あなたはどちらが好きですか?
You -> どっち?
You -> もしもし
Bot -> もしもし
You -> いちごとメロンどっちが好き?
Bot -> いちごはどうですか?
You -> 私はいちごが好きです。あなたはメロンが好きですか?
Bot -> 私はいちごは好きです。
You -> あなたはいちごが好きなんですね。
Bot -> あなたはいちごが好きな果物は?
You -> いちご以外だと、りんごが好きです。
Bot -> いちごは好きです。
You -> あなたはいちごが好きなんですね。りんごも好きですか?
Bot -> あなたはメロンが好き?
You -> いいえ、メロンは好きではありません。
Bot -> いいえ
You -> メロンは好きではないです。
Bot -> メロンも好きです。
You -> あなたはメロンも好きなんですね。
Bot -> あなたはいちごが好き?
You -> いちご好きです。りんごも好きです。
Bot -> いちごとメロンのどちらが好きですか?
You -> いちごが好きです。
Bot -> いちご好きです。
You -> りんごは好きですか?
Bot -> りんごは好きです。
You -> ありがとう
Bot -> ありがとう
Wikipedia
青空文庫 Aozora Bunko
ダウンロード - 株式会社ロンウイット
DOWNLOADS
KWDLC - LANGUAGE MEDIA PROCESSING LAB
FrontPage - PukiWiki
タイトルとURLをコピーしました