自作で対話システム作成日記:日付を返す処理の実装

背景

  • 自然言語処理の研究を学生時代行っていたが,形態素解析の辞書作成と基礎よりだった.
  • 応用部分の一分野である対話システムをやってみたいと思った.

やったこと

  • Python で今日,明日,昨日の日付を聞くと返してくれるプログラムの作成
  • 上記の日付以外については答えられないと返答するようにした.ただ,少しの入力文でしか確認していないので100%ではない.

処理概要

  • 「今日に日時は?」,「明日の日時は?」,「昨日の日時は?」の三つそれぞれを形態素解析し分散表現に変換
  • 分散表現への変換
  • 内容語だけ取り出す
  • 取り出した語の分散表現を足し合わせる
  • 取り出した内容後の数で割る
  • 入力文を分散表現に変換
  • 入力文の分散表現と作成した三つの分散表現の誤差を求める
    • 誤差の求め方
      • 入力文と三つの文とで各次元の値の差の絶対値の合計を求める
      • 求めた合計値を次元数で割る
  • 最も入力文との誤差が小さかった文のタスクを実行
    • ただし,誤差が閾値を超えた場合には実行しない
    • 閾値は,今回人手で決めたので改善したい

コード

from gensim.models import word2vec, KeyedVectors
from gensim.models.wrappers import FastText
from janome.tokenizer import Tokenizer
import numpy as np
import datetime

def sum_vec_error(A, B):
    result = 0
    for a, b in zip(A, B):
        #print(a,b)
        x = abs(a-b)
        #print(x)
        result += x

    result = result / A.shape[0]

    return result

def sentense_ave_vec(sentense):
    cnt_sentense = 0
    vec_sentence = np.zeros_like(w2v_model.wv['今日'])


    for token in tokenizer.tokenize(sentense):
        #print(token.surface)
        #print(w2v_model[token.surface])
        if token.part_of_speech.split(',')[0] in ['名詞', '動詞', '形容詞','形容動詞','副詞']:
            cnt_sentense += 1
            vec_sentence += w2v_model.wv[token.surface]

    vec_sentence = vec_sentence / cnt_sentense

    return vec_sentence


if __name__ == '__main__':
    # しろやぎコーポレーションが公開してくれている分散表現
    #w2v_model = word2vec.Word2Vec.load('data/latest-ja-word2vec-gensim-model/word2vec.gensim.model')
    # fatstext 読み込みに10分程度かかる
    w2v_model = KeyedVectors.load_word2vec_format('data/cc.ja.300.vec')

    #print(w2v_model['今日'])

    tokenizer = Tokenizer()

    while True:
        #input_sentense = '本日の日付は?'
        input_sentense = input('御用は何でしょうか?:')
        input_sentense = str(input_sentense)
        #print(input_sentense)
        #input_sentense = [input_sentense]
        input_sentense_ave_vec = sentense_ave_vec(input_sentense)

        sentenses = ['今日の日付は?','明日の日付は?','昨日の日付は?']
        list_sentenses_error = []

        for sentense in sentenses:
            sav = sentense_ave_vec(sentense)
            list_sentenses_error.append(sum_vec_error(input_sentense_ave_vec, sav))

        #print(list_sentenses_error)


        #返答
        min_sum_vec_error = min(list_sentenses_error)
        #print(min_sum_vec_error)
        min_sum_vec_error_index = list_sentenses_error.index(min_sum_vec_error)

        if min_sum_vec_error < 0.04: #閾値は人手なので改善の余地あり
            if sentenses[min_sum_vec_error_index] == sentenses[0]:
                now = datetime.datetime.now()
                print(now.strftime('%Y/%m/%d です'))
                exit
            elif sentenses[min_sum_vec_error_index] == sentenses[1]:
                now = datetime.datetime.now()
                yesterday = now + datetime.timedelta(days=1)
                print(yesterday.strftime('%Y/%m/%d です'))
                exit
            elif sentenses[min_sum_vec_error_index] == sentenses[2]:
                now = datetime.datetime.now()
                tommorow = now - datetime.timedelta(days=1)
                print(yesterday.strftime('%Y/%m/%d です'))
                exit
        else:
            print('お答えできません')