TPTブログ

テックポート株式会社のブログです。 技術情報や製品・サービス情報、 また未経験社員がデータサイエンティストを 目指す奮闘記など、更新していきます。

▲心くじけず言語処理100本ノック==30~34==

f:id:TBT_matsu:20200515145048p:plain
こんにちは!
テービーテックの村松です。

「言語処理100本ノック2020]」
nlp100.github.io
に挑戦中!
途中でくじけないか見守ってください・・・。
そして、皆さんも一緒に挑戦してみましょう!

本日は第4章:形態素解析 30~34です!
間違い・コード改善点などありましたら教えていただけると嬉しいです。

4章:形態素解析

「夏目漱石の小説『吾輩は猫である』の文章をMeCabを使って形態素解析し,その結果をneko.txt.mecabというファイルに保存せよ.このファイルを用いて,以下の問に対応するプログラムを実装せよ. なお,問題37, 38, 39はmatplotlibもしくはGnuplotを用いるとよい.」
ここからはneko.txtを使用して問題に取り組んでいきます。

下準備

コマンド操作でやる場合は、

mecab < ch04/neko.txt > ch04/neko.txt.mecab

で済むようですが、せっかくGoogleColabでこれまでやってきましたのでMeCab.Tagger()の使い方を確認する意味も込めて形態素解析を行っていこうと思います。

  • MeCabのインストール(GoogleColaboratoryの場合)2020/05/28現在
!apt install aptitude
!aptitude install mecab libmecab-dev mecab-ipadic-utf8 git make curl xz-utils file -y
!pip install mecab-python3==0.7
  • ファイルの読み込み~形態素解析
import MeCab
file_path = 'ファイル保存先/neko.txt'
#空のリストの用意
m_list = []
#テキストデータの読み込み
with open(file_path) as f:
  text_list = f.read()
  #改行で切り分けて各行ごとに形態素解析を行います。
  for i in text_list.split('\n'):
    mecab = MeCab.Tagger('mecab-ipadic-neologd').parse(i)
    #用意したm_listに格納します。
    m_list.append(mecab)
  print(m_list[2])
##結果
 	記号,空白,*,*,*,*, , , 
吾輩	名詞,代名詞,一般,*,*,*,吾輩,ワガハイ,ワガハイ
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
猫	名詞,一般,*,*,*,*,猫,ネコ,ネコ
で	助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ
ある	助動詞,*,*,*,五段・ラ行アル,基本形,ある,アル,アル
。	記号,句点,*,*,*,*,。,。,。
EOS

課題にはこの「m_list」を使用しても良いと思いますが、
「MeCabを使って形態素解析し,その結果をneko.txt.mecabというファイルに保存せよ」とあるので一応それに沿って一回書き出しを行います。

  • neko.txt.mecabへ書き出し
path_w = 'ファイルの保存先/neko.txt.mecab'
#リスト型を書き込むのでwritelines()を使用します。
with open(path_w, mode='w') as f:
  f.writelines(m_list)

はい。
これで下準備は終了です。
練習にはなりましたがスマートではないですね・・・。
気を取り直して課題に進みましょう。

30.形態素解析結果の読み込み

「形態素解析結果(neko.txt.mecab)を読み込むプログラムを実装せよ.ただし,各形態素は表層形(surface),基本形(base),品詞(pos),品詞細分類1(pos1)をキーとするマッピング型に格納し,1文を形態素(マッピング型)のリストとして表現せよ.第4章の残りの問題では,ここで作ったプログラムを活用せよ.」

#テキストデータの読み込み
#「EOS\n」を目印に文ごとに区切ってリストに格納
import re
with open(path_w) as f:
  _data = re.split('EOS\n', f.read())
#形態素解析の結果ごと(改行\n)で区切りつつ、
#空のリストは排除していきます。
data = []
for i in _data:
  if len(i) == 0:
    continue
  else:
    _s = re.split('\n', i)
    data.append(_s)
data

##結果
[['一\t名詞,数,*,*,*,*,一,イチ,イチ', ''],
 ['\u3000\t記号,空白,*,*,*,*,\u3000,\u3000,\u3000',
  '吾輩\t名詞,代名詞,一般,*,*,*,吾輩,ワガハイ,ワガハイ',
  'は\t助詞,係助詞,*,*,*,*,は,ハ,ワ',
  '猫\t名詞,一般,*,*,*,*,猫,ネコ,ネコ',
  'で\t助動詞,*,*,*,特殊・ダ,連用形,だ,デ,デ',
  'ある\t助動詞,*,*,*,五段・ラ行アル,基本形,ある,アル,アル',
  '。\t記号,句点,*,*,*,*,。,。,。',
  ''],
・・・以下略

形態素解析の結果の並びはこのようになっています。
「表層形\t品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用型,活用形,原形,読み,発音」

今回課題で使用する要素は、
表層(surface):リスト[0]番目
基本計(base):リスト[7]番目
品詞(pos):リスト[1]番目
品詞細分類1(pos1):リスト[2]番目
となりますので、これらを辞書型に格納していきます。

#辞書への格納
dicts = []
for i in s:
  _dicts = []
  for h in i:
    if len(h) == 0:
      pass
    else:
      _d = re.split('[\t|,]', h)
      d = dict(surface=_d[0], base=_d[7], pos=_d[1], pos1=_d[2])
      _dicts.append(d)
  dicts.append(_dicts)
dicts

##結果
[[{'base': '一', 'pos': '名詞', 'pos1': '数', 'surface': '一'}],
 [{'base': '\u3000', 'pos': '記号', 'pos1': '空白', 'surface': '\u3000'},
  {'base': '吾輩', 'pos': '名詞', 'pos1': '代名詞', 'surface': '吾輩'},
  {'base': 'は', 'pos': '助詞', 'pos1': '係助詞', 'surface': 'は'},
  {'base': '猫', 'pos': '名詞', 'pos1': '一般', 'surface': '猫'},
  {'base': 'だ', 'pos': '助動詞', 'pos1': '*', 'surface': 'で'},
・・・以下略

以降の課題にはここで作った「dicts」を使用します。

31.動詞

「動詞の表層形をすべて抽出せよ.」

ans_surface = []
for dict_ in dicts:
  #filter()を使用して条件に合った表層形(surface)を取り出します。
  verb_list = list(filter(lambda a: a['pos'] == '動詞', dict_))
  for n in verb_list:
    ans_surface.append(n['surface'])
print(ans_surface)
##結果
['生れ', 'つか', 'し', '泣い', 'し', 'いる', '始め', '見', '聞く', '捕え',・・・以下略
32.動詞の原形

「動詞の原形をすべて抽出せよ.」
31とほぼ同じです。

ans_base = []
for dict_ in dicts:
  verb_list = list(filter(lambda a: a['pos'] == '動詞', dict_))
  for n in verb_list:
    ans_base.append(n['base'])
print(ans_base)
##結果
['生れる', 'つく', 'する', '泣く', 'する', 'いる', '始める', '見る', '聞く', ・・・以下略
33.「AのB」

「2つの名詞が「の」で連結されている名詞句を抽出せよ.」

ans_noun = []
for dict_ in dicts:
  for n in range(1, len(dict_)-1):
    #「名詞」+「の」+「名詞」という並びのものを探します。
    if dict_[n-1]['pos'] == '名詞' and dict_[n]['base'] == 'の' and dict_[n+1]['pos'] == '名詞':
      #該当する表層形を繋げます。
      ans_noun.append(dict_[n-1]['surface'] + dict_[n]['surface'] + dict_[n + 1]['surface'])
##結果
['彼の掌', '掌の上', '書生の顔', 'はずの顔', '顔の真中', '穴の中', '書生の掌',・・・以下略
34.名詞の連接

「名詞の連接(連続して出現する名詞)を最長一致で抽出せよ.」

ans_nn = []
n_list = []
for dict_ in dicts:
  for n in range(len(dict_)):
    #形態素が名詞の場合、n_listに格納します。
    if dict_[n]['pos'] == '名詞':
      n_list.append(dict_[n]['surface'])
    #それ以外の時はn_listの中身の数を確認して2つ以上ならans_nnに格納します。
    elif len(n_list) >= 2:
      ans_nn.append(n_list)
      #n_listを空に戻します。
      n_list = []
    else:
      #n_listを空に戻します。
      n_list = []
print(ans_nn)
##結果
[['人間', '中'], ['一番', '獰悪'], ['時', '妙'], ['一', '毛'], ['その後', '猫'], ['一', '度'], ・・・以下略


ここまでご覧いただきありがとうございます。
以上、第4章30~34でした!