乙Py先生のプログラミング教室
初学者のためのプログラミング学習サイト

Mecab

さて今回は辞書データを調べて
日本語の単語の数がどうなっているかを
調べてみました。

解説動画はこちら



さて今回使用する辞書データは
こちらのものです
naist-jdic.csv(Mecab用の辞書データ)
(奈良先端科学技術大学院大学 : Nara Institute of Science and Technology)

調べたい方は検索してみてください。

早速これを読み込みします。

import pandas as pd
import codecs

tmp = codecs.open('naist-jdic.csv', 'r', 'euc_jp', 'ignore')
df = pd.read_csv(tmp)
df.shape
(485862, 16)


48万行ほどあるので
結構な数の単語が載っていますね。

1文字目を取り出して集計してみます。
df['行'] = df[' .2'].str[0:1]
df2 = pd.DataFrame(df['行'].value_counts())

for i , row in df2[df2['行']>=10].iterrows():
    print(i,row['行'])
カ 30723
シ 25156
オ 23427
ア 18293
ト 17947
・・・

「か」で始まる単語が多そうですね。

次はこれを行で数えてみます。

dc1={
    'ア':['ア','イ','ウ','エ','オ','ヴ'],
    'カ':['カ','キ','ク','ケ','コ','ガ','ギ','グ','ゲ','ゴ'],
    'サ':['サ','シ','ス','セ','ソ','ザ','ジ','ズ','ゼ','ゾ'],
    'タ':['タ','チ','ツ','テ','ト','ダ','ヂ','ヅ','デ','ド','ッ'],
    'ナ':['ナ','ニ','ヌ','ネ','ノ'],
    'ハ':['ハ','ヒ','フ','ヘ','ホ','バ','ビ','ブ','ベ','ボ','パ','ピ','プ','ペ','ポ'],
    'マ':['マ','ミ','ム','メ','モ'],
    'ヤ':['ヤ','ユ','ヨ','',''],
    'ラ':['ラ','リ','ル','レ','ロ'],
    'ワ':['ワ','ヲ','ン']}
dc2 = {k:{v2:0 for v2 in v} for k,v in dc1.items() }
for i , row in df2[df2['行']>=10].iterrows():
    for k,v in dc2.items():
        if i in v:
            dc2[k][i]=row['行']
            break
for k,v in dc2.items():
    print(k,sum([v2 for k2 , v2 in v.items()]))

結果は・・・

ア 77966
カ 88527
サ 72447
タ 69555
ナ 35274
ハ 65386
マ 41391
ヤ 22425
ラ 7263
ワ 5477

カ行の単語が一番多く
次いでア行、サ行でした。

前半の方に単語が多く載っていそうです。

ラ行やワ行の言葉は
かなり少ないですね。

何でこんなに偏るのか
日本語の成り立ちが気になっちゃいました。

今回は辞書データを調べて
どの行の単語が多いのか
調べてみました。

それでは。

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

解説動画はこちら



知らない人のために補足しておくと
日向坂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(バネロペ)
ペドロバルボーザ(ペドロバルボーザ)
ザカリウス親方(ザカリウスオヤカタ)
タルタルチキン


・・・・

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

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

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

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

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


このページのトップヘ