自然言語処理ハンズオン【MeCab, word2vec】文章から食材を自動抽出

自然言語処理でよく使われるライブラリ、
MeCabとWord2vecについて、とりあえず動かせるようになれる記事です。

# 目次
[1.今回のゴール](#1-今回のゴール)
[2.進め方](#2-進め方)
[3.Mecabとは](#3-mecabとは)
[4.word2vec：短い単語から検出](#4-word2vec短い単語から検出)
[5.実践：長文から検出](#5-実践長文から検出)

## 1. 今回のゴール
・ゴール1
短い文章からフルーツらしい単語を検出します。
・ゴール2
長文での実践として、wikipediaのカレーの説明文から食材を抽出します。

## 2. 進め方
Google colabratoryにてハンズオンで体験していきましょう！
https://colab.research.google.com/drive/1V1VUhmnsGGib56pySZrhlBRBJSIzSPgS?usp=sharing
![スクリーンショット 2022-11-22 13.03.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499988/a50653ad-b5a7-485c-afce-044c62d1d910.png)

## 3. Mecabとは
文章を単語に分けるライブラリです。
たとえば、、
"私はオレンジとバナナを作っている農家です。"
という文章を単語に分けることができます。分かち書きと呼びます。
~~~python:code
#Wikipediaの文章をMeCabで分かち書きする 
tagger = MeCab.Tagger()  
tagger = MeCab.Tagger("-Owakati")
sample_txt = "私はオレンジとバナナを作っている農家です。"
words_list=list(tagger.parse(sample_txt).split())
words_list
~~~
~~~out:out
['私', 'は', 'オレンジ', 'と', 'バナナ', 'を', '作っ', 'て', 'いる', '農家', 'です', '。']
~~~
さらに詳しく解析もできます。形態素解析と呼んだりします。
~~~python:code
#詳しい分析もできます 。
tagger1 = MeCab.Tagger()  
sample_txt = "私はオレンジとバナナを作っている農家です。"
tagger1.parse(sample_txt).split()
~~~
~~~out:out
['私','代名詞,,,,,,ワタクシ,私-代名詞,私,ワタクシ,私,ワタクシ,和,"","","","","","",体,ワタクシ,ワタクシ,ワタクシ,ワタクシ,"0","","",11345327978324480,41274',

'は', '助詞,係助詞,,,,,ハ,は,は,ワ,は,ワ,和,"","","","","","",係助,ハ,ハ,ハ,ハ,"","動詞%F2@0,名詞%F1,形容詞%F2@-1","",8059703733133824,29321',

'オレンジ','名詞,普通名詞,一般,,,,オレンジ,オレンジ-orange,オレンジ,オレンジ,オレンジ,オレンジ,外,"","","","","","",体,オレンジ,オレンジ,オレンジ,オレンジ,"2","C1","",1477202495545856,5374',
~~~
# 4. word2vec：短い単語から検出
単語同士の類似度を算出できるライブラリです。
「ワードtoベクトル」の略で、単語をベクトル化する技術です。

先ほど作成した単語リスト
['私', 'は', 'オレンジ', 'と', 'バナナ', 'を', '作っ', 'て', 'いる', '農家', 'です', '。']
からフルーツを抽出するために、それぞれの単語と「フルーツ」との類似度を計算します。

~~~python:code
#分かち書きした文章から 、word2vecでフルーツを抽出
for word in words_list:
  try:
    sim = word2vec_model.similarity("フルーツ", word)
    print(word,":",round(sim*100,2),"%")
  except (KeyError) :
    pass
~~~
~~~out:out
私 : 29.79 %
は : 27.44 %
オレンジ : 51.46 %
と : 29.47 %
バナナ : 69.16 %
を : 23.89 %
て : 28.42 %
いる : 17.57 %
農家 : 26.12 %
です : 30.46 %
。 : 22.53 %
~~~
オレンジとバナナの数値が高く、いい感じに計算されています。

MeCabとWord2vecが使えるようになったところで、2つ目のゴールの、カレーの説明文からの食材抽出を行いましょう！
# 5. 実践：長文から検出
まずはMeCabで分かち書きをします。
~~~python:code
#Wikipediaの文章をMeCabで分かち書きする 
tagger = MeCab.Tagger()  
tagger = MeCab.Tagger("-Owakati")
sample_txt1 = "日本にカレーが伝えられたのは1868年で、イギリスの商船が既成のカレー粉を持ち込んだのが始まりとされている[15]。その後1872年には仮名垣魯文によって編纂された『西洋料理通』が出版され、カレーレシピが紹介されることで広く浸透した[15]。定着の理由としては時代背景として肉食の奨励とともに西洋文化の取り込み・吸収に貪欲であったことに加え、野菜、肉、米をまとめて摂取可能な上に安上がりで食べ応えがあったことが挙げられている[16]。イギリスから伝わったものに小麦粉を加えたとろみのあるカレーを米飯（ライス）の上に掛けて食する「カレーライス」が普及しており、それぞれの地域や家庭、店舗等によって様々にアレンジされたカレーが存在する。スープ状のカレーや、カレー味のスープはスープカレーと呼ばれ、ハウス食品のレシピの例では、使用される具材は固形カレーの素、タマネギ、ロースハム、キャベツ、サラダ油、水、塩、胡椒である。グリーンカレーの名で販売する店舗もあり、インドの地方やタイのカレーは同様のカレーと呼ぶがスープ状の物であり、スープ状である事からカレースープと呼ぶ人もいる[17]。「カレー」と称しているがスープの店もある[18]。日清食品からカップのグリーンカレーのスープも販売されている。地元産素材を使う地域の町おこしとして売り出される例もみられる[19][20]。そのほかにも、日本独自のカレー料理（食品）は多く、カレー南蛮（カレー味の汁をかけたかけそば）などの麺類、ドライカレー、カレーまん、カレーパン、カレーコロッケなどがある。カレー味に調味したスナック菓子も多い。"
words_list1 = list(tagger.parse(sample_txt1).split()) #10単語だけ出力 
words_list1[:10]
~~~
~~~out:out
['日本', 'に', 'カレー', 'が', '伝え', 'られ', 'た', 'の', 'は', '1868'　……………..]
~~~
ここからWord2vecで「食材」に似ている単語を算出しましょう。
類似度が40%を超える単語に絞り込みます。
~~~python:code
#word2vecで分かち書きした文章から 、食材っぽいものを抽出
dump=[]
for word in words_list1:
  try:
    sim = word2vec_model.similarity("食材", word) #40 ％以上似ている単語に絞り込み
    if sim>0.4 and word not in dump:
      print(word,":",round(sim*100,2),"%")
    dump.append(word)
  except (KeyError) :
    pass
~~~
~~~out:out
カレー : 46.41 %
料理 : 70.61 %
レシピ : 50.2 %
野菜 : 71.45 %
肉 : 56.63 %
米飯 : 50.51 %
食する : 56.85 %
スープ : 47.82 %
味 : 43.54 %
食品 : 64.6 %
具材 : 63.38 %
キャベツ : 45.0 %
サラダ : 49.03 %
麺類 : 56.03 %
パン : 43.74 %
コロッケ : 41.91 %
調味 : 58.45 %
菓子 : 45.06 %
~~~

まずまず絞り込めてますが、微妙なものも入ってますね。
さらに「炭水化物」に似ているものに絞り込みましょう。
~~~python:code
#「食材」に加えて「炭水化物」でも絞り込んでみる
dump,dump2=[],[]
for word in words_list1:
  try:
    sim = word2vec_model.similarity("食材", word) #40 ％以上似ている単語に絞り込み
    if sim>0.4 and word not in dump:
      dump2.append(word)
    dump.append(word)
  except (KeyError) :
    pass
dump=[]
for word in dump2:
  try:
    sim = word2vec_model.similarity("炭水化物", word) #30 ％以上似ている単語に絞り込み
    if sim>0.3 and word not in dump:
      print(word,":",round(sim*100,2),"%")
    dump.append(word)
  except (KeyError) :
    pass
~~~
~~~:out
カレー : 31.18 %
野菜 : 44.94 %
肉 : 41.86 %
米飯 : 47.58 %
食する : 41.55 %
スープ : 37.43 %
食品 : 45.93 %
具材 : 35.5 %
キャベツ : 42.3 %
サラダ : 36.51 %
麺類 : 57.34 %
パン : 36.41 %
コロッケ : 30.61 %
調味 : 32.49 %
菓子 : 32.42 %
~~~
「料理、レシピ、味」が消されて少し、理想に近づきました。
まだ改善の余地はありますが、今回はここまでにしようと思います。
お時間あれば色々と試して精度を上げてみてください。



使用したモデル：
https://github.com/WorksApplications/chiVe