韻を扱いたいpart2

##__内容__
[前回](https://qiita.com/noliratina2/items/373ad7d8dfd832edcfde)入力データの分割方法に改良が必要なのでは？と感じたため、様々な分割方法を試してみる。入力データは前回同様某ラッパーの歌詞を使用。一応検証用として自分が温めていた韻をテーマにしたものも用意している。
##__分かち書きの場合__

```python
import MeCab

mecab = MeCab.Tagger("-Owakati")
mecab_text = mecab.parse(data).split()
```

歌詞通りの「韻」を抽出できている部分もあるが、「数万円」で踏んでいるところが分かち書きによって「数、万、円」と分割されているため認識できていない。余談だが、`kakashi`の`conv.do`に一度に多くのデータは渡せないようだ。`text_data = [conv.do(text) for text in mecab_text]`とした。ちなみに分かち書き後、母音に変換したwordの長さは最大8文字、平均2.16文字であった。細かく分け過ぎているので、分かち書きでの分割は適していないと言える。
~~このMeCabを使えるようにするまでに何回も挫けた。色んな記事を見過ぎたのかもしれない。[こちら](https://qiita.com/yukinoi/items/990b6933d9f21ba0fb43)に感謝~~
##__N-gramの場合__
では、単にN文字ごとに分割していくとどうなるだろう。Nは４から試してみる。

```python
def make_ngram(words, N):
    ngram = []
    for i in range(len(words)-N+1):
        #全角スペースと改行を取り除く
        row = "".join(words[i:i+N]).replace("\u3000","").replace("\n","")
        ngram.append(row)
    return ngram

```

体感だが、Nは５かそれ以上が良さそうである。（４以下だとスコアの差が付かない）そこそこ歌詞通りに韻を検出できている。試しに検証用データを入れてみると、一見気づかない韻が検出できた。wordが様々な切り取られ方をするのだから、スコアの付け方を変えてみる。

```python
def make_score_ngram(word_a, word_b):
    score = 0
    for i in range(len(word_a)):
        if word_a[-i:] == word_b[-i:]:
            score += i
     return score
```

母音の一致を語尾から見ることによって、出力が見やすい。Nの値については`len(target_word_vo)`(韻を探す元の言葉の母音の長さ)が良いだろう。自分がやりたいことが表現できてしまったような気がしている。
折角苦労してMeCabを使用できるようにして、「韻の数値化」も自分なりに考えたので、使いたい。この２つを組み合わせてみる。
##__target_wordが絞れるのでは？！__
「韻の数値化」では母音が合致する部分を探索し、合致している長さ`len(word[i:j)`をスコアにしていた。この`word[i:j]`は「eoi」等の形をしており、この出現回数をカウントすれば、入力データ中で一番登場する母音が分かるはずだ。それを含む言葉を`target_word`に指定すれば、多くのレコメンドが見込めるという考えである。申し訳程度に分かち書きと検証用に用意したテキストを使う。

```python
from pykakasi import kakasi
import re
from collections import defaultdict
import MeCab

with open("./test.txt","r",encoding="utf-8") as f:
    data = f.read()

mecab = MeCab.Tagger("-Owakati")
mecab_text = mecab.parse(data).split()

kakasi = kakasi()

kakasi.setMode('H', 'a')
kakasi.setMode('K', 'a')
kakasi.setMode('J', 'a')

conv = kakasi.getConverter()
text_data = [conv.do(text) for text in mecab_text]
vowel_data = [re.sub(r"[^aeiou]+","",text) for text in text_data]
dic_vo = {k:v for k,v in enumerate(vowel_data)}
#voel_dataのインデックスで母音変換前のdataが分かるように辞書作成。
dic = {k:v for k,v in enumerate(mecab_text)}

#新たなキーを追加する際に初期化を省きたいためdefaultdictを使用{母音:出現回数}
dic_rhyme = defaultdict(int)
for word_a in vowel_data:
    for word_b in vowel_data:
        if len(word_a) > len(word_b):
            word_len = len(word_b)
            for i in range(word_len):
                for j in range(word_len + 1):
                    #カウントするのは２文字以上に限定
                    if word_b[i:j] in word_a and not len(word_b[i:j])<2:
                        dic_rhyme[word_b[i:j]] +=　1
        else:
            word_len = len(word_a)
            for i in range(word_len):
                for j in range(word_len + 1):
                    if word_a[i:j] in word_b and not len(word_a[i:j])<2:
                        dic_rhyme[word_a[i:j]] += 1
#カウントが多かった順にソート
dic_rhyme = sorted(dic_rhyme.items(), key=lambda x:x[1], reverse=True)
print(dic_rhyme)
#dic_rhymeの上位にきたものが含まれているものを探索。ここでは"ai"を使用
bool_index = ["ai" in text for text in vowel_data]

for i in range(len(vowel_data)):
    if bool_index[i]:
        print(dic[i])
```

登場頻度の高い母音の並びを取得し、どこで使われているか出力できた。しかしながら、分かち書きで細分化された言葉は分かりにくくなっていた。もしかしたら、もう少し長い韻があった可能性もある。
##__改良点__
target_wordを絞るという用途では必要性を感じないが（自分が一番言いたいことを指定したいため）、どの母音の並びが頻出なのかは確認できても良いかもしれない。分かち書きで上手くいかなかったが、MeCabを利用して（~~何度もいうが、使えるようになるまで四苦八苦した~~）改良したい。
また、N-gramを採用したことによって「韻の数値化」も簡潔にできたので、もう少し複雑に「韻」を定義し直せないか考える。（現状「っ」など考慮していない）
しかし、回り道をした。「韻の数値化」は韻を漏らさないよう、入力データに対応できるよう、自分なりに考え抜いたつもりのものだ。まさか引数を様々にスライスすることが入力データを様々にスライス（表現が違うかもしれません）で解決できるとは…というかそれに気付かないとは。基本が大事ですね。でもN-gramって意味のない日本語が出来ると感じませんか？ただ、「韻」の部分を強調して発音する等やり方はあるんです。やはり、簡単なデータ使ってとにかくやってみることが大事ってことですわ。