自然な言語処理は今やどこにでもあります。音声インターフェースとチャットボットは急速に開発されており、大きなテキストデータを処理するためのモデルが開発されており、機械翻訳も開発され続けています。
この記事では、比較的新しいSpaCyライブラリについて説明します。これは、現在Pythonでのテキスト処理で最も人気があり便利なソリューションの1つです。その機能により、音声の一部の識別や名前付きエンティティの抽出から、分析用の独自のモデルの作成まで、非常に幅広いタスクを解決できます。
まず、SpaCyでデータがどのように処理されるかを見てみましょう。処理のためにロードされたテキストは、さまざまな処理コンポーネントを順番に通過し、Docオブジェクトのインスタンスとして保存されます
。DocはSpaCyの中心的なデータ構造であり、単語のシーケンス、またはトークンと呼ばれるトークンが格納されます。 Docオブジェクト内では、トークンとスパンの2つのオブジェクトタイプを区別できます。トークンはドキュメントの個々の単語へのリンクであり、スパンはいくつかの単語のシーケンスへのリンクです(自分で作成できます)。
もう1つの重要なデータ構造は、すべてのドキュメントに共通の参照テーブルのセットを格納するVocabオブジェクトです。これにより、メモリが節約され、処理されたすべてのドキュメントに単一の情報ソースが提供されます。
ドキュメントトークンは、ハッシュを介してVocabオブジェクトに接続されます。これを使用して、トークンの単語の初期形式またはその他の字句属性を取得できます。
これで、SpaCyライブラリでのデータの保存と処理がどのように配置されるかがわかりました。それが提供する機会をどのように活用するのですか?テキストを順番に処理するために使用できる操作を見てみましょう。
1.基本操作
テキストの操作を開始する前に、言語モデルをインポートする必要があります。ロシア語の場合、トークン化(テキストを個別のトークンに分割する)およびその他のいくつかの基本的な操作をサポートするSpaCyの公式モデルがあります。
from spacy.lang.ru import Russian
言語モデルをインポートしてインスタンス化した後、テキストの処理を開始できます。これを行うには、作成したインスタンスにテキストを渡す必要があります。
nlp = Russian()
doc = nlp(" , .")
結果のDocオブジェクトの操作は、リストの操作と非常によく似ています。インデックスを使用して目的のトークンにアクセスしたり、複数のトークンからスライスを作成したりできます。また、トークンまたはスライスのテキストを取得するには、text属性を使用できます。
token = doc[0]
print(token.text)
span = doc[3:6]
print(span.text)
トークンに含まれる情報の種類の詳細については、次の属性を使用できます。
- is_alpha-トークンにアルファベット文字のみが含まれているかどうかを確認します
- is_punct-トークンが句読点であるかどうかを確認します
- like_num-トークンが数字かどうかを確認します
print("is_alpha: ", [token.is_alpha for token in doc])
print("is_punct: ", [token.is_punct for token in doc])
print("like_num: ", [token.like_num for token in doc])
ポイントの前にあるすべてのトークンが画面に表示される別の例を考えてみましょう。この結果を得るには、トークンを反復処理するときに、token.i属性を使用して次のトークンを確認します。
for token in doc:
if token.i+1 < len(doc):
next_token = doc[token.i+1]
if next_token.text == ".":
print(token.text)
2.構文を使用した操作
より複雑な単語処理操作には、他のモデルが使用されます。これらは、構文、名前付きエンティティの抽出、および単語の意味の操作に関連するタスク用に特別にトレーニングされています。たとえば、英語の場合、サイズが異なる3つの公式モデルがあります。ロシア語の場合、現時点では公式モデルはまだトレーニングされていませんが、構文を操作できるサードパーティのソースからのru2モデルがすでに存在します。
この記事の最後では、独自のモデルを作成する方法、または特定のタスクでより適切に機能するように既存のモデルを追加でトレーニングする方法について説明します。
SpaCyの機能を完全に説明するために、この記事では英語モデルを使用します。可能性を示すのに最適な小さなen_core_web_smモデルを設定しましょう。コマンドラインにインストールするには、次のように入力する必要があります。
python -m spacy download en_core_web_sm
このモデルを使用すると、トークンごとに、音声の一部、文内の役割、およびそれが依存するトークンを取得できます。
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("New Apple MacBook set launch tomorrow")
for token in doc:
token_text = token.text
token_pos = token.pos_
token_dep = token.dep_
token_head = token.head.text
print(f"{token_text:<12}{token_pos:<10}" \
f"{token_dep:<10}{token_head:<12}")
New PROPN compound MacBook Apple PROPN compound MacBook MacBook PROPN nsubj set set VERB ROOT set to PART aux launch launch VERB xcomp set tomorrow NOUN npadvmod launch
依存関係を確認する最善の方法は、テキストデータを読み取るのではなく、構文ツリーを構築することです。ディスプレイス機能はこれに役立ちます。ドキュメントを転送するだけです。
from spacy import displacy
displacy.render(doc, style='dep', jupyter=True)
コードを実行した結果、文に関するすべての構文情報が配置されているツリーが得られ
ます。タグ名を解読するには、explain関数を使用できます。
print(spacy.explain("aux"))
print(spacy.explain("PROPN"))
auxiliary
proper noun
ここでは、画面に略語が表示されており、auxは補助粒子(auxiliary)を表し、PROPNは適切な名詞を表していることがわかります。
SpaCyは、任意のトークンの単語の初期形式を見つける機能も実装しています(-PRON-は発音に使用されます)。
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("I saw a movie yesterday")
print(' '.join([token.lemma_ for token in doc]))
'-PRON- see a movie yesterday'
3.名前付きエンティティの割り当て
多くの場合、テキストを操作するには、テキストで言及されているエンティティを強調表示する必要があります。doc.ents属性は、ドキュメント内の名前付きエンティティを一覧表示するために使用され、ent.label_属性は、このエンティティのラベルを取得するために使用されます。
import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("Apple is looking at buying U.K. startup for 1$ billion")
for ent in doc.ents:
print(ent.text, ent.label_)
Apple ORG
U.K. GPE
1$ billion MONEY
ここでexplain属性を使用して、名前付きエンティティラベルのデコードを確認することもできます。
print(spacy.explain("GPE"))
国、都市、州
そしてdisplacy関数は、テキスト内のエンティティのリストを視覚化するのに役立ちます:
from spacy import displacy
displacy.render(doc、style = 'ent'、jupyter = True)
4.テキスト検索用の独自のテンプレートを作成します
spaCyモジュールには、独自のテキスト検索テンプレートを作成できる非常に便利なツールが含まれています。特に、スピーチの特定の部分の単語、単語のすべての形式を最初の形式で検索し、トークン内のコンテンツのタイプを確認できます。主なパラメータのリストは次のとおりです
。トークンのシーケンスを認識するための独自のテンプレートを作成してみましょう。FIFAまたはICCクリケットワールドカップに関するテキストから、年についての言及を含む行を抽出するとします。
import spacy
from spacy.matcher import Matcher
nlp = spacy.load("en_core_web_sm")
matcher = Matcher(nlp.vocab)
pattern = [
{"IS_DIGIT": True},
{"LOWER": {"REGEX": "(fifa|icc)"}},
{"LOWER": "cricket", "OP": "?"},
{"LOWER": "world"},
{"LOWER": "cup"}
]
matcher.add("fifa_pattern", None, pattern)
doc = nlp("2018 ICC Cricket World Cup: Afghanistan won!")
matches = matcher(doc)
for match_id, start, end in matches:
matched_span = doc[start:end]
print(matched_span)
2018 ICC Cricket World Cup
そのため、このコードブロックでは、カスタムテンプレートのセットを保存できる特別なMatcherオブジェクトをインポートしました。初期化後、トークンのシーケンスを指定するテンプレートを作成しました。ICCとFIFAのどちらかを選択するために通常の式を使用し、クリケットトークン(このトークンのオプションの存在を示すキー)を使用したことに注意してください。
テンプレートを作成したら、add関数を使用してテンプレートをセットに追加し、パラメーターに一意のテンプレートIDを指定する必要があります。検索結果は、タプルのリストの形式で表示されます。各タプルは、一致IDと、ドキュメントで見つかったスライスの開始インデックスと終了インデックスで構成されます。
5.意味的近接性の決定
2つの単語の意味は非常に似ていますが、どのようにそれらの近さを測定しますか?このようなタスクでは、セマンティックベクトルが役に立ちます。 2つの単語または冗長な表現が類似している場合、それらのベクトルは互いに近くにあります。
言語モデルがそのような問題を解決するように訓練されている場合、SpaCyでベクトルの意味的近接性を計算することは難しくありません。結果はモデルのサイズに大きく依存するため、このタスクではより大きなモデルを使用してみましょう。
import spacy
nlp = spacy.load("en_core_web_md")
doc1 = nlp("I like burgers")
doc2 = nlp("I like pizza")
print(doc1.similarity(doc2))
0.9244169833828932
値の範囲は0から1です。1に近いほど、類似性が高くなります。上記の例では、2つのドキュメントを比較しましたが、個々のトークンとスライスを同じ方法で比較できます。
セマンティック近接評価は、多くの問題を解決するのに役立ちます。たとえば、これを使用して推奨システムを設定し、ユーザーがすでに読んだ内容に基づいて同様のテキストをユーザーに提供できるようにすることができます。
セマンティックアフィニティは非常に主観的であり、常にタスクのコンテキストに依存することを覚えておくことが重要です。たとえば、「犬が好き」と「犬が嫌い」という言葉は、どちらも犬についての意見を表しているため似ていますが、同時に気分が大きく異なります。場合によっては、結果が問題のコンテキストと相関するように、言語モデルを追加でトレーニングする必要があります。
6.独自の処理コンポーネントを作成する
SpaCyモジュールは、多数の組み込みコンポーネント(トークン化、名前付きエンティティの強調表示)をサポートしますが、独自のコンポーネントを定義することもできます。実際、コンポーネントは順番に関数と呼ばれ、ドキュメントを入力として受け取り、変更して送り返します。add_pipe属性を使用して、新しいコンポーネントを追加できます。
import spacy
def length_component(doc):
doc_length = len(doc)
print(f"This document is {doc_length} tokens long.")
return doc
nlp = spacy.load("en_core_web_sm")
nlp.add_pipe(length_component, first=True)
print(nlp.pipe_names)
doc = nlp("This is a sentence.")
['length_component', 'tagger', 'parser', 'ner']
This document is 5 tokens long.
上記の例では、処理されたドキュメント内のトークンの数を表示する独自の関数を作成して追加しました。nlp.pipe_names属性を使用して、コンポーネントの実行順序を取得しました。ご覧のとおり、作成されたコンポーネントがリストの最初にあります。次のオプションを使用して、新しいコンポーネントを追加する場所を指定できます。
カスタムコンポーネントを追加する機能は、ニーズに合わせて処理を最適化するための非常に強力なツールです。
7.モデルのトレーニングと更新
統計モデルは、トレーニングされた例に基づいて予測を行います。原則として、このようなモデルの精度は、タスクに固有の例でモデルを追加でトレーニングすることで改善できます。既存のモデルに関する追加のトレーニングは非常に役立ちます(たとえば、名前付きエンティティの認識や解析など)。
追加のトレーニング例は、SpaCyインターフェースに直接追加できます。例自体は、モデルがトレーニングするこの例のテキストデータとラベルのリストで構成されている必要があります。
例として、名前付きエンティティを取得するようにモデルを更新することを検討してください。このようなモデルを更新するには、テキスト、エンティティとそのクラスの表示を含む多くの例を渡す必要があります。例では、エンティティを抽出するときにモデルが句のコンテキストに大きく依存するため、句全体を使用する必要があります。非エンティティトークンを認識できるように、モデルを完全にトレーニングすることは非常に重要です。
例えば:
("What to expect at Apple's 10 November event", {"entities": [(18,23,"COMPANY")]})
("Is that apple pie I smell?", {"entities": []})
最初の例では、会社について言及しています。トレーニングでは、名前の始まりと終わりの位置を強調表示してから、このエンティティが会社であることを示すラベルを付けます。 2番目の例では、フルーツについて話しているので、エンティティはありません。
モデルをトレーニングするためのデータは通常、人によってマークアップされますが、この作業は、SpaCyの独自の検索テンプレートまたは特殊なマークアッププログラム(たとえば、Prodigy)を使用してわずかに自動化できます。
例を準備したら、モデルのトレーニングに直接進むことができます。モデルを効果的にトレーニングするには、一連の複数のトレーニングを実行する必要があります。トレーニングごとに、モデルは特定のパラメーターの重みを最適化します。SpaCyのモデルは確率的勾配降下技術を使用しているため、例を各トレーニングと混合し、それらを少しずつ(パケット)送信することをお勧めします。これにより、勾配推定の信頼性が向上します。
import spacy
import random
from spacy.lang.en import English
TRAINING_DATA = [
("What to expect at Apple's 10 November event",
{"entities": [(18,23,"COMPANY")]})
# ...
]
nlp = English()
for i in range(10):
random.shuffle(TRAINING_DATA)
for batch in spacy.util.minibatch(TRAINING_DATA):
texts = [text for text, annotation in batch]
annotations = [annotation for text, annotation in batch]
nlp.update(texts, annotations)
nlp.to_disk("model")
上記の例では、ループは10個のトレーニングで構成されています。トレーニングが完了すると、モデルはモデルフォルダのディスクに保存されました。
更新だけでなく、新しいモデルを作成する必要がある場合は、トレーニングを開始する前にいくつかの操作が必要になります。
名前付きエンティティを強調表示する新しいモデルを作成するプロセスを検討してください。
nlp = spacy.blank("en")
ner = nlp.create_pipe("ner")
nlp.add_pipe(ner)
ner.add_label("COMPANY")
nlp.begin_training()
まず、spacy.blank( "en")関数を使用して空のモデルを作成します。モデルには、言語データとトークン化ルールのみが含まれています。次に、名前付きエンティティの強調表示を担当するnerコンポーネントを追加し、add_label属性を使用して、エンティティのラベルを追加します。次に、nlp.begin_training()関数を使用して、重みのランダムな分布でトレーニング用のモデルを初期化します。さて、前の例で示したように、モデルをトレーニングするだけで十分です。