新年快樂。
冬休みは帰省などでドタバタしていて、開発が全然進められませんでした(統計の本はちょっとだけ読んだ)。
そして、今日から仕事が始まったわけですけど、金曜まで頑張れるのか不安ですわあ……。
言語処理100本ノック #048
48. 名詞から根へのパスの抽出
文中のすべての名詞を含む文節に対し,その文節から構文木の根に至るパスを抽出せよ. ただし,構文木上のパスは以下の仕様を満たすものとする.
- 各文節は(表層形の)形態素列で表現する
- パスの開始文節から終了文節に至るまで,各文節の表現を"->"で連結する
「吾輩はここで始めて人間というものを見た」という文(neko.txt.cabochaの8文目)から,次のような出力が得られるはずである.
吾輩は -> 見た
ここで -> 始めて -> 人間という -> ものを -> 見た
人間という -> ものを -> 見た
ものを -> 見た
調べたことメモ
Python:リストの中身を任意の区切り文字で出力する
区切り文字に \t
を使うなら、各要素をこれで join する。
print('\t'.join([str(i) for i in list]))
参考 👉 Pythonでリストをタブ区切りで表示する - ブログ
VS Code:Run Code を止める
うっかり無限ループに入ってもーた。
出力のウィンドウ範囲内で右クリック
右クリック>Stop Code Runを選択するか、 ショートカットキーAlt+Ctrl+Mで止める。
参考 👉 VSCode "情報 code is already running" と出て止められない場合の対処。 - Qiita
完成
# knock048.py # NLP Knock #048 by piijey import function_filetochunklist cabochafile = 'neko.txt.cabocha' # 指定された品詞を含む場合に、係り先文節を返す def getDst(chunk, poslist): for m in chunk.morphs: if m.pos in poslist and chunk.dst > 0: return chunk.dst return None # 名詞を含む文節と係り先文節の表層形のリストを返す def getNounRoot(sentence): if len(sentence) > 0: for chunk in sentence: ndst = getDst(chunk, ['名詞']) # 名詞以外・係り先文節なしなら終わり if ndst is None: continue # 名詞をリストに入れる nr_list = [chunk.returnmorphs] # 構文木の根に至るまでのループ # 係り先を探し、リストに追加していく while ndst is not None: nr_list.append(sentence[ndst].returnmorphs) if sentence[ndst].dst < 0: ndst = None else: ndst = sentence[ndst].dst # リストを返す yield nr_list else: return False if __name__ == '__main__': sentences = list(function_filetochunklist.fileToChunkList(cabochafile)) for i, s in enumerate(sentences): nroots_list = list(getNounRoot(s)) if len(nroots_list) < 1: continue # リストの要素を区切り文字で join して出力 for nr in nroots_list: print(' -> '.join([i for i in nr])) nroots_list = []
結果
$ python knock048.py >> knock048.txt (12行目まで) 吾輩は -> 猫である 名前は -> 無い どこで -> 生れたか -> つかぬ 見当が -> つかぬ 何でも -> 薄暗い -> 所で -> 泣いて -> 記憶している 所で -> 泣いて -> 記憶している ニャーニャー -> 泣いて -> 記憶している いた事だけは -> 記憶している 吾輩は -> 見た ここで -> 始めて -> 人間という -> ものを -> 見た 人間という -> ものを -> 見た ものを -> 見た
おまけ:#044で使った有向グラフで可視化
knock048.py メインの後半部分を下のように書き換え、さきほどの出力を有向グラフ化してみる。
dg = Digraph(format='png') for nr in nroots_list: for j in range(len(nr)-1): dg.edge(str(nr[j]), str(nr[j+1])) # j -> j+1 nroots_list = [] dg.render('./knock48_data/'+str(i)+'.dot', view=True)
↓ 結果
「吾輩はここで始めて人間というものを見た」という文の 名詞を含む文節から構文木の根に至るパス