Open2

Information Extraction(NLP)の勉強

nabetsunabetsu

Information Extraction

文書から関連する情報を抜き出す方法。

  • 組織
  • 場所
  • イベント

IEを難しくさせているのは抜き出す対象のデータがテキストであり、構造化されていないこと。
もちろん構造化されていないこと自体は他のNLPのタスクでも共通することだが、一定のパターンがあれば正規表現のパターンで情報を抜き出したりできるが、基本的に処理対象となるテキストデータはフリーフォーマットで決まった形式を持たずに記述されていることがほとんどで、そうした手法が使えない。

IEを使ったアプリケーション

  • ニュース等のタグ付け
  • チャットボット
    • 適切な回答を返すためにはユーザからの質問にどのような情報が含まれているか理解する必要がある
  • ソーシャルメディアを利用したアプリケーション
    • 具体的な例としてTwitterから渋滞の情報に関するツイートを抜き出して表示するアプリケーションなど
  • フォームやレシートからの情報取得
    • OCRと組み合わせてIEを使うことでデジタル化されていない情報を活用可能な形で利用することができる

IE Tasks

IEを支えているタスクはいくつかに分解できる

  • Keyphrase Extraction(KPE)
    • テキストの主題は何か
  • Named Entity Recognition
    • テキストに登場するエンティティの特定(人、組織、場所など)
  • Named Entity Disambiguation and Linking
    • 例えばAppleという単語が登場したときに果物ではなく会社であり、具体的にはApple, Inc.という意味だと認識する
  • Relation Extraction
    • ある人物が登場したときにそれがどういう役割を持っているか関係性を認識する

上記のほかに幾つかより発展的なタスクも存在する。

  • Event Extraction
  • Temporal Information Extraction
  • Template Filling

一般的なIEのタスク

実例

Keyphrase Extraction(KPE)

文書から重要な単語を抜き出す技術であり、結果をその他のNLPのタスク(検索、タグ付け、レコメンド、要約)で活用することができる。

KPEを活用したアプリケーションとして代表的なのがアマゾンのレビューであり、レビューでよく使われている単語を本の特徴を示すものとして表示している。

  • 教師あり学習
  • 教師なし学習

教師なし学習

  • 単語とフレーズをノードで繋いだグラフで表現する
  • 頻繁に用いられ、異なるノードと多くつながっているものが重要な単語やフレーズだとされる

実装

textacyが前述のグラフベースのKeyword Extractionを機能として提供している。

import textacy

mytext = open("practical-nlp/Ch5/Data/nlphistory.txt").read()
en = textacy.load_spacy_lang("en_core_web_sm", disable=("parser",))
doc = textacy.make_spacy_doc(mytext, lang=en)

print("TextRank output:", [kps for kps, weights in
                           textacy.extract.keyterms.textrank(doc, normalize="lemma", topn=5)])

print("SGRank output:", [kps for kps, weights in
                           textacy.extract.keyterms.sgrank(doc, topn=5)])
>>>
TextRank output: ['successful natural language processing system', 'statistical machine translation system', 'natural language system', 'statistical natural language processing', 'natural language task']
SGRank output: ['natural language processing system', 'statistical machine translation', 'research', 'late 1980', 'early']

その他の選択肢として、gensimもTextRankを利用したKeyword Extractionの機能を提供している。

実装(日本語)

日本語のモデルをインストールして利用する以外は基本的に同じ。

# 使用する日本語モデルのダウンロード
!python -m spacy download ja_core_news_sm

# パッケージのリロード
import pkg_resources, imp
imp.reload(pkg_resources)

ja = textacy.load_spacy_lang("ja_core_news_sm")
doc = textacy.make_spacy_doc(sample_text, lang=ja)
print("TextRank output:", [kps for kps, weights in
                           textacy.extract.keyterms.textrank(doc, normalize="lemma", topn=10)])

print("SGRank output:", [kps for kps, weights in
                           textacy.extract.keyterms.sgrank(doc, topn=10)])

最初モデルの読み込みができなくてContextualVersionConflict: (sortedcontainers 2.3.0 (/usr/local/lib/python3.7/dist-packages), Requirement.parse('sortedcontainers~=2.1.0'), {'sudachipy'})というエラーが出力されたが、この記事を参考にパッケージのリロードを実行したらロードできるようになった。

注意点

  • グラフの作成は文章の長さに影響されやすい。解決策の一つとして考えられるのは全てのテキストを使うのではなく、文章の最初と最後の一部を使うこと。
  • Keyphraseは個別にランクづけされるため、意味的に重複したフレーズが入ることがある。解決策の一つはコサイン類似度などの指標を使って類似した単語間でどの単語を使うか決定する。textacyではすでにその機能が提供されており、以下のコードで重複を排除できる?
terms = set([term for term,weight in textacy.extract.keyterms.sgrank(doc)])
print(textacy.extract.utils.aggregate_term_variants(terms))

Named Entity Recognition

Googleでwhere was Albert Einstein born?と調べると検索結果のリストの前に正確な地名が返される。
検索ワードからこの結果を返すにはまずAlbert Einsteinが人名であることを理解する必要がある。
これがNERの実際のアプリケーションでの実例である。

NERとは文書内のエンティティを特定することであり、一般的な例として以下が挙げられる。

  • 人名
  • 場所
  • 組織

NERはRelation ExtractionやEvent Extractionのような他のNLPタスクのために必要であり、また、機械翻訳などでも活用が可能で、多くのNLPのシステムで重要な役割を担う技術。

NERの構築

シンプルなアプローチとして考えられるのが業務に関連した人や組織、場所のコレクションを保持すること。
ただし、こうし

  • 新しいエンティティが出現したらどうする?

  • 定期的にデータベースを更新するか

  • エイリアス(USAとUnited Statesなど)はどう扱うか

  • rule-based NER

    • 特定のルールに基づいて単語をエンティティだと認識する
    • RegexNER(StanfordNLP)
    • EntityRuler(spaCy)
  • ML model

    • すべての単語に対してそれがエンティティであるか、もしそうならどんな種類のエンティティかを予測するモデルを作成する
    • 分類の問題に似ているが、唯一の違いはNERはsequence labeling problemであるという点
    • 分類の際には文ごとに判断を行い、前後の文脈を気にしなかったが、
    • 同等なPOS

自作

学習済みのモデルがあり、それを利用することができる。
以下がポピュラーなもの。

  • spaCy
  • Stanford NER
  • AllenNLP

学習済みのモデルを使うときに問題になるが以下の2つ。

  • ドメイン特有の知識は学習済みモデルには含まれていない

Pre-trained

import spacy

# 使用する言語モデルを設定
nlp = spacy.load("ja_core_news_sm")
text_from_fig = "憲法改正の手続きを定めた国民投票法の改正案について、自民党と立憲民主党の幹事長が会談し、立憲民主党の求めに応じて修正したうえで、今の国会の会期内に成立させることで合意しました。改正案は、このあと衆議院憲法審査会で採決が行われ、修正のうえ、賛成多数で可決される見通しです。そして、近く開かれる衆議院本会議で可決され、参議院に送られる運びで、改正案は、平成30年に提出されて以来、およそ3年を経て成立する見込みとなりました。"
doc = nlp(text_from_fig)
for ent in doc.ents:
    if ent.text:
         print(ent.text, "\t", ent.label_)
>>>
自民党 	 NORP
立憲民主党 	 NORP
立憲民主党 	 NORP
衆議院憲法審査会 	 ORG
衆議院本会議 	 FAC
参議院 	 ORG
平成30年 	 DATE
3年 	 DATE

Entityのラベルについてはモデルのページに説明がある。(spaCyの日本語モデル)
また、spacy.explainでラベルの説明を表示できる

spacy.explain("NORP")
>>>
Nationalities or religious or political groups

Active Learning

特定のドメインについての知識を持たせたいが、すべてをスクラッチで開発したくない場合には、既存のNERモデルを活用する方法がある。

  • RegexNER or EntityRuler
  • Active Learning(Prodigy)

参考書籍