Natural LanguageToolkit-クイックガイド

自然言語処理(NLP)とは何ですか?

人間が話したり、読んだり、書いたりできる助けを借りてコミュニケーションをとる方法は言語です。言い換えれば、私たち人間は自然言語で考え、計画を立て、決定を下すことができます。ここで大きな問題は、人工知能、機械学習、深層学習の時代に、人間はコンピューター/機械と自然言語で通信できるかということです。コンピューターは構造化データを必要とするため、NLPアプリケーションの開発は私たちにとって大きな課題ですが、一方で、人間の発話は構造化されておらず、本質的にあいまいなことがよくあります。

自然言語とは、コンピューターサイエンス、より具体的にはAIのサブフィールドであり、コンピューター/マシンが人間の言語を理解、処理、操作できるようにします。簡単に言うと、NLPは、ヒンディー語、英語、フランス語、オランダ語などの人間の自然言語から意味を分析、理解、および導出するための機械の方法です。

それはどのように機能しますか?

NLPの動作を深く掘り下げる前に、人間が言語をどのように使用しているかを理解する必要があります。毎日、私たち人間は数百または数千の単語を使用し、他の人間はそれらを解釈してそれに応じて答えます。人間にとっては簡単なコミュニケーションですね。しかし、私たちは言葉がそれよりもはるかに深く実行されることを知っており、私たちは常に私たちが言うことと私たちが言う方法から文脈を導き出します。そのため、音声変調に焦点を合わせるのではなく、NLPはコンテキストパターンを利用していると言えます。

例を挙げて理解しましょう−

Man is to woman as king is to what?
We can interpret it easily and answer as follows:
Man relates to king, so woman can relate to queen.
Hence the answer is Queen.

人間はどの単語が何を意味するのかをどのように知っていますか?この質問への答えは、私たちが経験を通して学ぶということです。しかし、マシン/コンピューターはどのようにして同じことを学ぶのでしょうか?

次の簡単な手順でそれを理解しましょう-

  • まず、マシンが経験から学習できるように、マシンに十分なデータを供給する必要があります。

  • 次に、マシンは、ディープラーニングアルゴリズムを使用して、以前に入力したデータとその周辺のデータから単語ベクトルを作成します。

  • 次に、これらの単語ベクトルに対して単純な代数演算を実行することにより、機械は人間としての答えを提供できるようになります。

NLPのコンポーネント

次の図は、自然言語処理(NLP)のコンポーネントを表しています。

形態学的処理

形態学的処理は、NLPの最初のコンポーネントです。これには、言語入力のチャンクを段落、文、単語に対応するトークンのセットに分割することが含まれます。たとえば、次のような単語“everyday” 次のように2つのサブワードトークンに分割できます “every-day”

構文解析

2番目のコンポーネントである構文解析は、NLPの最も重要なコンポーネントの1つです。このコンポーネントの目的は次のとおりです-

  • 文が整形式であるかどうかを確認するため。

  • 異なる単語間の構文上の関係を示す構造に分割すること。

  • 例:のような文 “The school goes to the student” 構文アナライザーによって拒否されます。

セマンティック分析

セマンティック分析は、テキストの意味をチェックするために使用されるNLPの3番目のコンポーネントです。正確な意味を描くことも含まれますが、テキストから辞書の意味を言うこともできます。例:「それは熱いアイスクリームです」のような文。セマンティックアナライザーによって破棄されます。

語用論的分析

語用論的分析は、NLPの4番目のコンポーネントです。これには、各コンテキストに存在する実際のオブジェクトまたはイベントを、前のコンポーネント、つまりセマンティック分析によって取得されたオブジェクト参照に適合させることが含まれます。例:のような文“Put the fruits in the basket on the table” 2つの意味解釈を持つことができるため、語用論的アナライザーはこれら2つの可能性から選択します。

NLPアプリケーションの例

新たなテクノロジーであるNLPは、私たちが最近見たさまざまな形のAIを導き出します。今日および明日のますます認知されるアプリケーションでは、人間と機械の間のシームレスでインタラクティブなインターフェイスを作成する際にNLPを使用することが引き続き最優先事項になります。以下は、NLPの非常に便利なアプリケーションの一部です。

機械翻訳

機械翻訳(MT)は、自然言語処理の最も重要なアプリケーションの1つです。MTは基本的に、あるソース言語またはテキストを別の言語に翻訳するプロセスです。機械翻訳システムは、バイリンガルまたはマルチリンガルのいずれかです。

スパムとの戦い

不要な電子メールが大幅に増加しているため、スパムフィルターはこの問題に対する最初の防衛線であるため重要になっています。誤検知と誤検知の問題を主な問題と見なすことで、NLPの機能を使用してスパムフィルタリングシステムを開発できます。

N-gramモデリング、Word Stemming、Bayesian分類は、スパムフィルタリングに使用できる既存のNLPモデルの一部です。

情報検索とWeb検索

Google、Yahoo、Bing、WolframAlphaなどのほとんどの検索エンジンは、機械翻訳(MT)テクノロジーをNLPディープラーニングモデルに基づいています。このような深層学習モデルにより、アルゴリズムはWebページ上のテキストを読み取り、その意味を解釈して別の言語に翻訳することができます。

自動テキスト要約

自動テキスト要約は、長いテキストドキュメントの短く正確な要約を作成する手法です。したがって、関連情報を短時間で取得するのに役立ちます。このデジタル時代では、インターネットを介した情報の洪水が止まることはないため、自動テキスト要約が深刻に必要とされています。NLPとその機能は、自動テキスト要約の開発において重要な役割を果たします。

文法修正

スペル修正と文法修正は、MicrosoftWordのようなワードプロセッサソフトウェアの非常に便利な機能です。自然言語処理(NLP)は、この目的で広く使用されています。

質問応答

自然言語処理(NLP)のもう1つの主要なアプリケーションである質問応答は、ユーザーが自然言語で投稿した質問に自動的に回答するシステムの構築に重点を置いています。

感情分析

感情分析は、自然言語処理(NLP)のもう1つの重要なアプリケーションの1つです。その名前が示すように、感情分析は次の目的で使用されます。

  • いくつかの投稿の中から感情を特定し、

  • 感情が明確に表現されていない感情を特定します。

AmazonやebayなどのオンラインEコマース企業は、感情分析を使用して、オンラインで顧客の意見や感情を特定しています。それは彼らが彼らの顧客が彼らの製品とサービスについてどう思うかを理解するのを助けるでしょう。

音声エンジン

Siri、Google Voice、Alexaなどの音声エンジンはNLP上に構築されているため、自然言語で通信できます。

NLPの実装

上記のアプリケーションを構築するには、言語を十分に理解し、言語を効率的に処理するためのツールを備えた特定のスキルセットが必要です。これを実現するために、さまざまなオープンソースツールを利用できます。それらのいくつかはオープンソースですが、他は独自のNLPアプリケーションを構築するために組織によって開発されています。以下はいくつかのNLPツールのリストです-

  • 自然言語ツールキット(NLTK)

  • Mallet

  • GATE

  • NLPを開く

  • UIMA

  • Genism

  • スタンフォードツールキット

これらのツールのほとんどはJavaで書かれています。

自然言語ツールキット(NLTK)

上記のNLPツールの中で、NLTKは、使いやすさと概念の説明に関して非常に高いスコアを獲得しています。Pythonの学習曲線は非常に速く、NLTKはPythonで記述されているため、NLTKにも非常に優れた学習キットがあります。NLTKには、トークン化、ステミング、レマタイゼーション、句読点、文字数、単語数などのほとんどのタスクが組み込まれています。とてもエレガントで扱いやすいです。

NLTKをインストールするには、コンピューターにPythonがインストールされている必要があります。リンクwww.python.org/downloadsにアクセスして、OSの最新バージョン(Windows、Mac、Linux / Unix)を選択できます。Pythonの基本的なチュートリアルについては、リンクwww.tutorialspoint.com/python3/index.htmを参照してください。

ここで、コンピューターシステムにPythonをインストールしたら、NLTKをインストールする方法を理解しましょう。

NLTKのインストール

NLTKは次のようにさまざまなOSにインストールできます-

Windowsの場合

Windows OSにNLTKをインストールするには、以下の手順に従ってください。

  • まず、Windowsコマンドプロンプトを開き、の場所に移動します pip フォルダ。

  • 次に、次のコマンドを入力してNLTKをインストールします-

pip3 install nltk

ここで、WindowsのスタートメニューからPythonShellを開き、次のコマンドを入力して、NLTKのインストールを確認します-

Import nltk

エラーが発生しない場合は、Python3を搭載したWindowsOSにNLTKが正常にインストールされています。

Mac / Linuxの場合

Mac / Linux OSにNLTKをインストールするには、次のコマンドを記述します-

sudo pip install -U nltk

コンピューターにpipがインストールされていない場合は、以下の手順に従って最初にインストールしてください pip

まず、次のコマンドを使用して、パッケージインデックスを更新します-

sudo apt update

次に、次のコマンドを入力してインストールします pip Python3の場合-

sudo apt install python3-pip

アナコンダを通して

Anacondaを介してNLTKをインストールするには、以下の手順に従います-

まず、Anacondaをインストールするには、リンクwww.anaconda.com/distribution/#download-sectionにアクセスし、インストールする必要のあるPythonのバージョンを選択します。

コンピューターシステムにAnacondaをインストールしたら、コマンドプロンプトに移動し、次のコマンドを記述します-

conda install -c anaconda nltk

出力を確認して、「yes」と入力する必要があります。NLTKがダウンロードされ、Anacondaパッケージにインストールされます。

NLTKのデータセットとパッケージのダウンロード

これで、NLTKがコンピューターにインストールされましたが、それを使用するには、NLTKで使用可能なデータセット(コーパス)をダウンロードする必要があります。利用可能な重要なデータセットのいくつかは次のとおりです。stpwords, guntenberg, framenet_v15 等々。

次のコマンドの助けを借りて、すべてのNLTKデータセットをダウンロードできます-

import nltk
nltk.download()

次のNLTKダウンロードウィンドウが表示されます。

次に、ダウンロードボタンをクリックして、データセットをダウンロードします。

NLTKスクリプトを実行する方法は?

以下は、PorterStemmerアルゴリズムを使用して実装している例です。 PorterStemmernltkクラス。この例を使用すると、NLTKスクリプトの実行方法を理解できます。

まず、自然言語ツールキット(nltk)をインポートする必要があります。

import nltk

今、インポートします PorterStemmer PorterStemmerアルゴリズムを実装するクラス。

from nltk.stem import PorterStemmer

次に、次のようにPorterStemmerクラスのインスタンスを作成します-

word_stemmer = PorterStemmer()

ここで、語幹にしたい単語を入力します。−

word_stemmer.stem('writing')

出力

'write'

word_stemmer.stem('eating')

出力

'eat'

トークン化とは何ですか?

これは、テキストを文や単語などの小さな部分に分割するプロセスとして定義できます。これらの小さな部分はトークンと呼ばれます。たとえば、単語は文のトークンであり、文は段落のトークンです。

NLPは、感情分析、QAシステム、言語翻訳、スマートチャットボット、音声システムなどのアプリケーションの構築に使用されることがわかっているため、それらを構築するには、テキストのパターンを理解することが不可欠です。上記のトークンは、これらのパターンを見つけて理解するのに非常に役立ちます。トークン化は、ステミングやレンマ化などの他のレシピの基本ステップと見なすことができます。

NLTKパッケージ

nltk.tokenize トークン化のプロセスを実現するためにNLTKモジュールによって提供されるパッケージです。

文を単語にトークン化する

文を単語に分割したり、文字列から単語のリストを作成したりすることは、すべてのテキスト処理アクティビティの重要な部分です。によって提供されるさまざまな機能/モジュールの助けを借りてそれを理解しましょうnltk.tokenize パッケージ。

word_tokenizeモジュール

word_tokenizeモジュールは、基本的な単語のトークン化に使用されます。次の例では、このモジュールを使用して文を単語に分割します。

import nltk
from nltk.tokenize import word_tokenize
word_tokenize('Tutorialspoint.com provides high quality technical tutorials for free.')

出力

['Tutorialspoint.com', 'provides', 'high', 'quality', 'technical', 'tutorials', 'for', 'free', '.']

TreebankWordTokenizerクラス

word_tokenize 上記で使用されているモジュールは、基本的に、tokenize()関数をインスタンスとして呼び出すラッパー関数です。 TreebankWordTokenizerクラス。これは、word_tokenize()モジュールを使用して文を単語に分割するときに得られるものと同じ出力を提供します。上で実装された同じ例を見てみましょう-

まず、自然言語ツールキット(nltk)をインポートする必要があります。

import nltk

今、インポートします TreebankWordTokenizer ワードトークナイザーアルゴリズムを実装するクラス-

from nltk.tokenize import TreebankWordTokenizer

次に、次のようにTreebankWordTokenizerクラスのインスタンスを作成します-

Tokenizer_wrd = TreebankWordTokenizer()

ここで、トークンに変換する文を入力します-

Tokenizer_wrd.tokenize(
   'Tutorialspoint.com provides high quality technical tutorials for free.'
)

出力

[
   'Tutorialspoint.com', 'provides', 'high', 'quality', 
   'technical', 'tutorials', 'for', 'free', '.'
]

完全な実装例

以下の完全な実装例を見てみましょう

import nltk
from nltk.tokenize import TreebankWordTokenizer
tokenizer_wrd = TreebankWordTokenizer()
tokenizer_wrd.tokenize('Tutorialspoint.com provides high quality technical
tutorials for free.')

出力

[
   'Tutorialspoint.com', 'provides', 'high', 'quality', 
   'technical', 'tutorials','for', 'free', '.'
]

トークナイザーの最も重要な規則は、収縮を分離することです。たとえば、この目的でword_tokenize()モジュールを使用すると、次のような出力が得られます。

import nltk
from nltk.tokenize import word_tokenize
word_tokenize('won’t')

出力

['wo', "n't"]]

によるそのような種類のコンベンション TreebankWordTokenizer受け入れられません。そのため、2つの代替単語トークナイザーがあります。PunktWordTokenizer そして WordPunctTokenizer

WordPunktTokenizerクラス

すべての句読点を個別のトークンに分割する代替単語トークナイザー。次の簡単な例でそれを理解しましょう-

from nltk.tokenize import WordPunctTokenizer
tokenizer = WordPunctTokenizer()
tokenizer.tokenize(" I can't allow you to go home early")

出力

['I', 'can', "'", 't', 'allow', 'you', 'to', 'go', 'home', 'early']

テキストを文にトークン化する

このセクションでは、テキスト/段落を文に分割します。NLTKは提供しますsent_tokenize この目的のためのモジュール。

なぜそれが必要なのですか?

私たちの頭に浮かんだ明らかな質問は、単語トークナイザーがある場合、なぜセンテンストークナイザーが必要なのか、なぜテキストをセンテンスにトークン化する必要があるのか​​ということです。文中の平均的な単語を数える必要があるとしたら、どうすればよいでしょうか。このタスクを実行するには、文のトークン化と単語のトークン化の両方が必要です。

次の簡単な例を使用して、文と単語のトークナイザーの違いを理解しましょう。

import nltk
from nltk.tokenize import sent_tokenize
text = "Let us understand the difference between sentence & word tokenizer. 
It is going to be a simple example."
sent_tokenize(text)

出力

[
   "Let us understand the difference between sentence & word tokenizer.", 
   'It is going to be a simple example.'
]

正規表現を使用した文のトークン化

単語トークナイザーの出力が受け入れられず、テキストのトークン化方法を完全に制御したい場合は、文のトークン化を行う際に使用できる正規表現を使用できます。NLTKは提供しますRegexpTokenizer これを達成するためのクラス。

以下の2つの例を使用して、概念を理解しましょう。

最初の例では、英数字トークンと一重引用符を照合するために正規表現を使用して、次のような収縮を分割しないようにします。 “won’t”

例1

import nltk
from nltk.tokenize import RegexpTokenizer
tokenizer = RegexpTokenizer("[\w']+")
tokenizer.tokenize("won't is a contraction.")
tokenizer.tokenize("can't is a contraction.")

出力

["won't", 'is', 'a', 'contraction']
["can't", 'is', 'a', 'contraction']

最初の例では、正規表現を使用して空白をトークン化します。

例2

import nltk
from nltk.tokenize import RegexpTokenizer
tokenizer = RegexpTokenizer('/s+' , gaps = True)
tokenizer.tokenize("won't is a contraction.")

出力

["won't", 'is', 'a', 'contraction']

上記の出力から、句読点がトークンに残っていることがわかります。パラメータgaps = Trueは、パターンがトークン化するギャップを識別しようとしていることを意味します。一方、gaps = Falseパラメーターを使用する場合、パターンは次の例で確認できるトークンを識別するために使用されます。

import nltk
from nltk.tokenize import RegexpTokenizer
tokenizer = RegexpTokenizer('/s+' , gaps = False)
tokenizer.tokenize("won't is a contraction.")

出力

[ ]

空白の出力が表示されます。

なぜ独自のセンテンストークナイザーをトレーニングするのですか?

これは非常に重要な質問です。NLTKのデフォルトのセンテンストークナイザーがある場合、なぜセンテンストークナイザーをトレーニングする必要があるのでしょうか。この質問に対する答えは、NLTKのデフォルトのセンテンストークナイザーの品質にあります。NLTKのデフォルトのトークナイザーは、基本的に汎用のトークナイザーです。それは非常にうまく機能しますが、非標準のテキスト、おそらく私たちのテキスト、または独自のフォーマットを持つテキストには適していません。このようなテキストをトークン化して最良の結果を得るには、独自のセンテンストークナイザーをトレーニングする必要があります。

実装例

この例では、Webテキストコーパスを使用します。このコーパスから使用するテキストファイルは、以下に示すダイアログとしてフォーマットされたテキストを持っています-

Guy: How old are you?
Hipster girl: You know, I never answer that question. Because to me, it's about
how mature you are, you know? I mean, a fourteen year old could be more mature
than a twenty-five year old, right? I'm sorry, I just never answer that question.
Guy: But, uh, you're older than eighteen, right?
Hipster girl: Oh, yeah.

このテキストファイルをtraining_tokenizerという名前で保存しました。NLTKはという名前のクラスを提供しますPunktSentenceTokenizer生のテキストをトレーニングしてカスタムセンテンストークナイザーを作成することができます。ファイルを読み込むか、NLTKコーパスからを使用して生のテキストを取得できます。raw() 方法。

以下の例を見て、より多くの洞察を得ましょう-

まず、インポート PunktSentenceTokenizer からのクラス nltk.tokenize パッケージ-

from nltk.tokenize import PunktSentenceTokenizer

今、インポート webtext コーパスから nltk.corpus パッケージ

from nltk.corpus import webtext

次に、 raw() メソッド、から生のテキストを取得します training_tokenizer.txt 次のようにファイル-

text = webtext.raw('C://Users/Leekha/training_tokenizer.txt')

次に、のインスタンスを作成します PunktSentenceTokenizer 次のようにテキストファイルからトークン化文を印刷します-

sent_tokenizer = PunktSentenceTokenizer(text)
sents_1 = sent_tokenizer.tokenize(text)
print(sents_1[0])

出力

White guy: So, do you have any plans for this evening?
print(sents_1[1])
Output:
Asian girl: Yeah, being angry!
print(sents_1[670])
Output:
Guy: A hundred bucks?
print(sents_1[675])
Output:
Girl: But you already have a Big Mac...

完全な実装例

from nltk.tokenize import PunktSentenceTokenizer
from nltk.corpus import webtext
text = webtext.raw('C://Users/Leekha/training_tokenizer.txt')
sent_tokenizer = PunktSentenceTokenizer(text)
sents_1 = sent_tokenizer.tokenize(text)
print(sents_1[0])

出力

White guy: So, do you have any plans for this evening?

NLTKのデフォルトのセンテンストークナイザーと独自のトレーニング済みセンテンストークナイザーの違いを理解するために、同じファイルをデフォルトのセンテンストークナイザー(sent_tokenize())でトークン化してみましょう。

from nltk.tokenize import sent_tokenize
   from nltk.corpus import webtext
   text = webtext.raw('C://Users/Leekha/training_tokenizer.txt')
sents_2 = sent_tokenize(text)

print(sents_2[0])
Output:

White guy: So, do you have any plans for this evening?
print(sents_2[675])
Output:
Hobo: Y'know what I'd do if I was rich?

出力の違いの助けを借りて、私たちはなぜ私たち自身のセンテンストークナイザーを訓練することが有用であるかという概念を理解することができます。

ストップワードとは何ですか?

テキストには存在するが、文の意味には寄与しないいくつかの一般的な単語。このような単語は、情報検索や自然言語処理の目的ではまったく重要ではありません。最も一般的なストップワードは「the」と「a」です。

NLTKストップワードコーパス

実際、Natural Language Toolキットには、多くの言語の単語リストを含むストップワードコーパスが付属しています。次の例を参考にして、その使用法を理解しましょう。

まず、nltk.corpusパッケージからストップワードコーパスをインポートします-

from nltk.corpus import stopwords

今、私たちは英語のストップワードを使用します

english_stops = set(stopwords.words('english'))
words = ['I', 'am', 'a', 'writer']
[word for word in words if word not in english_stops]

出力

['I', 'writer']

完全な実装例

from nltk.corpus import stopwords
english_stops = set(stopwords.words('english'))
words = ['I', 'am', 'a', 'writer']
[word for word in words if word not in english_stops]

出力

['I', 'writer']

サポートされている言語の完全なリストを見つける

次のPythonスクリプトの助けを借りて、NLTKストップワードコーパスでサポートされている言語の完全なリストを見つけることもできます-

from nltk.corpus import stopwords
stopwords.fileids()

出力

[
   'arabic', 'azerbaijani', 'danish', 'dutch', 'english', 'finnish', 'french',
   'german', 'greek', 'hungarian', 'indonesian', 'italian', 'kazakh', 'nepali',
   'norwegian', 'portuguese', 'romanian', 'russian', 'slovene', 'spanish',
   'swedish', 'tajik', 'turkish'
]

Wordnetとは何ですか?

Wordnetは、プリンストンによって作成された英語の大規模な語彙データベースです。これはNLTKコーパスの一部です。名詞、動詞、形容詞、副詞はすべて、一連の同義語、つまり認知同義語にグループ化されます。ここで、シンセットの各セットは異なる意味を表します。以下はWordnetのいくつかのユースケースです-

  • 単語の定義を調べるために使用できます
  • 単語の同義語と反意語を見つけることができます
  • Wordnetを使用して単語の関係と類似性を調べることができます
  • 複数の用途と定義を持つ単語の語義の曖昧性解消

Wordnetをインポートする方法は?

Wordnetは、次のコマンドを使用してインポートできます-

from nltk.corpus import wordnet

よりコンパクトなコマンドを使用するには、次を使用します-

from nltk.corpus import wordnet as wn

Synsetインスタンス

Synsetは、同じ概念を表す同義語のグループです。Wordnetを使用して単語を検索すると、Synsetインスタンスのリストが表示されます。

wordnet.synsets(word)

Synsetのリストを取得するには、Wordnetで任意の単語を検索します。 wordnet.synsets(word)。たとえば、次のPythonレシピでは、Synsetのいくつかのプロパティとメソッドとともに「dog」のSynsetを検索します。

まず、次のようにワードネットをインポートします-

from nltk.corpus import wordnet as wn

ここで、Synsetを検索する単語を入力します-

syn = wn.synsets('dog')[0]

ここでは、name()メソッドを使用して、Synsetを直接取得するために使用できるSynsetの一意の名前を取得しています。

syn.name()
Output:
'dog.n.01'

次に、単語の定義を提供するdefinition()メソッドを使用しています-

syn.definition()
Output:
'a member of the genus Canis (probably descended from the common wolf) that has
been domesticated by man since prehistoric times; occurs in many breeds'

別のメソッドはexamples()で、これは単語−に関連する例を示します。

syn.examples()
Output:
['the dog barked all night']

完全な実装例

from nltk.corpus import wordnet as wn
syn = wn.synsets('dog')[0]
syn.name()
syn.definition()
syn.examples()

上位概念の取得

シンセットは、継承ツリーのような構造で編成されています。 Hypernyms より抽象的な用語を表しますが Hyponymsより具体的な用語を表します。重要なことの1つは、このツリーをルートの上位概念までたどることができるということです。次の例を参考にして、概念を理解しましょう。

from nltk.corpus import wordnet as wn
syn = wn.synsets('dog')[0]
syn.hypernyms()

出力

[Synset('canine.n.02'), Synset('domestic_animal.n.01')]

ここで、canineとdomestic_animalが「犬」の上位概念であることがわかります。

これで、「犬」の下位概念を次のように見つけることができます-

syn.hypernyms()[0].hyponyms()

出力

[
   Synset('bitch.n.04'),
   Synset('dog.n.01'),
   Synset('fox.n.01'),
   Synset('hyena.n.01'),
   Synset('jackal.n.01'),
   Synset('wild_dog.n.01'),
   Synset('wolf.n.01')
]

上記の出力から、「犬」は「domestic_animals」の多くの下位概念の1つにすぎないことがわかります。

これらすべてのルートを見つけるには、次のコマンドを使用できます-

syn.root_hypernyms()

出力

[Synset('entity.n.01')]

上記の出力から、ルートが1つしかないことがわかります。

完全な実装例

from nltk.corpus import wordnet as wn
syn = wn.synsets('dog')[0]
syn.hypernyms()
syn.hypernyms()[0].hyponyms()
syn.root_hypernyms()

出力

[Synset('entity.n.01')]

Wordnetの見出語

言語学では、単語の正規形または形態学的形は補題と呼ばれます。単語の同義語と反意語を見つけるために、WordNetで見出語を検索することもできます。その方法を見てみましょう。

同義語の検索

lemma()メソッドを使用することにより、Synsetの同義語の数を見つけることができます。このメソッドを「dog」シンセットに適用してみましょう-

from nltk.corpus import wordnet as wn
syn = wn.synsets('dog')[0]
lemmas = syn.lemmas()
len(lemmas)

出力

3

上記の出力は、「犬」に3つの見出語があることを示しています。

次のように最初の補題の名前を取得する-

lemmas[0].name()
Output:
'dog'

次のように2番目の補題の名前を取得する-

lemmas[1].name()
Output:
'domestic_dog'

次のように3番目の補題の名前を取得する-

lemmas[2].name()
Output:
'Canis_familiaris'

実際、Synsetはすべて同じ意味を持つ補題のグループを表し、補題は異なる単語形式を表します。

アントニムを見つける

WordNetでは、一部の見出語にも反意語があります。たとえば、「良い」という単語には合計27のシネットがあり、そのうち5つには見出語があります。反意語を見つけましょう(「good」という単語が名詞として使用されている場合と「good」という単語が形容詞として使用されている場合)。

例1

from nltk.corpus import wordnet as wn
   syn1 = wn.synset('good.n.02')
   antonym1 = syn1.lemmas()[0].antonyms()[0]
antonym1.name()

出力

'evil'

antonym1.synset().definition()

出力

'the quality of being morally wrong in principle or practice'

上記の例は、「善」という単語が名詞として使用される場合、最初の反意語「悪」を持っていることを示しています。

例2

from nltk.corpus import wordnet as wn
   syn2 = wn.synset('good.a.01')
   antonym2 = syn2.lemmas()[0].antonyms()[0]
antonym2.name()

出力

'bad'

antonym2.synset().definition()

出力

'having undesirable or negative qualities’

上記の例は、「良い」という単語が形容詞として使用される場合、最初の反意語「悪い」を持っていることを示しています。

ステミングとは何ですか?

ステミングは、接辞を削除して単語の基本形を抽出するために使用される手法です。木の枝を茎まで切り倒すようなものです。たとえば、単語の語幹eating, eats, eaten です eat

検索エンジンは、単語のインデックス作成にステミングを使用します。そのため、検索エンジンはすべての形式の単語を保存するのではなく、語幹のみを保存できます。このようにして、ステミングはインデックスのサイズを縮小し、検索の精度を高めます。

さまざまなステミングアルゴリズム

NLTKでは、 stemmerIstem()メソッド、インターフェイスには、次に説明するすべてのステマーがあります。次の図で理解しましょう

ポーターステミングアルゴリズム

これは最も一般的なステミングアルゴリズムの1つであり、基本的に英語の単語のよく知られた接尾辞を削除して置き換えるように設計されています。

PorterStemmerクラス

NLTKは PorterStemmer語幹にしたい単語に対してPorterStemmerアルゴリズムを簡単に実装できるクラス。このクラスは、入力単語を最終的な語幹に変換できる助けを借りて、いくつかの通常の単語形式と接尾辞を知っています。結果として得られる語幹は、多くの場合、同じ語根の意味を持つ短い単語です。例を見てみましょう-

まず、自然言語ツールキット(nltk)をインポートする必要があります。

import nltk

今、インポートします PorterStemmer PorterStemmerアルゴリズムを実装するクラス。

from nltk.stem import PorterStemmer

次に、次のようにPorterStemmerクラスのインスタンスを作成します-

word_stemmer = PorterStemmer()

ここで、語幹にしたい単語を入力します。

word_stemmer.stem('writing')

出力

'write'

word_stemmer.stem('eating')

出力

'eat'

完全な実装例

import nltk
from nltk.stem import PorterStemmer
word_stemmer = PorterStemmer()
word_stemmer.stem('writing')

出力

'write'

ランカスターステミングアルゴリズム

これはランカスター大学で開発されたもので、もう1つの非常に一般的なステミングアルゴリズムです。

LancasterStemmerクラス

NLTKは LancasterStemmer語幹にしたい単語に対してランカスターステマーアルゴリズムを簡単に実装できるクラス。例を見てみましょう-

まず、自然言語ツールキット(nltk)をインポートする必要があります。

import nltk

今、インポートします LancasterStemmer LancasterStemmerアルゴリズムを実装するクラス

from nltk.stem import LancasterStemmer

次に、のインスタンスを作成します LancasterStemmer 次のようにクラス-

Lanc_stemmer = LancasterStemmer()

ここで、語幹にしたい単語を入力します。

Lanc_stemmer.stem('eats')

出力

'eat'

完全な実装例

import nltk
from nltk.stem import LancatserStemmer
Lanc_stemmer = LancasterStemmer()
Lanc_stemmer.stem('eats')

出力

'eat'

正規表現ステミングアルゴリズム

このステミングアルゴリズムの助けを借りて、独自のステマーを構築できます。

RegexpStemmerクラス

NLTKは RegexpStemmer正規表現ステマーアルゴリズムを簡単に実装できるクラス。基本的に単一の正規表現を取り、式に一致するプレフィックスまたはサフィックスを削除します。例を見てみましょう-

まず、自然言語ツールキット(nltk)をインポートする必要があります。

import nltk

今、インポートします RegexpStemmer 正規表現ステマーアルゴリズムを実装するクラス。

from nltk.stem import RegexpStemmer

次に、のインスタンスを作成します RegexpStemmer クラスと次のように単語から削除したい接尾辞または接頭辞を提供します-

Reg_stemmer = RegexpStemmer(‘ing’)

ここで、語幹にしたい単語を入力します。

Reg_stemmer.stem('eating')

出力

'eat'

Reg_stemmer.stem('ingeat')

出力

'eat'
Reg_stemmer.stem('eats')

出力

'eat'

完全な実装例

import nltk
from nltk.stem import RegexpStemmer
Reg_stemmer = RegexpStemmer()
Reg_stemmer.stem('ingeat')

出力

'eat'

スノーボールステミングアルゴリズム

これは、もう1つの非常に便利なステミングアルゴリズムです。

SnowballStemmerクラス

NLTKは SnowballStemmerSnowballStemmerアルゴリズムを簡単に実装できるクラス。15の英語以外の言語をサポートします。このsteamingクラスを使用するには、使用している言語の名前でインスタンスを作成してから、stem()メソッドを呼び出す必要があります。例を見てみましょう-

まず、自然言語ツールキット(nltk)をインポートする必要があります。

import nltk

今、インポートします SnowballStemmer SnowballStemmerアルゴリズムを実装するクラス

from nltk.stem import SnowballStemmer

サポートされている言語を見てみましょう-

SnowballStemmer.languages

出力

(
   'arabic',
   'danish',
   'dutch',
   'english',
   'finnish',
   'french',
   'german',
   'hungarian',
   'italian',
   'norwegian',
   'porter',
   'portuguese',
   'romanian',
   'russian',
   'spanish',
   'swedish'
)

次に、使用する言語でSnowballStemmerクラスのインスタンスを作成します。ここでは、「フランス語」言語のステマーを作成しています。

French_stemmer = SnowballStemmer(‘french’)

次に、stem()メソッドを呼び出して、ステミングする単語を入力します。

French_stemmer.stem (‘Bonjoura’)

出力

'bonjour'

完全な実装例

import nltk
from nltk.stem import SnowballStemmer
French_stemmer = SnowballStemmer(‘french’)
French_stemmer.stem (‘Bonjoura’)

出力

'bonjour'

Lemmatizationとは何ですか?

Lemmatizationテクニックはステミングのようなものです。補題の後に得られる出力は「補題」と呼ばれます。これは、語幹の出力である語幹ではなく、語幹です。レンマ化後、同じことを意味する有効な単語を取得します。

NLTKは提供します WordNetLemmatizer の周りの薄いラッパーであるクラス wordnetコーパス。このクラスはmorphy() 機能する WordNet CorpusReader補題を見つけるためのクラス。例を挙げて理解しましょう−

まず、自然言語ツールキット(nltk)をインポートする必要があります。

import nltk

今、インポートします WordNetLemmatizer レンマ化手法を実装するクラス。

from nltk.stem import WordNetLemmatizer

次に、のインスタンスを作成します WordNetLemmatizer クラス。

lemmatizer = WordNetLemmatizer()

ここで、lemmatize()メソッドを呼び出して、補題を見つけたい単語を入力します。

lemmatizer.lemmatize('eating')

出力

'eating'
lemmatizer.lemmatize('books')

出力

'book'

完全な実装例

import nltk
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
lemmatizer.lemmatize('books')

出力

'book'

ステミングとレマタイゼーションの違い

次の例を使用して、ステミングとレマタイゼーションの違いを理解しましょう。

import nltk
from nltk.stem import PorterStemmer
word_stemmer = PorterStemmer()
word_stemmer.stem('believes')

出力

believ

import nltk
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
lemmatizer.lemmatize(' believes ')

出力

believ

両方のプログラムの出力は、ステミングとレンマ化の主な違いを示しています。 PorterStemmerクラスは単語から「es」を切り落とします。一方、WordNetLemmatizerクラスは有効な単語を見つけます。簡単に言えば、ステミング技法は単語の形式のみを調べますが、レンマ化技法は単語の意味を調べます。これは、レンマ化を適用した後、常に有効な単語を取得することを意味します。

ステミングとレンマ化は、一種の言語的圧縮と見なすことができます。同じ意味で、単語の置換は、テキストの正規化またはエラー訂正と考えることができます。

しかし、なぜ単語の置換が必要なのですか?トークン化について話す場合、収縮に問題があると仮定します(できない、できないなど)。したがって、このような問題を処理するには、単語を置き換える必要があります。たとえば、縮約を拡張された形式に置き換えることができます。

正規表現を使用した単語の置換

まず、正規表現に一致する単語を置き換えます。ただし、このためには、正規表現とpythonreモジュールの基本的な理解が必要です。以下の例では、正規表現を使用して、短縮形を拡張形式に置き換えます(たとえば、「できない」は「できない」に置き換えられます)。

まず、正規表現を使用するために必要なパッケージをインポートします。

import re
from nltk.corpus import wordnet

次に、選択した置換パターンを次のように定義します-

R_patterns = [
   (r'won\'t', 'will not'),
   (r'can\'t', 'cannot'),
   (r'i\'m', 'i am'),
   r'(\w+)\'ll', '\g<1> will'),
   (r'(\w+)n\'t', '\g<1> not'),
   (r'(\w+)\'ve', '\g<1> have'),
   (r'(\w+)\'s', '\g<1> is'),
   (r'(\w+)\'re', '\g<1> are'),
]

次に、単語の置換に使用できるクラスを作成します-

class REReplacer(object):
   def __init__(self, pattern = R_patterns):
      self.pattern = [(re.compile(regex), repl) for (regex, repl) in patterns]
   def replace(self, text):
      s = text
      for (pattern, repl) in self.pattern:
         s = re.sub(pattern, repl, s)
      return s

このPythonプログラム(たとえばrepRE.py)を保存し、Pythonコマンドプロンプトから実行します。実行後、単語を置き換える場合はREReplacerクラスをインポートします。その方法を見てみましょう。

from repRE import REReplacer
rep_word = REReplacer()
rep_word.replace("I won't do it")
Output:
'I will not do it'
rep_word.replace("I can’t do it")
Output:
'I cannot do it'

完全な実装例

import re
from nltk.corpus import wordnet
R_patterns = [
   (r'won\'t', 'will not'),
   (r'can\'t', 'cannot'),
   (r'i\'m', 'i am'),
   r'(\w+)\'ll', '\g<1> will'),
   (r'(\w+)n\'t', '\g<1> not'),
   (r'(\w+)\'ve', '\g<1> have'),
   (r'(\w+)\'s', '\g<1> is'),
   (r'(\w+)\'re', '\g<1> are'),
]
class REReplacer(object):
def __init__(self, patterns=R_patterns):
   self.patterns = [(re.compile(regex), repl) for (regex, repl) in patterns]
def replace(self, text):
   s = text
   for (pattern, repl) in self.patterns:
      s = re.sub(pattern, repl, s)
   return s

上記のプログラムを保存して実行すると、クラスをインポートして次のように使用できます。

from replacerRE import REReplacer
rep_word = REReplacer()
rep_word.replace("I won't do it")

出力

'I will not do it'

テキスト処理前の置換

自然言語処理(NLP)を使用する際の一般的な方法の1つは、テキスト処理の前にテキストをクリーンアップすることです。この懸念では、私たちも使用することができますREReplacer 前の例で上記で作成されたクラス。テキスト処理、つまりトークン化の前の準備ステップとして。

from nltk.tokenize import word_tokenize
from replacerRE import REReplacer
rep_word = REReplacer()
word_tokenize("I won't be able to do this now")
Output:
['I', 'wo', "n't", 'be', 'able', 'to', 'do', 'this', 'now']
word_tokenize(rep_word.replace("I won't be able to do this now"))
Output:
['I', 'will', 'not', 'be', 'able', 'to', 'do', 'this', 'now']

上記のPythonレシピでは、正規表現置換を使用しない場合と使用する場合の単語トークナイザーの出力の違いを簡単に理解できます。

繰り返し文字の削除

私たちは日常の言語で厳密に文法的ですか?ちがうよ。たとえば、「こんにちは」という単語を強調するために、「HiiiiiiiiiiiiMohan」と書くことがあります。しかし、コンピュータシステムは、「Hiiiiiiiiiiii」が「Hi」という単語のバリエーションであることを認識していません。以下の例では、という名前のクラスを作成しますrep_word_removal 繰り返し単語を削除するために使用できます。

まず、正規表現を使用するために必要なパッケージをインポートします

import re
from nltk.corpus import wordnet

ここで、繰り返し単語を削除するために使用できるクラスを作成します-

class Rep_word_removal(object):
   def __init__(self):
      self.repeat_regexp = re.compile(r'(\w*)(\w)\2(\w*)')
      self.repl = r'\1\2\3'
   def replace(self, word):
      if wordnet.synsets(word):
      return word
   repl_word = self.repeat_regexp.sub(self.repl, word)
   if repl_word != word:
      return self.replace(repl_word)
   else:
      return repl_word

このPythonプログラム(removalrepeat.pyなど)を保存し、Pythonコマンドプロンプトから実行します。実行後、インポートRep_word_removal繰り返し単語を削除したいときのクラス。どのように見てみましょう?

from removalrepeat import Rep_word_removal
rep_word = Rep_word_removal()
rep_word.replace ("Hiiiiiiiiiiiiiiiiiiiii")
Output:
'Hi'
rep_word.replace("Hellooooooooooooooo")
Output:
'Hello'

完全な実装例

import re
from nltk.corpus import wordnet
class Rep_word_removal(object):
   def __init__(self):
      self.repeat_regexp = re.compile(r'(\w*)(\w)\2(\w*)')
      self.repl = r'\1\2\3'
   def replace(self, word):
      if wordnet.synsets(word):
         return word
   replace_word = self.repeat_regexp.sub(self.repl, word)
   if replace_word != word:
      return self.replace(replace_word)
   else:
      return replace_word

上記のプログラムを保存して実行すると、クラスをインポートして次のように使用できます。

from removalrepeat import Rep_word_removal
rep_word = Rep_word_removal()
rep_word.replace ("Hiiiiiiiiiiiiiiiiiiiii")

出力

'Hi'

単語を一般的な同義語に置き換える

NLPを使用している間、特に頻度分析とテキストインデックス作成の場合は、多くのメモリを節約できるため、意味を失うことなく語彙を圧縮することが常に有益です。これを実現するには、単語の同義語へのマッピングを定義する必要があります。以下の例では、という名前のクラスを作成しますword_syn_replacer これは、単語を一般的な同義語に置き換えるために使用できます。

まず、必要なパッケージをインポートします re 正規表現を操作します。

import re
from nltk.corpus import wordnet

次に、単語置換マッピングをとるクラスを作成します-

class word_syn_replacer(object):
   def __init__(self, word_map):
   self.word_map = word_map
def replace(self, word):
   return self.word_map.get(word, word)

このPythonプログラム(たとえばreplacesyn.py)を保存し、Pythonコマンドプロンプトから実行します。実行後、インポートword_syn_replacer単語を一般的な同義語に置き換えたい場合のクラス。その方法を見てみましょう。

from replacesyn import word_syn_replacer
rep_syn = word_syn_replacer ({‘bday’: ‘birthday’)
rep_syn.replace(‘bday’)

出力

'birthday'

完全な実装例

import re
from nltk.corpus import wordnet
class word_syn_replacer(object):
   def __init__(self, word_map):
   self.word_map = word_map
def replace(self, word):
   return self.word_map.get(word, word)

上記のプログラムを保存して実行すると、クラスをインポートして次のように使用できます。

from replacesyn import word_syn_replacer
rep_syn = word_syn_replacer ({‘bday’: ‘birthday’)
rep_syn.replace(‘bday’)

出力

'birthday'

上記の方法の欠点は、Python辞書に同義語をハードコーディングする必要があることです。CSVファイルとYAMLファイルの形式で2つのより良い選択肢があります。同義語の語彙を上記のファイルのいずれかに保存して、構築することができますword_mapそれらからの辞書。例を使って概念を理解しましょう。

CSVファイルを使用する

この目的でCSVファイルを使用するには、ファイルに2つの列が必要です。最初の列は単語で構成され、2番目の列はそれを置き換えるための同義語で構成されます。このファイルを次のように保存しましょうsyn.csv. 以下の例では、という名前のクラスを作成します CSVword_syn_replacer 伸びる word_syn_replacerreplacesyn.py ファイルとを構築するために使用されます word_map からの辞書 syn.csv ファイル。

まず、必要なパッケージをインポートします。

import csv

次に、単語置換マッピングをとるクラスを作成します-

class CSVword_syn_replacer(word_syn_replacer):
   def __init__(self, fname):
      word_map = {}
      for line in csv.reader(open(fname)):
         word, syn = line
         word_map[word] = syn
      super(Csvword_syn_replacer, self).__init__(word_map)

実行後、インポート CSVword_syn_replacer単語を一般的な同義語に置き換えたい場合のクラス。どのように見てみましょう?

from replacesyn import CSVword_syn_replacer
rep_syn = CSVword_syn_replacer (‘syn.csv’)
rep_syn.replace(‘bday’)

出力

'birthday'

完全な実装例

import csv
class CSVword_syn_replacer(word_syn_replacer):
def __init__(self, fname):
word_map = {}
for line in csv.reader(open(fname)):
   word, syn = line
   word_map[word] = syn
super(Csvword_syn_replacer, self).__init__(word_map)

上記のプログラムを保存して実行すると、クラスをインポートして次のように使用できます。

from replacesyn import CSVword_syn_replacer
rep_syn = CSVword_syn_replacer (‘syn.csv’)
rep_syn.replace(‘bday’)

出力

'birthday'

YAMLファイルを使用する

CSVファイルを使用したので、この目的でYAMLファイルを使用することもできます(PyYAMLをインストールする必要があります)。ファイルを次のように保存しましょうsyn.yaml. 以下の例では、という名前のクラスを作成します YAMLword_syn_replacer 伸びる word_syn_replacerreplacesyn.py ファイルとを構築するために使用されます word_map からの辞書 syn.yaml ファイル。

まず、必要なパッケージをインポートします。

import yaml

次に、単語置換マッピングをとるクラスを作成します-

class YAMLword_syn_replacer(word_syn_replacer):
   def __init__(self, fname):
   word_map = yaml.load(open(fname))
   super(YamlWordReplacer, self).__init__(word_map)

実行後、インポート YAMLword_syn_replacer単語を一般的な同義語に置き換えたい場合のクラス。どのように見てみましょう?

from replacesyn import YAMLword_syn_replacer
rep_syn = YAMLword_syn_replacer (‘syn.yaml’)
rep_syn.replace(‘bday’)

出力

'birthday'

完全な実装例

import yaml
class YAMLword_syn_replacer(word_syn_replacer):
def __init__(self, fname):
   word_map = yaml.load(open(fname))
   super(YamlWordReplacer, self).__init__(word_map)

上記のプログラムを保存して実行すると、クラスをインポートして次のように使用できます。

from replacesyn import YAMLword_syn_replacer
rep_syn = YAMLword_syn_replacer (‘syn.yaml’)
rep_syn.replace(‘bday’)

出力

'birthday'

アントニムの交換

反意語は別の単語とは逆の意味を持つ単語であり、同義語の置換の反対は反意語の置換と呼ばれます。このセクションでは、反意語の置換、つまりWordNetを使用して単語を明確な反意語に置換する方法について説明します。以下の例では、という名前のクラスを作成しますword_antonym_replacer 単語を置き換える方法と否定を削除する方法の2つの方法があります。

まず、必要なパッケージをインポートします。

from nltk.corpus import wordnet

次に、という名前のクラスを作成します word_antonym_replacer

class word_antonym_replacer(object):
   def replace(self, word, pos=None):
      antonyms = set()
      for syn in wordnet.synsets(word, pos=pos):
         for lemma in syn.lemmas():
            for antonym in lemma.antonyms():
               antonyms.add(antonym.name())
      if len(antonyms) == 1:
         return antonyms.pop()
      else:
         return None
   def replace_negations(self, sent):
      i, l = 0, len(sent)
      words = []
      while i < l:
         word = sent[i]
         if word == 'not' and i+1 < l:
            ant = self.replace(sent[i+1])
            if ant:
               words.append(ant)
               i += 2
               continue
         words.append(word)
         i += 1
      return words

このPythonプログラム(replaceantonym.pyなど)を保存し、Pythonコマンドプロンプトから実行します。実行後、インポートword_antonym_replacer単語を明確な反意語に置き換えたい場合のクラス。その方法を見てみましょう。

from replacerantonym import word_antonym_replacer
rep_antonym = word_antonym_replacer ()
rep_antonym.replace(‘uglify’)

出力

['beautify'']
sentence = ["Let us", 'not', 'uglify', 'our', 'country']
rep_antonym.replace _negations(sentence)

出力

["Let us", 'beautify', 'our', 'country']

完全な実装例

nltk.corpus import wordnet
class word_antonym_replacer(object):
def replace(self, word, pos=None):
   antonyms = set()
   for syn in wordnet.synsets(word, pos=pos):
      for lemma in syn.lemmas():
      for antonym in lemma.antonyms():
         antonyms.add(antonym.name())
   if len(antonyms) == 1:
      return antonyms.pop()
   else:
      return None
def replace_negations(self, sent):
   i, l = 0, len(sent)
   words = []
   while i < l:
      word = sent[i]
      if word == 'not' and i+1 < l:
         ant = self.replace(sent[i+1])
         if ant:
            words.append(ant)
            i += 2
            continue
      words.append(word)
      i += 1
   return words

上記のプログラムを保存して実行すると、クラスをインポートして次のように使用できます。

from replacerantonym import word_antonym_replacer
rep_antonym = word_antonym_replacer ()
rep_antonym.replace(‘uglify’)
sentence = ["Let us", 'not', 'uglify', 'our', 'country']
rep_antonym.replace _negations(sentence)

出力

["Let us", 'beautify', 'our', 'country']

コーパスとは何ですか?

コーパスは、自然なコミュニケーション環境で作成された、機械で読み取り可能なテキストの構造化された形式の大規模なコレクションです。コーパスという言葉は、コーパスの複数形です。コーパスは次のように多くの方法で導き出すことができます-

  • 元々電子的だったテキストから
  • 話し言葉の書き起こしから
  • 光学式文字認識などから

コーパスの代表性、コーパスバランス、サンプリング、コーパスサイズは、コーパスを設計する際に重要な役割を果たす要素です。NLPタスクで最も人気のあるコーパスには、TreeBank、PropBank、VarbNet、WordNetがあります。

カスタムコーパスを構築する方法は?

NLTKのダウンロード中に、NLTKデータパッケージもインストールしました。したがって、すでにNLTKデータパッケージがコンピューターにインストールされています。Windowsについて話す場合、このデータパッケージはにインストールされていると想定します。C:\natural_language_toolkit_data Linux、Unix、Mac OS Xについて話す場合、このデータパッケージはにインストールされていると想定します。 /usr/share/natural_language_toolkit_data

次のPythonレシピでは、NLTKで定義されたパスの1つ内にある必要があるカスタムコーパスを作成します。それはNLTKによって見つけることができるからです。公式のNLTKデータパッケージとの競合を避けるために、ホームディレクトリにカスタムのnatural_language_toolkit_dataディレクトリを作成しましょう。

import os, os.path
path = os.path.expanduser('~/natural_language_toolkit_data')
if not os.path.exists(path):
   os.mkdir(path)
os.path.exists(path)

出力

True

それでは、ホームディレクトリにnatural_language_toolkit_dataディレクトリがあるかどうかを確認しましょう-

import nltk.data
path in nltk.data.path

出力

True

出力Trueを取得したので、 nltk_data ホームディレクトリのディレクトリ。

次に、という名前のワードリストファイルを作成します wordfile.txt コーパスという名前のフォルダに入れます nltk_data ディレクトリ (~/nltk_data/corpus/wordfile.txt) を使用してロードします nltk.data.load

import nltk.data
nltk.data.load(‘corpus/wordfile.txt’, format = ‘raw’)

出力

b’tutorialspoint\n’

コーパスリーダー

NLTKは、さまざまなCorpusReaderクラスを提供します。次のPythonレシピでそれらをカバーします

ワードリストコーパスの作成

NLTKは WordListCorpusReader単語のリストを含むファイルへのアクセスを提供するクラス。次のPythonレシピでは、CSVまたは通常のテキストファイルのワードリストファイルを作成する必要があります。たとえば、次のデータを含む「list」という名前のファイルを作成しました-

tutorialspoint
Online
Free
Tutorials

今、インスタンス化しましょう WordListCorpusReader 作成したファイルから単語のリストを生成するクラス ‘list’

from nltk.corpus.reader import WordListCorpusReader
reader_corpus = WordListCorpusReader('.', ['list'])
reader_corpus.words()

出力

['tutorialspoint', 'Online', 'Free', 'Tutorials']

POSタグ付き単語コーパスの作成

NLTKは TaggedCorpusReaderPOSタグ付き単語コーパスを作成できるクラス。実際、POSタグ付けは、単語の品詞タグを識別するプロセスです。

タグ付きコーパスの最も単純な形式の1つは、茶色のコーパスからの抜粋に続く「単語/タグ」の形式です。

The/at-tl expense/nn and/cc time/nn involved/vbn are/ber
astronomical/jj ./.

上記の抜粋では、各単語にはそのPOSを示すタグがあります。例えば、vb 動詞を指します。

今、インスタンス化しましょう TaggedCorpusReaderファイルからPOSタグ付き単語を生成するクラス ‘list.pos’、上記の抜粋があります。

from nltk.corpus.reader import TaggedCorpusReader
reader_corpus = TaggedCorpusReader('.', r'.*\.pos')
reader_corpus.tagged_words()

出力

[('The', 'AT-TL'), ('expense', 'NN'), ('and', 'CC'), ...]

チャンクフレーズコーパスの作成

NLTKは ChnkedCorpusReaderチャンクフレーズコーパスを作成できるクラス。実際、チャンクは文中の短いフレーズです。

たとえば、タグ付けされたものから次の抜粋があります treebank コーパス-

[Earlier/JJR staff-reduction/NN moves/NNS] have/VBP trimmed/VBN about/
IN [300/CD jobs/NNS] ,/, [the/DT spokesman/NN] said/VBD ./.

上記の抜粋では、すべてのチャンクは名詞句ですが、括弧で囲まれていない単語は文ツリーの一部であり、名詞句サブツリーの一部ではありません。

今、インスタンス化しましょう ChunkedCorpusReader ファイルからチャンクフレーズを生成するクラス ‘list.chunk’、上記の抜粋があります。

from nltk.corpus.reader import ChunkedCorpusReader
reader_corpus = TaggedCorpusReader('.', r'.*\.chunk')
reader_corpus.chunked_words()

出力

[
   Tree('NP', [('Earlier', 'JJR'), ('staff-reduction', 'NN'), ('moves', 'NNS')]),
   ('have', 'VBP'), ...
]

分類されたテキストコーパスの作成

NLTKは CategorizedPlaintextCorpusReader分類されたテキストコーパスを作成できるクラス。大量のテキストがあり、それを別々のセクションに分類したい場合に非常に便利です。

たとえば、茶色のコーパスにはいくつかの異なるカテゴリがあります。次のPythonコードの助けを借りてそれらを見つけましょう-

from nltk.corpus import brown^M
brown.categories()

出力

[
   'adventure', 'belles_lettres', 'editorial', 'fiction', 'government',
   'hobbies', 'humor', 'learned', 'lore', 'mystery', 'news', 'religion',
   'reviews', 'romance', 'science_fiction'
]

コーパスを分類する最も簡単な方法の1つは、カテゴリごとに1つのファイルを用意することです。たとえば、からの2つの抜粋を見てみましょう。movie_reviews コーパス-

movie_pos.txt

細い赤い線には欠陥がありますが、それは誘発します。

movie_neg.txt

巨額の予算と光沢のある作品は、彼らのテレビ番組に浸透している自発性の欠如を補うことはできません。

したがって、上記の2つのファイルから、2つのカテゴリがあります。 pos そして neg

次に、インスタンス化しましょう CategorizedPlaintextCorpusReader クラス。

from nltk.corpus.reader import CategorizedPlaintextCorpusReader
reader_corpus = CategorizedPlaintextCorpusReader('.', r'movie_.*\.txt',
cat_pattern = r'movie_(\w+)\.txt')
reader_corpus.categories()
reader_corpus.fileids(categories = [‘neg’])
reader_corpus.fileids(categories = [‘pos’])

出力

['neg', 'pos']
['movie_neg.txt']
['movie_pos.txt']

POSタグ付けとは何ですか?

分類の一種であるタグ付けは、トークンの説明の自動割り当てです。記述子を「タグ」と呼びます。これは、品詞(名詞、動詞、副詞、形容詞、代名詞、接続詞とそのサブカテゴリ)、意味情報などの1つを表します。

一方、品詞(POS)のタグ付けについて話す場合、それは単語のリストの形式の文をタプルのリストに変換するプロセスとして定義される場合があります。ここで、タプルは(word、tag)の形式です。品詞の1つを特定の単語に割り当てるプロセスをPOSタグ付けと呼ぶこともできます。

次の表は、ペンツリーバンクコーパスで使用される最も頻繁なPOS通知を表しています。

シニア番号 鬼ごっこ 説明
1 NNP 固有名詞、単数
2 NNPS 固有名詞、複数形
3 PDT 事前限定詞
4 POS 所有格エンディング
5 PRP 人称代名詞
6 PRP $ 所有代名詞
7 RB 副詞
8 RBR 副詞、比較級
9 RBS 副詞、最上級
10 RP 粒子
11 SYM 記号(数学または科学)
12
13 ええと 間投詞
14 VB 動詞、基本形
15 VBD 動詞、過去形
16 VBG 動詞、動名詞/現在分詞
17 VBN 動詞、過去
18 WP Wh-代名詞
19 WP $ 所有格wh-代名詞
20 WRB Wh-副詞
21 ポンド記号
22 $ ドル記号
23 文-最後の句読点
24 コンマ
25 コロン、セミコロン
26 (( 左角かっこ文字
27 右角かっこ文字
28 「」 ストレート二重引用符
29 ' 開いたままの一重引用符
30 「」 開いたままの二重引用符
31 ' 一重引用符を右閉じる
32 「」 右開きの二重引用符

Pythonの実験でそれを理解しましょう-

import nltk
from nltk import word_tokenize
sentence = "I am going to school"
print (nltk.pos_tag(word_tokenize(sentence)))

出力

[('I', 'PRP'), ('am', 'VBP'), ('going', 'VBG'), ('to', 'TO'), ('school', 'NN')]

なぜPOSタグ付け?

POSタグ付けは、次のようにさらにNLP分析の前提条件として機能するため、NLPの重要な部分です。

  • Chunking
  • 構文解析
  • 情報抽出
  • 機械翻訳
  • 感情分析
  • 文法分析と語義の曖昧性解消

TaggerI-基本クラス

すべてのタガーはNLTKのnltk.tagパッケージにあります。これらのタガーの基本クラスはTaggerI、は、すべてのタガーがこのクラスから継承することを意味します。

Methods − TaggerIクラスには、すべてのサブクラスで実装する必要がある次の2つのメソッドがあります。

  • tag() method −名前が示すように、このメソッドは入力として単語のリストを受け取り、出力としてタグ付けされた単語のリストを返します。

  • evaluate() method −この方法を使用すると、タガーの精度を評価できます。

POSタグ付けのベースライン

POSタグ付けのベースラインまたは基本ステップは次のとおりです。 Default Tagging、NLTKのDefaultTaggerクラスを使用して実行できます。デフォルトのタグ付けは、すべてのトークンに同じPOSタグを割り当てるだけです。デフォルトのタグ付けは、精度の向上を測定するためのベースラインも提供します。

DefaultTaggerクラス

デフォルトのタグ付けは、を使用して実行されます DefaultTagging クラス。単一の引数、つまり適用するタグを取ります。

それはどのように機能しますか?

前に述べたように、すべてのタガーはから継承されます TaggerIクラス。ザ・DefaultTagger から継承されます SequentialBackoffTagger これはのサブクラスです TaggerI class。次の図で理解しましょう-

の一部として SeuentialBackoffTaggerDefaultTagger 次の3つの引数を取るchoose_tag()メソッドを実装する必要があります。

  • トークンのリスト
  • 現在のトークンのインデックス
  • 以前のトークンのリスト、つまり履歴

import nltk
from nltk.tag import DefaultTagger
exptagger = DefaultTagger('NN')
exptagger.tag(['Tutorials','Point'])

出力

[('Tutorials', 'NN'), ('Point', 'NN')]

この例では、最も一般的なタイプの単語である名詞タグを選択しました。また、DefaultTagger 最も一般的なPOSタグを選択するときにも最も役立ちます。

精度評価

ザ・ DefaultTaggerタガーの精度を評価するためのベースラインでもあります。それが私たちが一緒にそれを使うことができる理由ですevaluate()精度を測定する方法。ザ・evaluate() メソッドは、タグ付けされたトークンのリストを、タガーを評価するためのゴールドスタンダードとして受け取ります。

以下は、デフォルトのタガーを使用した例です。 exptagger、上記で作成された、のサブセットの精度を評価するため treebank コーパスタグ付き文-

import nltk
from nltk.tag import DefaultTagger
exptagger = DefaultTagger('NN')
from nltk.corpus import treebank
testsentences = treebank.tagged_sents() [1000:]
exptagger.evaluate (testsentences)

出力

0.13198749536374715

上記の出力は、 NN すべてのタグについて、1000エントリの約13%の精度テストを達成できます。 treebank コーパス。

文のリストにタグを付ける

NLTKは、1つの文にタグを付けるのではなく、 TaggerI クラスはまた私達に提供します tag_sents()文のリストにタグを付けることができる方法。以下は、2つの簡単な文にタグを付けた例です。

import nltk
from nltk.tag import DefaultTagger
exptagger = DefaultTagger('NN')
exptagger.tag_sents([['Hi', ','], ['How', 'are', 'you', '?']])

出力

[
   [
      ('Hi', 'NN'), 
      (',', 'NN')
   ], 
   [
      ('How', 'NN'), 
      ('are', 'NN'),
      ('you', 'NN'), 
      ('?', 'NN')
   ]
]

上記の例では、以前に作成したデフォルトのタガーを使用しました。 exptagger

文のタグ付けを解除する

文のタグを外すこともできます。NLTKは、この目的のためにnltk.tag.untag()メソッドを提供します。タグ付きの文を入力として受け取り、タグなしの単語のリストを提供します。例を見てみましょう-

import nltk
from nltk.tag import untag
untag([('Tutorials', 'NN'), ('Point', 'NN')])

出力

['Tutorials', 'Point']

ユニグラムタガーとは何ですか?

名前が示すように、ユニグラムタガーは、POS(Part-of-Speech)タグを決定するためのコンテキストとして1つの単語のみを使用するタガーです。簡単に言うと、Unigram Taggerはコンテキストベースのタガーであり、そのコンテキストは単一の単語、つまりUnigramです。

それはどのように機能しますか?

NLTKはという名前のモジュールを提供します UnigramTaggerこの目的のために。しかし、その動作を深く掘り下げる前に、次の図を使用して階層を理解しましょう-

上図から、 UnigramTagger から継承されます NgramTagger これはのサブクラスです ContextTagger、から継承します SequentialBackoffTagger

の働き UnigramTagger 次の手順の助けを借りて説明されています-

  • 私たちが見たとおり、 UnigramTagger から継承 ContextTagger、それは実装します context()方法。このcontext() メソッドは、と同じ3つの引数を取ります choose_tag() 方法。

  • 結果として context()メソッドは、モデルの作成にさらに使用される単語トークンになります。モデルが作成されると、トークンという単語も最適なタグを検索するために使用されます。

  • この方法では、 UnigramTagger タグ付けされた文のリストからコンテキストモデルを構築します。

ユニグラムタガーのトレーニング

NLTKの UnigramTagger初期化時にタグ付けされた文のリストを提供することでトレーニングできます。以下の例では、ツリーバンクコーパスのタグ付き文を使用します。そのコーパスの最初の2500文を使用します。

まず、nltkからUniframTaggerモジュールをインポートします-

from nltk.tag import UnigramTagger

次に、使用するコーパスをインポートします。ここではツリーバンクコーパスを使用しています-

from nltk.corpus import treebank

さて、訓練目的のために文章を取りなさい。トレーニング目的で最初の2500文を取得し、タグを付けます-

train_sentences = treebank.tagged_sents()[:2500]

次に、トレーニング目的で使用される文にUnigramTaggerを適用します-

Uni_tagger = UnigramTagger(train_sentences)

テスト目的で、トレーニング目的、つまり2500と同じかそれ以下の文章をいくつか取ります。ここでは、テスト目的で最初の1500を使用しています-

test_sentences = treebank.tagged_sents()[1500:]
Uni_tagger.evaluate(test_sents)

出力

0.8942306156033808

ここでは、単一の単語のルックアップを使用してPOSタグを決定するタガーの精度が約89%になりました。

完全な実装例

from nltk.tag import UnigramTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Uni_tagger = UnigramTagger(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
Uni_tagger.evaluate(test_sentences)

出力

0.8942306156033808

コンテキストモデルのオーバーライド

の階層を示す上の図から UnigramTagger、から継承するすべてのタガーを知っています ContextTagger、独自にトレーニングする代わりに、事前に構築されたモデルを使用できます。この事前に構築されたモデルは、コンテキストキーをタグにマッピングするPython辞書です。そしてのためにUnigramTagger、コンテキストキーは個々の単語ですが、その他の場合は NgramTagger サブクラス、それはタプルになります。

別の単純なモデルをに渡すことで、このコンテキストモデルをオーバーライドできます。 UnigramTaggerトレーニングセットに合格する代わりにクラス。以下の簡単な例の助けを借りてそれを理解しましょう-

from nltk.tag import UnigramTagger
from nltk.corpus import treebank
Override_tagger = UnigramTagger(model = {‘Vinken’ : ‘NN’})
Override_tagger.tag(treebank.sents()[0])

出力

[
   ('Pierre', None),
   ('Vinken', 'NN'),
   (',', None),
   ('61', None),
   ('years', None),
   ('old', None),
   (',', None),
   ('will', None),
   ('join', None),
   ('the', None),
   ('board', None),
   ('as', None),
   ('a', None),
   ('nonexecutive', None),
   ('director', None),
   ('Nov.', None),
   ('29', None),
   ('.', None)
]

モデルには唯一のコンテキストキーとして「Vinken」が含まれているため、上記の出力から、この単語のみがタグを取得し、他のすべての単語はタグとしてNoneを持っていることがわかります。

最小周波数しきい値の設定

特定のコンテキストで最も可能性の高いタグを決定するために、 ContextTaggerクラスは発生頻度を使用します。コンテキストワードとタグが1回だけ出現する場合でも、デフォルトでそれを実行しますが、最小頻度しきい値を設定するには、cutoff の価値 UnigramTaggerクラス。以下の例では、UnigramTaggerをトレーニングした前のレシピのカットオフ値を渡します-

from nltk.tag import UnigramTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Uni_tagger = UnigramTagger(train_sentences, cutoff = 4)
test_sentences = treebank.tagged_sents()[1500:]
Uni_tagger.evaluate(test_sentences)

出力

0.7357651629613641

タガーを組み合わせる

タガーを組み合わせたり、タガーをチェーンしたりすることは、NLTKの重要な機能の1つです。タガーの組み合わせの背後にある主な概念は、1人のタガーが単語にタグを付ける方法を知らない場合、それが連鎖タガーに渡されるということです。この目的を達成するために、SequentialBackoffTagger 私たちに Backoff tagging 特徴。

バックオフタグ付け

前に述べたように、バックオフタグ付けはの重要な機能の1つです SequentialBackoffTagger、これにより、あるタガーが単語にタグを付ける方法がわからない場合に、チェックするバックオフタガーがなくなるまで、単語が次のタガーに渡されるようにタガーを組み合わせることができます。

それはどのように機能しますか?

実際には、のすべてのサブクラス SequentialBackoffTagger'backoff'キーワード引数を取ることができます。このキーワード引数の値は、の別のインスタンスです。SequentialBackoffTagger。今これがいつでもSequentialBackoffTaggerクラスが初期化されると、バックオフタガーの内部リスト(それ自体を最初の要素として)が作成されます。さらに、バックオフタガーが指定されている場合、このバックオフタガーの内部リストが追加されます。

以下の例では、 DefaulTagger 上記のPythonレシピのバックオフタガーとして、 UnigramTagger

この例では、 DefaulTaggerバックオフタガーとして。いつでもUnigramTagger 単語にタグを付けることができません、バックオフタガー、すなわち DefaulTagger、この場合、「NN」でタグ付けします。

from nltk.tag import UnigramTagger
from nltk.tag import DefaultTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
back_tagger = DefaultTagger('NN')
Uni_tagger = UnigramTagger(train_sentences, backoff = back_tagger)
test_sentences = treebank.tagged_sents()[1500:]
Uni_tagger.evaluate(test_sentences)

出力

0.9061975746536931

上記の出力から、バックオフタガーを追加することにより、精度が約2%向上することがわかります。

ピクルスでタガーを節約

タガーのトレーニングは非常に面倒で時間がかかります。時間を節約するために、後で使用するために訓練されたタガーを漬けることができます。以下の例では、すでにトレーニング済みのタガーにこれを実行します。‘Uni_tagger’

import pickle
f = open('Uni_tagger.pickle','wb')
pickle.dump(Uni_tagger, f)
f.close()
f = open('Uni_tagger.pickle','rb')
Uni_tagger = pickle.load(f)

NgramTaggerクラス

前の単元で説明した階層図から、 UnigramTagger から継承されます NgarmTagger クラスですが、さらに2つのサブクラスがあります NgarmTagger クラス-

BigramTaggerサブクラス

実際には、ngramはn個のアイテムのサブシーケンスであるため、名前が示すように、 BigramTaggerサブクラスは2つの項目を調べます。最初の項目は前にタグ付けされた単語であり、2番目の項目は現在のタグ付けされた単語です。

TrigramTaggerサブクラス

の同じメモに BigramTagger, TrigramTagger サブクラスは、3つの項目、つまり2つの前のタグ付き単語と1つの現在のタグ付き単語を調べます。

実際に適用すれば BigramTagger そして TrigramTaggerUnigramTaggerサブクラスで行ったように、サブクラスは個別に実行されますが、どちらもパフォーマンスが非常に低くなります。以下の例を見てみましょう。

BigramTaggerサブクラスの使用

from nltk.tag import BigramTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Bi_tagger = BigramTagger(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
Bi_tagger.evaluate(test_sentences)

出力

0.44669191071913594

TrigramTaggerサブクラスの使用

from nltk.tag import TrigramTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Tri_tagger = TrigramTagger(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
Tri_tagger.evaluate(test_sentences)

出力

0.41949863394526193

以前に使用したUnigramTagger(約89%の精度)とBigramTagger(約44%の精度)およびTrigramTagger(約41%の精度)のパフォーマンスを比較できます。その理由は、BigramおよびTrigramタガーは、文の最初の単語からコンテキストを学習できないためです。一方、UnigramTaggerクラスは前のコンテキストを気にせず、各単語の最も一般的なタグを推測するため、ベースラインの精度を高くすることができます。

ngramタガーの組み合わせ

上記の例から、BigramおよびTrigramタガーをバックオフタギングと組み合わせると、それらが貢献できることは明らかです。以下の例では、Unigram、Bigram、Trigramのタガーをバックオフタグと組み合わせています。コンセプトは前のレシピと同じですが、UnigramTaggerとバックオフタガーを組み合わせています。唯一の違いは、バックオフ操作に、以下に示すtagger_util.pyのbackoff_tagger()という名前の関数を使用していることです。

def backoff_tagger(train_sentences, tagger_classes, backoff=None):
   for cls in tagger_classes:
      backoff = cls(train_sentences, backoff=backoff)
   return backoff

from tagger_util import backoff_tagger
from nltk.tag import UnigramTagger
from nltk.tag import BigramTagger
from nltk.tag import TrigramTagger
from nltk.tag import DefaultTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
back_tagger = DefaultTagger('NN')
Combine_tagger = backoff_tagger(train_sentences,
[UnigramTagger, BigramTagger, TrigramTagger], backoff = back_tagger)
test_sentences = treebank.tagged_sents()[1500:]
Combine_tagger.evaluate(test_sentences)

出力

0.9234530029238365

上記の出力から、精度が約3%向上していることがわかります。

タガーを付ける

ContextTaggerサブクラスのもう1つの重要なクラスは、AffixTaggerです。AffixTaggerクラスでは、コンテキストは単語の接頭辞または接尾辞のいずれかです。これが、AffixTaggerクラスが単語の先頭または末尾の固定長の部分文字列に基づいてタグを学習できる理由です。

それはどのように機能しますか?

その動作は、プレフィックスまたはサフィックスの長さを指定するaffix_lengthという名前の引数に依存します。デフォルト値は3です。しかし、AffixTaggerクラスが単語のプレフィックスまたはサフィックスを学習したかどうかをどのように区別しますか?

  • affix_length=positive − affix_lenghtの値が正の場合、AffixTaggerクラスが単語のプレフィックスを学習することを意味します。

  • affix_length=negative − affix_lenghtの値が負の場合、AffixTaggerクラスが単語のサフィックスを学習することを意味します。

明確にするために、以下の例では、タグ付けされたツリーバンクセンテンスでAffixTaggerクラスを使用します。

この例では、affix_length引数に値を指定していないため、AffixTaggerは単語のプレフィックスを学習します。引数はデフォルト値3−を取ります

from nltk.tag import AffixTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Prefix_tagger = AffixTagger(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
Prefix_tagger.evaluate(test_sentences)

出力

0.2800492099250667

以下の例で、affix_length引数に値4を指定した場合の精度を見てみましょう。

from nltk.tag import AffixTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Prefix_tagger = AffixTagger(train_sentences, affix_length=4 )
test_sentences = treebank.tagged_sents()[1500:]
Prefix_tagger.evaluate(test_sentences)

出力

0.18154947354966527

この例では、affix_length引数に負の値を指定するため、AffixTaggerは単語のサフィックスを学習します。

from nltk.tag import AffixTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
Suffix_tagger = AffixTagger(train_sentences, affix_length = -3)
test_sentences = treebank.tagged_sents()[1500:]
Suffix_tagger.evaluate(test_sentences)

出力

0.2800492099250667

ブリルタガー

Brill Taggerは、変換ベースのタガーです。NLTKは提供しますBrillTagger のサブクラスではない最初のタガーであるクラス SequentialBackoffTagger。それとは反対に、最初のタガーの結果を修正するための一連のルールがによって使用されますBrillTagger

それはどのように機能しますか?

トレーニングするには BrillTagger 使用するクラス BrillTaggerTrainer 次の関数を定義します-

def train_brill_tagger(initial_tagger, train_sentences, **kwargs)

templates = [
   brill.Template(brill.Pos([-1])),
   brill.Template(brill.Pos([1])),
   brill.Template(brill.Pos([-2])),
   brill.Template(brill.Pos([2])),
   brill.Template(brill.Pos([-2, -1])),
   brill.Template(brill.Pos([1, 2])),
   brill.Template(brill.Pos([-3, -2, -1])),
   brill.Template(brill.Pos([1, 2, 3])),
   brill.Template(brill.Pos([-1]), brill.Pos([1])),
   brill.Template(brill.Word([-1])),
   brill.Template(brill.Word([1])),
   brill.Template(brill.Word([-2])),
   brill.Template(brill.Word([2])),
   brill.Template(brill.Word([-2, -1])),
   brill.Template(brill.Word([1, 2])),
   brill.Template(brill.Word([-3, -2, -1])),
   brill.Template(brill.Word([1, 2, 3])),
   brill.Template(brill.Word([-1]), brill.Word([1])),
]
trainer = brill_trainer.BrillTaggerTrainer(initial_tagger, templates, deterministic=True)
return trainer.train(train_sentences, **kwargs)

ご覧のとおり、この関数には initial_tagger そして train_sentences。それはかかりますinitial_tagger 引数とテンプレートのリスト。これは、 BrillTemplateインターフェース。ザ・BrillTemplate インターフェースはにあります nltk.tbl.templateモジュール。そのような実装の1つはbrill.Template クラス。

変換ベースのタガーの主な役割は、最初のタガーの出力をトレーニング文とより一致するように修正する変換ルールを生成することです。以下のワークフローを見てみましょう-

この例では、 combine_tagger のバックオフチェーンから(前のレシピで)タガーを組み合わせながら作成しました NgramTagger クラス、 initial_tagger。まず、を使用して結果を評価しましょうCombine.tagger そしてそれを initial_tagger ブリルタガーを訓練する。

from tagger_util import backoff_tagger
from nltk.tag import UnigramTagger
from nltk.tag import BigramTagger
from nltk.tag import TrigramTagger
from nltk.tag import DefaultTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
back_tagger = DefaultTagger('NN')
Combine_tagger = backoff_tagger(
   train_sentences, [UnigramTagger, BigramTagger, TrigramTagger], backoff = back_tagger
)
test_sentences = treebank.tagged_sents()[1500:]
Combine_tagger.evaluate(test_sentences)

出力

0.9234530029238365

さて、評価結果を見てみましょう。 Combine_tagger として使用されます initial_tagger ブリルタガーを訓練する-

from tagger_util import train_brill_tagger
brill_tagger = train_brill_tagger(combine_tagger, train_sentences)
brill_tagger.evaluate(test_sentences)

出力

0.9246832510505041

私たちはそれに気付くことができます BrillTagger クラスの精度は、 Combine_tagger

完全な実装例

from tagger_util import backoff_tagger
from nltk.tag import UnigramTagger
from nltk.tag import BigramTagger
from nltk.tag import TrigramTagger
from nltk.tag import DefaultTagger
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
back_tagger = DefaultTagger('NN')
Combine_tagger = backoff_tagger(train_sentences,
[UnigramTagger, BigramTagger, TrigramTagger], backoff = back_tagger)
test_sentences = treebank.tagged_sents()[1500:]
Combine_tagger.evaluate(test_sentences)
from tagger_util import train_brill_tagger
brill_tagger = train_brill_tagger(combine_tagger, train_sentences)
brill_tagger.evaluate(test_sentences)

出力

0.9234530029238365
0.9246832510505041

TnTタガー

TnT Taggerは、Trigrams'nTagsの略で、2次マルコフモデルに基づく統計タガーです。

それはどのように機能しますか?

次の手順でTnTタガーの動作を理解できます-

  • 最初にトレーニングデータに基づいて、TnTテガーはいくつかの内部を維持します FreqDist そして ConditionalFreqDist インスタンス。

  • その後、ユニグラム、バイグラム、トリグラムがこれらの度数分布でカウントされます。

  • これで、タグ付け中に、頻度を使用して、各単語の可能なタグの確率が計算されます。

そのため、NgramTaggerのバックオフチェーンを構築する代わりに、すべてのngramモデルを一緒に使用して、各単語に最適なタグを選択します。次の例でTnTタガーを使用して精度を評価しましょう-

from nltk.tag import tnt
from nltk.corpus import treebank
train_sentences = treebank.tagged_sents()[:2500]
tnt_tagger = tnt.TnT()
tnt_tagger.train(train_sentences)
test_sentences = treebank.tagged_sents()[1500:]
tnt_tagger.evaluate(test_sentences)

出力

0.9165508316157791

BrillTaggerよりも精度がわずかに低くなります。

電話する必要があることに注意してください train()evaluate() それ以外の場合は、0%の精度が得られます。

NLPにおける構文解析とその関連性

ラテン語に由来する「構文解析」という単語 ‘pars’ (つまり、 ‘part’)、テキストから正確な意味または辞書の意味を引き出すために使用されます。構文解析または構文解析とも呼ばれます。形式文法の規則を比較して、構文解析はテキストの意味をチェックします。たとえば、「Give me hot ice-cream」のような文は、パーサーまたは構文アナライザーによって拒否されます。

この意味で、構文解析、構文解析、構文解析、構文解析は次のように定義できます。

これは、形式文法の規則に準拠した自然言語の記号の文字列を分析するプロセスとして定義できます。

次の点を参考にして、NLPでの構文解析の関連性を理解できます。

  • パーサーは、構文エラーを報告するために使用されます。

  • プログラムの残りの部分の処理を続行できるように、一般的に発生するエラーから回復するのに役立ちます。

  • パーサーツリーは、パーサーを使用して作成されます。

  • パーサーは、NLPで重要な役割を果たすシンボルテーブルを作成するために使用されます。

  • パーサーは、中間表現(IR)の生成にも使用されます。

深い対浅い構文解析

ディープ解析 シャローパーサ
深い構文解析では、検索戦略により、文に完全な構文構造が与えられます。 これは、指定されたタスクからの構文情報の限られた部分を解析するタスクです。
複雑なNLPアプリケーションに適しています。 それほど複雑でないNLPアプリケーションに使用できます。
対話システムと要約は、深い構文解析が使用されるNLPアプリケーションの例です。 情報抽出とテキストマイニングは、ディープ解析が使用されるNLPアプリケーションの例です。
これは、完全解析とも呼ばれます。 チャンキングとも呼ばれます。

さまざまなタイプのパーサー

説明したように、パーサーは基本的に文法の手続き型解釈です。さまざまな木の空間を検索した後、与えられた文に最適な木を見つけます。以下の利用可能なパーサーのいくつかを見てみましょう-

再帰下降パーサー

再帰下降構文解析は、最も単純な形式の構文解析の1つです。以下は、再帰下降パーサーに関するいくつかの重要なポイントです。

  • それはトップダウンのプロセスに従います。

  • 入力ストリームの構文が正しいかどうかを確認しようとします。

  • 入力文を左から右に読みます。

  • 再帰下降パーサーに必要な操作の1つは、入力ストリームから文字を読み取り、それらを文法の端末と照合することです。

Shift-reduceパーサー

以下は、shift-reduceパーサーに関するいくつかの重要なポイントです-

  • これは、単純なボトムアッププロセスに従います。

  • 文法プロダクションの右側に対応する単語やフレーズのシーケンスを見つけようとし、それらをプロダクションの左側に置き換えます。

  • 単語のシーケンスを見つける上記の試みは、文全体が縮小されるまで続きます。

  • 言い換えると、shift-reduceパーサーは入力シンボルから開始し、開始シンボルまでパーサーツリーを構築しようとします。

チャートパーサ

以下はチャートパーサに関するいくつかの重要なポイントです-

  • これは主に、自然言語の文法を含むあいまいな文法に役立ちます。

  • 動的計画法を構文解析の問題に適用します。

  • 動的計画法のため、部分的に仮定された結果は「チャート」と呼ばれる構造に格納されます。

  • 「チャート」は再利用することもできます。

正規表現パーサー

正規表現解析は、最もよく使用される解析手法の1つです。以下は、正規表現パーサーに関するいくつかの重要なポイントです。

  • 名前が示すように、POSタグ付き文字列の上に文法の形式で定義された正規表現を使用します。

  • 基本的に、これらの正規表現を使用して入力文を解析し、これから解析ツリーを生成します。

以下は、正規表現パーサーの実用的な例です。

import nltk
sentence = [
   ("a", "DT"),
   ("clever", "JJ"),
   ("fox","NN"),
   ("was","VBP"),
   ("jumping","VBP"),
   ("over","IN"),
   ("the","DT"),
   ("wall","NN")
]
grammar = "NP:{<DT>?<JJ>*<NN>}" 
Reg_parser = nltk.RegexpParser(grammar)
Reg_parser.parse(sentence)
Output = Reg_parser.parse(sentence)
Output.draw()

出力

依存関係の解析

依存関係解析(DP)は、最新の構文解析メカニズムであり、その主な概念は、各言語単位、つまり単語が直接リンクによって相互に関連していることです。これらの直接リンクは実際には‘dependencies’言語学で。たとえば、次の図は、文の依存文法を示しています。“John can hit the ball”

NLTKパッケージ

NLTKで依存関係の解析を行うには2つの方法があります-

確率的で射影的な依存関係パーサー

これは、NLTKを使用して依存関係の解析を実行できる最初の方法です。ただし、このパーサーには、限られたトレーニングデータセットを使用したトレーニングの制限があります。

スタンフォードパーサー

これは、NLTKを使用して依存関係の解析を行うことができるもう1つの方法です。スタンフォードパーサーは、最先端の依存関係パーサーです。NLTKにはラッパーがあります。それを使用するには、次の2つをダウンロードする必要があります-

スタンフォードCoreNLPパーサ。

希望する言語の言語モデル。たとえば、英語モデル。

モデルをダウンロードすると、NLTKを介して次のように使用できます-

from nltk.parse.stanford import StanfordDependencyParser
path_jar = 'path_to/stanford-parser-full-2014-08-27/stanford-parser.jar'
path_models_jar = 'path_to/stanford-parser-full-2014-08-27/stanford-parser-3.4.1-models.jar'
dep_parser = StanfordDependencyParser(
   path_to_jar = path_jar, path_to_models_jar = path_models_jar
)
result = dep_parser.raw_parse('I shot an elephant in my sleep')
depndency = result.next()
list(dependency.triples())

出力

[
   ((u'shot', u'VBD'), u'nsubj', (u'I', u'PRP')),
   ((u'shot', u'VBD'), u'dobj', (u'elephant', u'NN')),
   ((u'elephant', u'NN'), u'det', (u'an', u'DT')),
   ((u'shot', u'VBD'), u'prep', (u'in', u'IN')),
   ((u'in', u'IN'), u'pobj', (u'sleep', u'NN')),
   ((u'sleep', u'NN'), u'poss', (u'my', u'PRP$'))
]

チャンキングとは何ですか?

自然言語処理の重要なプロセスの1つであるチャンキングは、品詞(POS)と短いフレーズを識別するために使用されます。言い換えれば、チャンクを使用すると、文の構造を取得できます。とも呼ばれますpartial parsing

チャンクパターンとチンク

Chunk patternsチャンクを構成する単語の種類を定義する品詞(POS)タグのパターンです。変更された正規表現を使用してチャンクパターンを定義できます。

さらに、どのような種類の単語をチャンクに含めるべきではないかについてのパターンを定義することもできます。これらのアンチャンクされた単語は、 chinks

実装例

以下の例では、文を解析した結果とともに “the book has many chapters”, チャンクとチンクパターンの両方を組み合わせた名詞句の文法があります-

import nltk
sentence = [
   ("the", "DT"),
   ("book", "NN"),
   ("has","VBZ"),
   ("many","JJ"),
   ("chapters","NNS")
]
chunker = nltk.RegexpParser(
   r'''
   NP:{<DT><NN.*><.*>*<NN.*>}
   }<VB.*>{
   '''
)
chunker.parse(sentence)
Output = chunker.parse(sentence)
Output.draw()

出力

上記のように、チャンクを指定するためのパターンは、次のように中括弧を使用することです。

{<DT><NN>}

また、チンクを指定するには、次のように中括弧を反転します。

}<VB>{.

現在、特定のフレーズタイプについて、これらのルールを組み合わせて文法を作成できます。

情報抽出

情報抽出エンジンの構築に使用できるタガーとパーサーを確認しました。基本的な情報抽出パイプラインを見てみましょう-

情報抽出には、以下を含む多くのアプリケーションがあります。

  • ビジネス・インテリジェンス
  • 収穫を再開する
  • メディア分析
  • 感情の検出
  • 特許検索
  • メールスキャン

固有表現抽出(NER)

固有表現抽出(NER)は、実際には、名前、組織、場所などの最も一般的なエンティティのいくつかを抽出する方法です。文のトークン化、POSタグ付け、チャンク化、NER、などのすべての前処理ステップを実行した例を見てみましょう。上の図に示されているパイプラインに従います。

Import nltk
file = open (
   # provide here the absolute path for the file of text for which we want NER
)
data_text = file.read()
sentences = nltk.sent_tokenize(data_text)
tokenized_sentences = [nltk.word_tokenize(sentence) for sentence in sentences]
tagged_sentences = [nltk.pos_tag(sentence) for sentence in tokenized_sentences]
for sent in tagged_sentences:
print nltk.ne_chunk(sent)

変更された名前付きエンティティ認識(NER)の一部は、製品名、生物医学エンティティ、ブランド名などのエンティティを抽出するためにも使用できます。

関係の抽出

別の一般的に使用される情報抽出操作である関係抽出は、さまざまなエンティティ間のさまざまな関係を抽出するプロセスです。継承、同義語、類似などのさまざまな関係が存在する可能性があり、その定義は情報の必要性によって異なります。たとえば、本の執筆を探したい場合、著者は著者名と本名の関係になります。

次の例では、上の図に示すように、名前付きエンティティリレーション(NER)まで使用したものと同じIEパイプラインを使用し、NERタグに基づくリレーションパターンで拡張します。

import nltk
import re
IN = re.compile(r'.*\bin\b(?!\b.+ing)')
for doc in nltk.corpus.ieer.parsed_docs('NYT_19980315'):
for rel in nltk.sem.extract_rels('ORG', 'LOC', doc, corpus = 'ieer',
pattern = IN):
print(nltk.sem.rtuple(rel))

出力

[ORG: 'WHYY'] 'in' [LOC: 'Philadelphia']
[ORG: 'McGlashan & Sarrail'] 'firm in' [LOC: 'San Mateo']
[ORG: 'Freedom Forum'] 'in' [LOC: 'Arlington']
[ORG: 'Brookings Institution'] ', the research group in' [LOC: 'Washington']
[ORG: 'Idealab'] ', a self-described business incubator based in' [LOC: 'Los Angeles']
[ORG: 'Open Text'] ', based in' [LOC: 'Waterloo']
[ORG: 'WGBH'] 'in' [LOC: 'Boston']
[ORG: 'Bastille Opera'] 'in' [LOC: 'Paris']
[ORG: 'Omnicom'] 'in' [LOC: 'New York']
[ORG: 'DDB Needham'] 'in' [LOC: 'New York']
[ORG: 'Kaplan Thaler Group'] 'in' [LOC: 'New York']
[ORG: 'BBDO South'] 'in' [LOC: 'Atlanta']
[ORG: 'Georgia-Pacific'] 'in' [LOC: 'Atlanta']

上記のコードでは、ieerという名前の組み込みコーパスを使用しています。このコーパスでは、名前付きエンティティ関係(NER)まで文にタグが付けられます。ここでは、必要な関係パターンと、関係で定義するNERの種類を指定するだけで済みます。この例では、組織と場所の間の関係を定義しました。これらのパターンのすべての組み合わせを抽出しました。

なぜチャンクを変換するのですか?

今まで、文からチャンクやフレーズを取得しましたが、それらをどうするかを考えます。重要なタスクの1つは、それらを変換することです。しかし、なぜ?それは次のことをすることです-

  • 文法の修正と
  • フレーズを並べ替える

重要でない/役に立たない単語のフィルタリング

フレーズの意味を判断したい場合は、「the」、「a」などの一般的に使用される単語が多く、重要でないか役に立たないとします。たとえば、次のフレーズを参照してください-

「映画は良かった」。

ここで最も重要な言葉は「映画」と「良い」です。言い換えれば、「the」と「was」はどちらも役に立たないか、重要ではありません。それらがなくても、同じ意味のフレーズが得られるからです。'良い映画'。

次のPythonレシピでは、POSタグを使用して、役に立たない/重要でない単語を削除し、重要な単語を保持する方法を学習します。

まず、目を通すことによって treebankストップワードのコーパスでは、どの品詞タグが重要でどれが重要でないかを判断する必要があります。重要でない単語とタグの次の表を見てみましょう-

鬼ごっこ
a DT
すべて PDT
アン DT
そして CC
または CC
それ WDT
ザ・ DT

上記の表から、CC以外のすべてのタグがDTで終わっていることがわかります。これは、タグのサフィックスを調べることで、重要でない単語を除外できることを意味します。

この例では、という名前の関数を使用します filter()これは単一のチャンクを取り、重要でないタグ付き単語なしで新しいチャンクを返します。この関数は、DTまたはCCで終わるタグをすべて除外します。

import nltk
def filter(chunk, tag_suffixes=['DT', 'CC']):
   significant = []
   for word, tag in chunk:
      ok = True
      for suffix in tag_suffixes:
         if tag.endswith(suffix):
            ok = False
            break
      if ok:
         significant.append((word, tag))
   return (significant)

ここで、Pythonレシピでこの関数filter()を使用して、重要でない単語を削除しましょう-

from chunk_parse import filter
filter([('the', 'DT'),('good', 'JJ'),('movie', 'NN')])

出力

[('good', 'JJ'), ('movie', 'NN')]

動詞の修正

多くの場合、実際の言語では、動詞の形式が正しくありません。たとえば、「大丈夫ですか?」正しくありません。この文では動詞の形が正しくありません。文は「大丈夫ですか?」NLTKは、動詞修正マッピングを作成することにより、このような間違いを修正する方法を提供します。これらの補正マッピングは、チャンクに複数形または単数形の名詞があるかどうかに応じて使用されます。

Pythonレシピを実装するには、最初に動詞修正マッピングを定義する必要があります。次のように2つのマッピングを作成しましょう-

Plural to Singular mappings

plural= {
   ('is', 'VBZ'): ('are', 'VBP'),
   ('was', 'VBD'): ('were', 'VBD')
}

Singular to Plural mappings

singular = {
   ('are', 'VBP'): ('is', 'VBZ'),
   ('were', 'VBD'): ('was', 'VBD')
}

上記のように、各マッピングには、別のタグ付き動詞にマップするタグ付き動詞があります。この例の最初のマッピングは、マッピングの基本をカバーしていますis to are, was to were、 およびその逆。

次に、という名前の関数を定義します verbs()、間違った動詞形式のチンクを渡すことができ、 '修正されたチャンクが返されます。それを成し遂げるために、verb() 関数は、という名前のヘルパー関数を使用します index_chunk() これは、最初にタグ付けされた単語の位置をチャンクで検索します。

これらの関数を見てみましょう-

def index_chunk(chunk, pred, start = 0, step = 1):
   l = len(chunk)
   end = l if step > 0 else -1
   for i in range(start, end, step):
      if pred(chunk[i]):
         return i
      return None
def tag_startswith(prefix):
   def f(wt):
      return wt[1].startswith(prefix)
   return f

def verbs(chunk):
   vbidx = index_chunk(chunk, tag_startswith('VB'))
   if vbidx is None:
      return chunk
   verb, vbtag = chunk[vbidx]
   nnpred = tag_startswith('NN')
   nnidx = index_chunk(chunk, nnpred, start = vbidx+1)
   if nnidx is None:
      nnidx = index_chunk(chunk, nnpred, start = vbidx-1, step = -1)
   if nnidx is None:
      return chunk
   noun, nntag = chunk[nnidx]
   if nntag.endswith('S'):
      chunk[vbidx] = plural.get((verb, vbtag), (verb, vbtag))
   else:
      chunk[vbidx] = singular.get((verb, vbtag), (verb, vbtag))
   return chunk

これらの関数を、PythonまたはAnacondaがインストールされているローカルディレクトリのPythonファイルに保存して実行します。として保存しましたverbcorrect.py

さて、電話しましょう verbs() タグ付けされたPOSでの機能 is you fine チャンク-

from verbcorrect import verbs
verbs([('is', 'VBZ'), ('you', 'PRP$'), ('fine', 'VBG')])

出力

[('are', 'VBP'), ('you', 'PRP$'), ('fine','VBG')]

フレーズから受動態を排除する

もう1つの便利なタスクは、フレーズから受動態を排除することです。これは、動詞の周りの単語を交換することで実行できます。例えば、‘the tutorial was great’ に変換することができます ‘the great tutorial’

これを実現するために、次の名前の関数を定義しています。 eliminate_passive()これは、動詞をピボットポイントとして使用して、チャンクの右側を左側に交換します。ピボットする動詞を見つけるために、index_chunk() 上で定義された関数。

def eliminate_passive(chunk):
   def vbpred(wt):
      word, tag = wt
      return tag != 'VBG' and tag.startswith('VB') and len(tag) > 2
   vbidx = index_chunk(chunk, vbpred)
   if vbidx is None:
      return chunk
   return chunk[vbidx+1:] + chunk[:vbidx]

さて、電話しましょう eliminate_passive() タグ付けされたPOSでの機能 the tutorial was great チャンク-

from passiveverb import eliminate_passive
eliminate_passive(
   [
      ('the', 'DT'), ('tutorial', 'NN'), ('was', 'VBD'), ('great', 'JJ')
   ]
)

出力

[('great', 'JJ'), ('the', 'DT'), ('tutorial', 'NN')]

名詞の枢機卿を交換する

ご存知のように、5などの基本的な単語はチャンクでCDとしてタグ付けされます。これらの基本的な単語は、名詞の前後に出現することがよくありますが、正規化の目的で、常に名詞の前に置くと便利です。たとえば、日付January 5 次のように書くことができます 5 January。次の例でそれを理解しましょう。

これを実現するために、次の名前の関数を定義しています。 swapping_cardinals()これにより、名詞の直後に発生する枢機卿が名詞と交換されます。これにより、枢機卿は名詞の直前に出現します。指定されたタグとの等価比較を行うために、名前を付けたヘルパー関数を使用しますtag_eql()

def tag_eql(tag):
   def f(wt):
      return wt[1] == tag
   return f

これで、swapping_cardinals()−を定義できます。

def swapping_cardinals (chunk):
   cdidx = index_chunk(chunk, tag_eql('CD'))
   if not cdidx or not chunk[cdidx-1][1].startswith('NN'):
      return chunk
   noun, nntag = chunk[cdidx-1]
   chunk[cdidx-1] = chunk[cdidx]
   chunk[cdidx] = noun, nntag
   return chunk

さて、電話しましょう swapping_cardinals() 日付の機能 “January 5”

from Cardinals import swapping_cardinals()
swapping_cardinals([('Janaury', 'NNP'), ('5', 'CD')])

出力

[('10', 'CD'), ('January', 'NNP')]
10 January

以下は、ツリーを変換する2つの理由です-

  • ディープ解析ツリーを変更するには
  • 深い解析木を平坦化するには

ツリーまたはサブツリーを文に変換する

ここで説明する最初のレシピは、ツリーまたはサブツリーを文またはチャンク文字列に変換することです。これは非常に簡単です。次の例で見てみましょう-

from nltk.corpus import treebank_chunk
tree = treebank_chunk.chunked_sents()[2]
' '.join([w for w, t in tree.leaves()])

出力

'Rudolph Agnew , 55 years old and former chairman of Consolidated Gold Fields
PLC , was named a nonexecutive director of this British industrial
conglomerate .'

深い木の平坦化

ネストされたフレーズの深いツリーはチャンクのトレーニングには使用できないため、使用する前にそれらをフラット化する必要があります。次の例では、ネストされたフレーズの深いツリーである3番目の解析された文を使用します。treebank コーパス。

これを実現するために、次の名前の関数を定義しています。 deeptree_flat()これは単一のツリーを取り、最下位レベルのツリーのみを保持する新しいツリーを返します。ほとんどの作業を行うために、名前を付けたヘルパー関数を使用しますchildtree_flat()

from nltk.tree import Tree
def childtree_flat(trees):
   children = []
   for t in trees:
      if t.height() < 3:
         children.extend(t.pos())
      elif t.height() == 3:
         children.append(Tree(t.label(), t.pos()))
      else:
         children.extend(flatten_childtrees([c for c in t]))
   return children
def deeptree_flat(tree):
   return Tree(tree.label(), flatten_childtrees([c for c in tree]))

さて、電話しましょう deeptree_flat() ネストされたフレーズの深いツリーである3番目の解析された文の関数 treebankコーパス。これらの関数をdeeptree.pyという名前のファイルに保存しました。

from deeptree import deeptree_flat
from nltk.corpus import treebank
deeptree_flat(treebank.parsed_sents()[2])

出力

Tree('S', [Tree('NP', [('Rudolph', 'NNP'), ('Agnew', 'NNP')]),
(',', ','), Tree('NP', [('55', 'CD'), 
('years', 'NNS')]), ('old', 'JJ'), ('and', 'CC'),
Tree('NP', [('former', 'JJ'), 
('chairman', 'NN')]), ('of', 'IN'), Tree('NP', [('Consolidated', 'NNP'), 
('Gold', 'NNP'), ('Fields', 'NNP'), ('PLC', 
'NNP')]), (',', ','), ('was', 'VBD'), 
('named', 'VBN'), Tree('NP-SBJ', [('*-1', '-NONE-')]), 
Tree('NP', [('a', 'DT'), ('nonexecutive', 'JJ'), ('director', 'NN')]),
('of', 'IN'), Tree('NP', 
[('this', 'DT'), ('British', 'JJ'), 
('industrial', 'JJ'), ('conglomerate', 'NN')]), ('.', '.')])

浅い木の構築

前のセクションでは、最下位レベルのサブツリーのみを保持することにより、ネストされたフレーズの深いツリーをフラット化しました。このセクションでは、最上位のサブツリーのみを保持します。つまり、浅いツリーを構築します。次の例では、ネストされたフレーズの深いツリーである3番目の解析された文を使用します。treebank コーパス。

これを実現するために、次の名前の関数を定義しています。 tree_shallow() これにより、最上位のサブツリーラベルのみが保持されるため、ネストされたすべてのサブツリーが削除されます。

from nltk.tree import Tree
def tree_shallow(tree):
   children = []
   for t in tree:
      if t.height() < 3:
         children.extend(t.pos())
      else:
         children.append(Tree(t.label(), t.pos()))
   return Tree(tree.label(), children)

さて、電話しましょう tree_shallow()ネストされたフレーズの深いツリーである3番目の解析された文の関数treebankコーパス。これらの関数をshallowtree.pyという名前のファイルに保存しました。

from shallowtree import shallow_tree
from nltk.corpus import treebank
tree_shallow(treebank.parsed_sents()[2])

出力

Tree('S', [Tree('NP-SBJ-1', [('Rudolph', 'NNP'), ('Agnew', 'NNP'), (',', ','), 
('55', 'CD'), ('years', 'NNS'), ('old', 'JJ'), ('and', 'CC'), 
('former', 'JJ'), ('chairman', 'NN'), ('of', 'IN'), ('Consolidated', 'NNP'), 
('Gold', 'NNP'), ('Fields', 'NNP'), ('PLC', 'NNP'), (',', ',')]), 
Tree('VP', [('was', 'VBD'), ('named', 'VBN'), ('*-1', '-NONE-'), ('a', 'DT'), 
('nonexecutive', 'JJ'), ('director', 'NN'), ('of', 'IN'), ('this', 'DT'), 
('British', 'JJ'), ('industrial', 'JJ'), ('conglomerate', 'NN')]), ('.', '.')])

木の高さを取得することで違いを見ることができます-

from nltk.corpus import treebank
tree_shallow(treebank.parsed_sents()[2]).height()

出力

3

from nltk.corpus import treebank
treebank.parsed_sents()[2].height()

出力

9

ツリーラベルの変換

解析木にはさまざまなものがあります Treeチャンクツリーに存在しないラベルタイプ。ただし、解析ツリーを使用してチャンカーをトレーニングする際に、ツリーラベルの一部をより一般的なラベルタイプに変換することで、この種類を減らしたいと考えています。たとえば、2つの代替NPサブツリー、つまりNP-SBLとNP-TMPがあります。両方をNPに変換できます。次の例でそれを行う方法を見てみましょう。

これを実現するために、次の名前の関数を定義しています。 tree_convert() 次の2つの引数を取る-

  • 変換するツリー
  • ラベル変換マッピング

この関数は、マッピングの値に基づいて一致するすべてのラベルが置き換えられた新しいツリーを返します。

from nltk.tree import Tree
def tree_convert(tree, mapping):
   children = []
   for t in tree:
      if isinstance(t, Tree):
         children.append(convert_tree_labels(t, mapping))
      else:
         children.append(t)
   label = mapping.get(tree.label(), tree.label())
   return Tree(label, children)

さて、電話しましょう tree_convert() ネストされたフレーズの深いツリーである3番目の解析された文の関数 treebankコーパス。これらの関数をという名前のファイルに保存しましたconverttree.py

from converttree import tree_convert
from nltk.corpus import treebank
mapping = {'NP-SBJ': 'NP', 'NP-TMP': 'NP'}
convert_tree_labels(treebank.parsed_sents()[2], mapping)

出力

Tree('S', [Tree('NP-SBJ-1', [Tree('NP', [Tree('NNP', ['Rudolph']), 
Tree('NNP', ['Agnew'])]), Tree(',', [',']), 
Tree('UCP', [Tree('ADJP', [Tree('NP', [Tree('CD', ['55']), 
Tree('NNS', ['years'])]), 
Tree('JJ', ['old'])]), Tree('CC', ['and']), 
Tree('NP', [Tree('NP', [Tree('JJ', ['former']), 
Tree('NN', ['chairman'])]), Tree('PP', [Tree('IN', ['of']), 
Tree('NP', [Tree('NNP', ['Consolidated']), 
Tree('NNP', ['Gold']), Tree('NNP', ['Fields']), 
Tree('NNP', ['PLC'])])])])]), Tree(',', [','])]), 
Tree('VP', [Tree('VBD', ['was']),Tree('VP', [Tree('VBN', ['named']), 
Tree('S', [Tree('NP', [Tree('-NONE-', ['*-1'])]), 
Tree('NP-PRD', [Tree('NP', [Tree('DT', ['a']), 
Tree('JJ', ['nonexecutive']), Tree('NN', ['director'])]), 
Tree('PP', [Tree('IN', ['of']), Tree('NP', 
[Tree('DT', ['this']), Tree('JJ', ['British']), Tree('JJ', ['industrial']), 
Tree('NN', ['conglomerate'])])])])])])]), Tree('.', ['.'])])

テキスト分類とは何ですか?

テキスト分類は、その名前が示すように、テキストまたはドキュメントの断片を分類する方法です。しかし、ここで、なぜテキスト分類子を使用する必要があるのか​​という疑問が生じます。ドキュメントまたはテキスト内の単語の使用法を調べると、分類子はそれに割り当てるクラスラベルを決定できます。

二項分類器

名前が示すように、バイナリ分類器は2つのラベルのどちらかを決定します。たとえば、正または負。この場合、テキストまたはドキュメントはいずれかのラベルにすることができますが、両方にすることはできません。

マルチラベル分類子

バイナリ分類器とは反対に、マルチラベル分類器は1つ以上のラベルをテキストまたはドキュメントに割り当てることができます。

ラベル付きとラベルなしの機能セット

機能名から機能値へのKey-Valueマッピングは、機能セットと呼ばれます。ラベル付き機能セットまたはトレーニングデータは、後でラベルなし機能セットを分類できるように、分類トレーニングにとって非常に重要です。

ラベル付き機能セット ラベルのない機能セット
(feat、label)のようなタプルです。 それ自体が偉業です。
これは、既知のクラスラベルを持つインスタンスです。 ラベルが関連付けられていない場合は、インスタンスと呼ぶことができます。
分類アルゴリズムのトレーニングに使用されます。 トレーニングが完了すると、分類アルゴリズムはラベルのない機能セットを分類できます。

テキスト特徴抽出

テキスト特徴抽出は、その名前が示すように、単語のリストを分類器で使用できる特徴セットに変換するプロセスです。テキストをに変換する必要があります‘dict’ Natural Language Tool Kit(NLTK)が期待するため、スタイル機能セット ‘dict’ スタイルの機能セット。

Bag of Words(BoW)モデル

NLPで最も単純なモデルの1つであるBoWは、テキストまたはドキュメントから特徴を抽出するために使用され、MLアルゴリズムなどのモデリングで使用できるようにします。基本的に、インスタンスのすべての単語から単語プレゼンス機能セットを構築します。この方法の背後にある概念は、単語が出現する回数や単語の順序を気にせず、単語が単語のリストに存在するかどうかだけを気にするというものです。

この例では、bow()−という名前の関数を定義します。

def bow(words):
   return dict([(word, True) for word in words])

さて、電話しましょう bow()言葉で機能します。この関数をbagwords.pyという名前のファイルに保存しました。

from bagwords import bow
bow(['we', 'are', 'using', 'tutorialspoint'])

出力

{'we': True, 'are': True, 'using': True, 'tutorialspoint': True}

分類器のトレーニング

前のセクションでは、テキストから特徴を抽出する方法を学びました。これで、分類器をトレーニングできます。最初で最も簡単な分類子はNaiveBayesClassifier クラス。

単純ベイズ分類器

特定の機能セットが特定のラベルに属する確率を予測するために、ベイズの定理を使用します。ベイズの定理の公式は次のとおりです。

$$P(A|B)=\frac{P(B|A)P(A)}{P(B)}$$

ここに、

P(A|B) −事後確率、つまり2番目のイベント(B)が発生した場合に最初のイベント(A)が発生する確率とも呼ばれます。

P(B|A) −最初のイベント(A)の後に2番目のイベント(B)が発生する確率です。

P(A), P(B) −事前確率、つまり最初のイベント、つまりAまたは2番目のイベント、つまりBが発生する確率とも呼ばれます。

単純ベイズ分類器をトレーニングするために、 movie_reviewsNLTKのコーパス。このコーパスには、次の2つのカテゴリのテキストがあります。pos そして neg。これらのカテゴリは、それらでトレーニングされた分類器をバイナリ分類器にします。コーパス内のすべてのファイルは2つで構成され、1つは肯定的な映画レビューで、もう1つは否定的な映画レビューです。この例では、分類器のトレーニングとテストの両方で、各ファイルを単一のインスタンスとして使用します。

分類器をトレーニングするには、ラベル付きの機能セットのリストが必要です。これは[(featureset, label)]。ここにfeatureset 変数は dict labelは、の既知のクラスラベルです。 featureset。名前の付いた関数を作成しますlabel_corpus() 名前の付いたコーパスを取ります movie_reviewsまた、という名前の関数 feature_detector、デフォルトは bag of words。{label:[featureset]}という形式のマッピングを作成して返します。その後、このマッピングを使用して、ラベル付けされたトレーニングインスタンスとテストインスタンスのリストを作成します。

import collections

def label_corpus(corp, feature_detector=bow):
   label_feats = collections.defaultdict(list)
   for label in corp.categories():
      for fileid in corp.fileids(categories=[label]):
         feats = feature_detector(corp.words(fileids=[fileid]))
         label_feats[label].append(feats)
   return label_feats

上記の関数の助けを借りて、マッピングを取得します {label:fetaureset}。次に、という名前の関数をもう1つ定義します。split それはから返されたマッピングを取ります label_corpus() 機能し、機能セットの各リストをラベル付きのトレーニングとテストインスタンスに分割します。

def split(lfeats, split=0.75):
   train_feats = []
   test_feats = []
   for label, feats in lfeats.items():
      cutoff = int(len(feats) * split)
      train_feats.extend([(feat, label) for feat in feats[:cutoff]])
      test_feats.extend([(feat, label) for feat in feats[cutoff:]])
   return train_feats, test_feats

では、これらの関数をコーパスで使用しましょう。つまり、movie_reviews −

from nltk.corpus import movie_reviews
from featx import label_feats_from_corpus, split_label_feats
movie_reviews.categories()

出力

['neg', 'pos']

lfeats = label_feats_from_corpus(movie_reviews)
lfeats.keys()

出力

dict_keys(['neg', 'pos'])

train_feats, test_feats = split_label_feats(lfeats, split = 0.75)
len(train_feats)

出力

1500

len(test_feats)

出力

500

私たちはそれを見てきました movie_reviewsコーパスには、1000個のposファイルと1000個のnegファイルがあります。また、1500個のラベル付きトレーニングインスタンスと500個のラベル付きテストインスタンスができあがります。

さあ、訓練しましょう NaïveBayesClassifier そのを使用して train() クラスメソッド-

from nltk.classify import NaiveBayesClassifier
NBC = NaiveBayesClassifier.train(train_feats)
NBC.labels()

出力

['neg', 'pos']

デシジョンツリー分類子

もう1つの重要な分類子は、決定木分類子です。ここでそれを訓練するDecisionTreeClassifierクラスはツリー構造を作成します。このツリー構造では、各ノードは機能名に対応し、ブランチは機能値に対応します。そして、枝を下って、木の葉、つまり分類ラベルに到達します。

デシジョンツリー分類器をトレーニングするには、同じトレーニング機能とテスト機能を使用します。 train_feats そして test_feats、から作成した変数 movie_reviews コーパス。

この分類器をトレーニングするために、 DecisionTreeClassifier.train() 次のようなクラスメソッド-

from nltk.classify import DecisionTreeClassifier
decisiont_classifier = DecisionTreeClassifier.train(
   train_feats, binary = True, entropy_cutoff = 0.8, 
   depth_cutoff = 5, support_cutoff = 30
)
accuracy(decisiont_classifier, test_feats)

出力

0.725

最大エントロピー分類器

もう1つの重要な分類子は MaxentClassifier これは、 conditional exponential classifier または logistic regression classifier。ここでそれを訓練するために、MaxentClassifier クラスは、エンコーディングを使用して、ラベル付けされたフィーチャセットをベクトルに変換します。

デシジョンツリー分類器をトレーニングするには、同じトレーニング機能とテスト機能を使用します。 train_featsそして test_feats、から作成した変数 movie_reviews コーパス。

この分類器をトレーニングするために、 MaxentClassifier.train() 次のようなクラスメソッド-

from nltk.classify import MaxentClassifier
maxent_classifier = MaxentClassifier
.train(train_feats,algorithm = 'gis', trace = 0, max_iter = 10, min_lldelta = 0.5)
accuracy(maxent_classifier, test_feats)

出力

0.786

Scikit-learn分類子

最高の機械学習(ML)ライブラリの1つは、Scikit-learnです。実際には、さまざまな目的のためにあらゆる種類のMLアルゴリズムが含まれていますが、それらはすべて、次のように同じフィット設計パターンを持っています。

  • モデルをデータに適合させる
  • そして、そのモデルを使用して予測を行います

ここでは、scikit-learnモデルに直接アクセスするのではなく、NLTKを使用します。 SklearnClassifierクラス。このクラスは、NLTKのClassifierインターフェースに準拠させるためのscikit-learnモデルのラッパークラスです。

次の手順に従って、 SklearnClassifier クラス-

Step 1 −最初に、以前のレシピで行ったようにトレーニング機能を作成します。

Step 2 −ここで、Scikit-learnアルゴリズムを選択してインポートします。

Step 3 −次に、構築する必要があります SklearnClassifier 選択したアルゴリズムのクラス。

Step 4 −最後にトレーニングします SklearnClassifier トレーニング機能を備えたクラス。

以下のPythonレシピでこれらのステップを実装しましょう-

from nltk.classify.scikitlearn import SklearnClassifier
from sklearn.naive_bayes import MultinomialNB
sklearn_classifier = SklearnClassifier(MultinomialNB())
sklearn_classifier.train(train_feats)
<SklearnClassifier(MultinomialNB(alpha = 1.0,class_prior = None,fit_prior = True))>
accuracy(sk_classifier, test_feats)

出力

0.885

適合率と再現率の測定

さまざまな分類器をトレーニングしながら、それらの精度も測定しました。しかし、精度とは別に、分類子を評価するために使用される他の多くのメトリックがあります。これらのメトリックの2つはprecision そして recall

この例では、以前にトレーニングしたNaiveBayesClassifierクラスの適合率と再現率を計算します。これを実現するために、2つの引数をとるmetrics_PR()という名前の関数を作成します。1つはトレーニング済みの分類子で、もう1つはラベル付きのテスト機能です。両方の引数は、分類子の精度を計算するときに渡したものと同じです。

import collections
from nltk import metrics
def metrics_PR(classifier, testfeats):
   refsets = collections.defaultdict(set)
   testsets = collections.defaultdict(set)
   for i, (feats, label) in enumerate(testfeats):
      refsets[label].add(i)
      observed = classifier.classify(feats)
         testsets[observed].add(i)
   precisions = {}
   recalls = {}
   for label in classifier.labels():
   precisions[label] = metrics.precision(refsets[label],testsets[label])
   recalls[label] = metrics.recall(refsets[label], testsets[label])
   return precisions, recalls

この関数を呼び出して適合率を求め、再現率を求めましょう。

from metrics_classification import metrics_PR
nb_precisions, nb_recalls = metrics_PR(nb_classifier,test_feats)
nb_precisions['pos']

出力

0.6713532466435213

nb_precisions['neg']

出力

0.9676271186440678

nb_recalls['pos']

出力

0.96

nb_recalls['neg']

出力

0.478

分類子と投票の組み合わせ

分類器を組み合わせることは、分類のパフォーマンスを向上させるための最良の方法の1つです。また、投票は、複数の分類子を組み合わせるための最良の方法の1つです。投票するには、奇数の分類子が必要です。次のPythonレシピでは、NaiveBayesClassifierクラス、DecisionTreeClassifierクラス、MaxentClassifierクラスの3つの分類器を組み合わせます。

これを実現するために、voting_classifiers()という名前の関数を次のように定義します。

import itertools
from nltk.classify import ClassifierI
from nltk.probability import FreqDist
class Voting_classifiers(ClassifierI):
   def __init__(self, *classifiers):
      self._classifiers = classifiers
      self._labels = sorted(set(itertools.chain(*[c.labels() for c in classifiers])))
   def labels(self):
      return self._labels
   def classify(self, feats):
      counts = FreqDist()
      for classifier in self._classifiers:
         counts[classifier.classify(feats)] += 1
      return counts.max()

この関数を呼び出して、3つの分類子を組み合わせ、精度を見つけましょう。

from vote_classification import Voting_classifiers
combined_classifier = Voting_classifiers(NBC, decisiont_classifier, maxent_classifier)
combined_classifier.labels()

出力

['neg', 'pos']

accuracy(combined_classifier, test_feats)

出力

0.948

上記の出力から、結合された分類器が個々の分類器よりも最高の精度を獲得したことがわかります。