言語処理100本ノック 2020「40. 係り受け解析結果の読み込み(形態素)」
問題文
問題の概要
本章では、CaboChaを用いて係り受け解析した結果を読み込んでいきます。手始めに、以下コマンドでファイルに対して係り受け解析を実行しましょう。
cat ch05/ai.ja/ai.ja.txt | cabocha -f1 > ch05/ai.ja.txt.cabocha
あとは、読み込むファイルの形式に応じてデータを取得します。次の4段階で処理しました。
- ファイル全体を読み込む
- 「split('EOS\n')」で、データを分割する
- 不要な行を「filter」で取り除く
- 「parse_cabocha」関数を適用する
class Morph: def __init__(self, dc): self.surface = dc['surface'] self.base = dc['base'] self.pos = dc['pos'] self.pos1 = dc['pos1'] def parse_cabocha(block): res = [] for line in block.split('\n'): if line == '': return res elif line[0] == '*': continue (surface, attr) = line.split('\t') attr = attr.split(',') lineDict = { 'surface': surface, 'base': attr[6], 'pos': attr[0], 'pos1': attr[1] } res.append(Morph(lineDict)) filename = 'ch05/ai.ja.txt.cabocha' with open(filename, mode='rt', encoding='utf-8') as f: blocks = f.read().split('EOS\n') blocks = list(filter(lambda x: x != '', blocks)) blocks = [parse_cabocha(block) for block in blocks] for m in blocks[2]: print(vars(m))
言語処理100本ノック 2020「39. Zipfの法則」
問題文
問題の概要
両対数グラフとは、それぞれの次元のデータに対してlogを取ったグラフです。
import math from collections import defaultdict import matplotlib.pyplot as plt def parse_mecab(block): res = [] for line in block.split('\n'): if line == '': return res (surface, attr) = line.split('\t') attr = attr.split(',') lineDict = { 'surface': surface, 'base': attr[6], 'pos': attr[0], 'pos1': attr[1] } res.append(lineDict) def extract_words(block): return [b['base'] + '_' + b['pos'] + '_' + b['pos1'] for b in block] filename = 'ch04/neko.txt.mecab' with open(filename, mode='rt', encoding='utf-8') as f: blocks = f.read().split('EOS\n') blocks = list(filter(lambda x: x != '', blocks)) blocks = [parse_mecab(block) for block in blocks] words = [extract_words(block) for block in blocks] d = defaultdict(int) for word in words: for w in word: d[w] += 1 ans = sorted(d.items(), key=lambda x: x[1], reverse=True) ranks = [math.log(r + 1) for r in range(len(ans))] values = [math.log(a[1]) for a in ans] plt.figure(figsize=(8, 8)) plt.scatter(ranks, values) plt.savefig('ch04/ans39.png')
言語処理100本ノック 2020「38. ヒストグラム」
問題文
問題の概要
「matplotlib」を用いて、ヒストグラムを描きましょう。
from collections import defaultdict import matplotlib.pyplot as plt def parse_mecab(block): res = [] for line in block.split('\n'): if line == '': return res (surface, attr) = line.split('\t') attr = attr.split(',') lineDict = { 'surface': surface, 'base': attr[6], 'pos': attr[0], 'pos1': attr[1] } res.append(lineDict) def extract_words(block): return [b['base'] + '_' + b['pos'] + '_' + b['pos1'] for b in block] filename = 'ch04/neko.txt.mecab' with open(filename, mode='rt', encoding='utf-8') as f: blocks = f.read().split('EOS\n') blocks = list(filter(lambda x: x != '', blocks)) blocks = [parse_mecab(block) for block in blocks] words = [extract_words(block) for block in blocks] d = defaultdict(int) for word in words: for w in word: d[w] += 1 ans = d.values() plt.figure(figsize=(8, 8)) plt.hist(ans, bins=100) plt.savefig('ch04/ans38.png')
言語処理100本ノック 2020「37. 「猫」と共起頻度の高い上位10語」
問題文
問題の概要
出現頻度辞書を作る前の段階で、集計対象とする文章を絞り込んでおきます。「list(filter(lambda x: '猫' in x, wordList))」の処理で、猫という語を持つ文のみに限定しています。
from collections import defaultdict import matplotlib.pyplot as plt import japanize_matplotlib def parse_mecab(block): res = [] for line in block.split('\n'): if line == '': return res (surface, attr) = line.split('\t') attr = attr.split(',') lineDict = { 'surface': surface, 'base': attr[6], 'pos': attr[0], 'pos1': attr[1] } res.append(lineDict) def extract_base(block): return [b['base'] for b in block] filename = 'ch04/neko.txt.mecab' with open(filename, mode='rt', encoding='utf-8') as f: blocks = f.read().split('EOS\n') blocks = list(filter(lambda x: x != '', blocks)) blocks = [parse_mecab(block) for block in blocks] words = [extract_base(block) for block in blocks] words = list(filter(lambda x: '猫' in x, words)) d = defaultdict(int) for word in words: for w in word: if w != '猫': d[w] += 1 ans = sorted(d.items(), key=lambda x: x[1], reverse=True)[:10] labels = [a[0] for a in ans] values = [a[1] for a in ans] plt.figure(figsize=(8, 8)) plt.barh(labels, values) plt.savefig('ch04/ans37.png')
言語処理100本ノック 2020「36. 頻度上位10語」
問題文
問題の概要
35. 単語の出現頻度の結果の上位10件を棒グラフで可視化するだけです。
可視化ライブラリとしては「matplotlib」を使っています。日本語が文字化けする現象には「japanize_matplotlib」*1で対応しています。
from collections import defaultdict import matplotlib.pyplot as plt import japanize_matplotlib def parse_mecab(block): res = [] for line in block.split('\n'): if line == '': return res (surface, attr) = line.split('\t') attr = attr.split(',') lineDict = { 'surface': surface, 'base': attr[6], 'pos': attr[0], 'pos1': attr[1] } res.append(lineDict) def extract_words(block): return [b['base'] + '_' + b['pos'] + '_' + b['pos1'] for b in block] filename = 'ch04/neko.txt.mecab' with open(filename, mode='rt', encoding='utf-8') as f: blocks = f.read().split('EOS\n') blocks = list(filter(lambda x: x != '', blocks)) blocks = [parse_mecab(block) for block in blocks] words = [extract_words(block) for block in blocks] d = defaultdict(int) for word in words: for w in word: d[w] += 1 ans = sorted(d.items(), key=lambda x: x[1], reverse=True)[:10] labels = [a[0] for a in ans] values = [a[1] for a in ans] plt.figure(figsize=(15, 8)) plt.barh(labels, values) plt.savefig('ch04/ans36.png')
言語処理100本ノック 2020「35. 単語の出現頻度」
問題文
問題の概要
「30. 形態素解析結果の読み込み」で作成したデータ構造から、全ての単語を取り出し、出現頻度を計算します。
全ての単語を前から確認していき(単語, 出現回数)のペアの辞書を作り上げました。普通のdictではなく「defaultdict」*1が便利です。
from collections import defaultdict def parse_mecab(block): res = [] for line in block.split('\n'): if line == '': return res (surface, attr) = line.split('\t') attr = attr.split(',') lineDict = { 'surface': surface, 'base': attr[6], 'pos': attr[0], 'pos1': attr[1] } res.append(lineDict) def extract_words(block): return [b['base'] + '_' + b['pos'] + '_' + b['pos1'] for b in block] filename = 'ch04/neko.txt.mecab' with open(filename, mode='rt', encoding='utf-8') as f: blocks = f.read().split('EOS\n') blocks = list(filter(lambda x: x != '', blocks)) blocks = [parse_mecab(block) for block in blocks] words = [extract_words(block) for block in blocks] d = defaultdict(int) for word in words: for w in word: d[w] += 1 ans = sorted(d.items(), key=lambda x: x[1], reverse=True) print(ans)
言語処理100本ノック 2020「34. 名詞の連接」
問題文
問題の概要
「30. 形態素解析結果の読み込み」で作成したデータ構造から、データを取り出します。抽出条件は最長一致の名詞の連接です。
品詞を前から見ていき、次の順に処理します。
- リスト res, tmpを用意
- 条件分岐
- 名詞の場合は、リストtmpに格納
- 名詞ではなくリストtmpの大きさが2以上の場合は、tmpの内容を基にresへ保存。tmpを空にする
- 名詞ではなくリストtmpの大きさが1以下の場合は何もしない
def parse_mecab(block): res = [] for line in block.split('\n'): if line == '': return res (surface, attr) = line.split('\t') attr = attr.split(',') lineDict = { 'surface': surface, 'base': attr[6], 'pos': attr[0], 'pos1': attr[1] } res.append(lineDict) def extract_noun_noun(block): res = [] tmp = [] for b in block: if b['pos'] == '名詞': tmp.append(b['surface']) elif len(tmp) >= 2: res.append(''.join(tmp)) tmp = [] else: tmp = [] return res filename = 'ch04/neko.txt.mecab' with open(filename, mode='rt', encoding='utf-8') as f: blocks = f.read().split('EOS\n') blocks = list(filter(lambda x: x != '', blocks)) blocks = [parse_mecab(block) for block in blocks] ans = [extract_noun_noun(block) for block in blocks] print(ans)