今回はあの
丹生ちゃんのタルタルチキンしりとりを
再現するプログラムを考えてみました。

解説動画はこちら



知らない人のために補足しておくと
日向坂46の丹生あかりちゃんには
なんかしらの言葉をしりとりで
タルタルチキンに繋げる・・・
という特技があります。

それをプログラムで再現します。

さて、今回のテーマはしりとりです。
しりとりをプログラムで行うには
単語のデータがないとうまくはいきません。

そこでMeacbの辞書を使って
しりとりを行えるような
プログラムを作っていきたいと思います。

Google Colab上で動くようなコードになってます。

まず最初はMecabをインストールします。
Mecabは形態素解析用のライブラリで
これには辞書が含まれています。

その辞書を使っていくわけですね。
GoogleColabにMecabをインストールするのは
次のコードです。
# MeCab と 辞書(mecab-ipadic-NEologd)のインストール 
!apt-get -q -y install sudo file mecab libmecab-dev mecab-ipadic-utf8 git curl python-mecab > /dev/null
!git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git > /dev/null 
!echo yes | mecab-ipadic-neologd/bin/install-mecab-ipadic-neologd -n > /dev/null 2>&1
!pip install mecab-python3 > /dev/null
!ln -s /etc/mecabrc /usr/local/etc/mecabrc
!echo `mecab-config --dicdir`"/mecab-ipadic-neologd"

インストールできたかどうか
確かめてみましょう。

次のコードで実行確認ができます。
# テスト
import MeCab
import random

sample_txt = "鬼滅の刃の炭次郎"
path = "-d /usr/lib/x86_64-linux-gnu/mecab/dic/mecab-ipadic-neologd"
m = MeCab.Tagger(path)
print("Mecab ipadic NEologd:\n",m.parse(sample_txt))
Mecab ipadic NEologd:
 鬼滅の刃 名詞,固有名詞,一般,*,*,*,鬼滅の刃,キメツノヤイバ,キメツノヤイバ
助詞,連体化,*,*,*,*,の,ノ,ノ
名詞,固有名詞,人名,姓,*,*,炭,タン,タン
次郎 名詞,固有名詞,人名,名,*,*,次郎,ジロウ,ジロー
EOS


いい感じで形態素解析出来ていますね。

形態素解析は文章を単語に分割しますが
辞書に無い固有名詞はより細かい単語に
分割されてしまいます。

この場合、「鬼滅の刃」がそれに当たります。
この辞書は「鬼滅の刃」が辞書登録されていますね。

この辞書データを使ってしりとり用の
辞書データを作っていきます。
# ここのパスは要チェック
dic_path = '/content/mecab-ipadic-neologd/build/mecab-ipadic-2.7.0-20070801-neologd-20200910/mecab-user-dict-seed.20200910.csv'
dic_data = {}
with open(dic_path) as _f:
    for i,row in enumerate(_f):
        rows = row.replace('\n','').split(',')
        word = rows[0]
        yomi = rows[11]
        hinsi = rows[4]
        
        # 品詞の分類
        if '記号' in m.parse(word[0]):
          continue
        # 名詞かつ ンやーでない 数字でもないものだけ登録
        if '名詞' in hinsi and len(yomi)>2 and 'ン'!=yomi[-1] and 'ー'!=yomi[-1] and not any([a.isnumeric() for a in word]):
          #print(rows)          
          s_word = yomi[0]
          e_word = yomi[-1]
          if s_word in dic_data:
            tmp_s = dic_data[s_word]
            if e_word in tmp_s:
              tmp_e = tmp_s[e_word]
              tmp_e.append({'word':word,'yomi':yomi})
            else:
              tmp_e = [{'word':word,'yomi':yomi}]
            tmp_s[e_word] = tmp_e
            dic_data[s_word] = tmp_s
          else:
            tmp_e = [{'word':word,'yomi':yomi}]
            dic_data[s_word] = {s_word:tmp_e}
これで辞書データが出来ました。
辞書のパスは変わる可能性があるので
うまく合わせてください。

次にしりとりを行う関数の定義です。

最初の単語を入力して
次の単語をしりとりとして
繋がるようなモノを選んで
最後の言葉につなげるようにします。
# 最初の終わりと最後のワードの始まりの文字
def word_b_and_e(target_word,last_word):
  targets = m.parse(target_word)
  targets = targets.replace('\nEOS\n','').split('\n')
  target_e = targets[-1].split(',')[-2][-1]
  lasts = m.parse(last_word)
  lasts = lasts.replace('\nEOS\n','').split('\n')
  lasts_s = lasts[0].split(',')[-2][0] if lasts[0].split(',')[-2]!='*' else lasts[0].replace('\t',',').split(',')[0][0]
  return target_e,lasts_s

# 次のワードを選択する
def nect_select(target_e):
  next_dic = dic_data[target_e]
  next_e_word = random.choice(list(next_dic.keys()))
  next_ends = next_dic[next_e_word]
  next_word_dic = random.choice(next_ends)
  return next_e_word,next_word_dic

# しりとり5
def siritori5(target_word,last_word):
  for a in range(10):
    try:
      words_route = [target_word]
      target_e , lasts_s = word_b_and_e(target_word,last_word)
      next_target = target_e
      for i in range(2):
        next_e_word , next_word_dic = nect_select(next_target)
        words_route.append('{0}({1})'.format(next_word_dic['word'],next_word_dic['yomi']))
        next_target = next_e_word

      lasts = random.choice(dic_data[next_target][lasts_s])
      words_route.append('{0}({1})'.format(lasts['word'],lasts['yomi']))
      words_route.append(last_word)
      for w in words_route:
        print(w)
      break
    except:
      pass

これでしりとりを行う準備が出来ました。

あとは実行です。
最初の単語と
最後につなげる単語を用意しておきます。


今回は始まりを「鬼滅の刃」
終わりを「タルタルチキン」にします。

結果はランダムで選ばれます。
# 実行
target_word = '鬼滅の刃'
last_word = 'タルタルチキン'
siritori5(target_word,last_word)
鬼滅の刃
バイエルン国立バレエ(バイエルンコクリツバレエ)
エドゥアードヴェジンヌ(エドゥアードヴェジンヌ)
沼尻健太(ヌマジリケンタ)
タルタルチキン

鬼滅の刃
馬簾水母(バレンクラゲ)
ゲッコウガ(ゲッコウガ)
ガジンフジタ(ガジンフジタ)
タルタルチキン

鬼滅の刃
vanellope(バネロペ)
ペドロバルボーザ(ペドロバルボーザ)
ザカリウス親方(ザカリウスオヤカタ)
タルタルチキン


・・・・

なんか聞いたことの無い単語ばかり

たまにまともな奴がでやりしますんで
試したい方は
何回もやり直してみて下さい。

今回は丹生ちゃんの
タルタルチキンしりとりを再現する
プログラムでした。

いやータルタルチキン
最高ですねーーー

今日はここまでです
それでは。