内容
前回の修正と活用法、カウント表現を行ってみる。母音の並びを単語に見立てる部分で重複があったため、重複がないように修正する。その後は前回同様テキスト中の文章をバイナリ表現で表し、コサイン類似度の高いものを表示しようと思う。カウント表現についても同様に行ってみる。
修正点
frompykakasiimportkakasiimportreimportnumpyasnpimportpandasaspdimportitertoolswithopen("./test.txt","r",encoding="utf-8")asf:data=f.read()#単語リスト。母音のみ使ってできる2文字から4文字の単語。775種類
word_list2=[i[0]+i[1]foriinitertools.product("aiueo",repeat=2)]word_list3=[i[0]+i[1]+i[2]foriinitertools.product("aiueo",repeat=3)]word_list4=[i[0]+i[1]+i[2]+i[3]foriinitertools.product("aiueo",repeat=4)]word_list=word_list2+word_list3+word_list4text_data=re.split("\u3000|\n",data)kakasi=kakasi()kakasi.setMode('J','a')kakasi.setMode('H','a')kakasi.setMode('K','a')conv=kakasi.getConverter()vowel_text_list=[conv.do(d)fordintext_data]vowel_text_list=[re.sub(r"[^aeiou]+","",text)fortextinvowel_text_list]
itertools
を使用して単語リスト部の重複がでないようにした。活用法のコサイン類似度を調べる際にも、(0,1) と(1,0)を二回計算しないために使用した。itertools
バイナリ表現
df=pd.DataFrame({"文章":text_data,"母音":vowel_text_list})#カラム名"aa"等で、文章中に出現したら1、しなければ0
binali_dic={}temp=[]forwordinword_list:forvowelinvowel_text_list:ifwordinvowel:temp.append(1)else:temp.append(0)binali_dic[word]=temptemp=[]fork,vinbinali_dic.items():df[k]=v
3列目以降が"aa"等の単語に見立てた母音の並びが文章中に存在するかどうかを示している。
活用法
#コサイン類似度
defcosine_similarity(v1,v2):cos_sim=np.dot(v1,v2)/(np.linalg.norm(v1)*np.linalg.norm(v2))returncos_sim#dfのインデックスを渡して、共通母音を返す
defcommon_vowel(index1,index2):idx=df.iloc[index1,2:].values+df.iloc[index2,2:].valuesvowel_word=df.columns[2:]common_list=[vowel_word[i]foriinrange(len(idx))ifidx[i]==2]returncommon_list#コサイン類似度ランキング。リスト(インデックス,インデックス,cos_sim,共通母音リスト)
defcos_sim_ranking(df,threshold):ranking=[]idx=itertools.combinations(df.index,2)foriinidx:cos_sim=cosine_similarity(df.iloc[i[0]][2:].values,df.iloc[i[1]][2:].values)ifcos_sim>threshold:com_list=common_vowel(i[0],i[1])ranking.append((i[0],i[1],cos_sim,com_list))returnsorted(ranking,key=lambdax:-x[2])ranking=cos_sim_ranking(df,0.4)forrinranking:print(df["文章"][r[0]]+":"+df["文章"][r[1]])print("共通母音:{}".format(r[3]))print()
コサイン類似度の閾値(threshold:任意の値)以上のものを、類似度が高い順に、元の文章、共通する母音の並びを出力するようにした。元の文章を倒置法等を使って、文の頭や最後に共通母音を移動させれば韻を強調できる。
カウント表現
df=pd.DataFrame({"文章":text_data,"母音":vowel_text_list})#カラム名"aa"等で、値は出現回数
count_dic={}temp=[]forwordinword_list:forvowelinvowel_text_list:temp.append(vowel.count(word))count_dic[word]=temptemp=[]fork,vincount_dic.items():df[k]=v#dfのインデックスを渡して、共通母音、出現回数を返す
defcommon_vowel(index1,index2):idx=df.iloc[index1,2:].values+df.iloc[index2,2:].valuesvowel_word=df.columns[2:]common_list=[(vowel_word[i],idx[i])foriinrange(len(idx))ifidx[i]>=2]returncommon_list
データフレーム作成と、common_vowelで「出現回数」を加えて返すところが違う。出力結果は同じ閾値を使っても違う結果で、出現回数まで分かるカウント表現が良いと感じた。
まとめ
テストデータでの出力は十分満足いくものとなった。カウント2以上のものを共通母音としているが、それが一つの文章でカウント2になっているものもある。これはその文章自身で韻を踏めることを示していて、思わぬ収穫となった。当初もなるべく長い分のまま扱おうとしていたのだが、「その文自身で踏める韻」を捉えられないと思い断念した記憶がある。その後、どのように分割しようか悩んで、結局文章を分割せずに扱うことになったのがおもしろい。まあ、これまでやったことがダメというわけではなく、利点や欠点が実感できたので良かった。細かい修正点や改良点はあるかもしれないが、文章を「どんな母音の並びをもっているか」で表す方法に面白みを感じたので、一度「韻を扱いたい」は終了する。
今後やりたいこと
実際のラッパーの歌詞で、今回のカウント表現を行ってみて何か発見がないかを見ていきたい。