NLTKによるテキスト要約(Python版

この記事を書いている現在、インターネット上では1,907,223,370のウェブサイトが活動し、毎秒2,722,460通の電子メールが送信されている。

これは信じられないほど膨大な量のデータである。

このような膨大な量のデータから、ユーザーがインサイトを得ることは不可能です。

さらに、このデータの大部分は冗長であるか、有用な情報をあまり含んでいません。

冗長で重要でないデータを選別することなく、データの最も重要な部分にアクセスする最も効率的な方法は、データを冗長でない有用な情報だけを含むように要約することである。

データは、音声、映像、画像、テキストなど、どのような形態でもよい。

今回は、テキストデータを要約するために、自動テキスト要約の技術をどのように利用できるかを見ていくことにする。

テキスト要約は、自然言語処理(NLP)のサブドメインで、巨大なテキストの塊から要約を抽出することを扱うものである。

テキスト要約に使用される技術には、主に2つのタイプがある。

NLPベースの技術とディープラーニングベースの技術です。

この記事では、NLPベースのシンプルなテキスト要約技術を見ていきます。

この記事では、機械学習ライブラリは使用しません。

PythonのNLTKライブラリを使って、Wikipediaの記事を要約します。

テキスト要約のステップ

NLPの技術を使ったテキスト要約のステップを、例を挙げて説明します。

以下は、第48回NAACPイメージ賞でのデンゼル・ワシントンの有名なスピーチの1段落です。

So, keep working. 努力し続けなさい。

決してあきらめるな。

7回倒れても8回起き上がればいい。

楽は苦難よりも進歩への大きな脅威である。

楽は苦難よりも進歩への大きな脅威である。

だから、前進し続け、成長し続け、学び続けなさい。

職場でお会いしましょう。

上記の段落から、彼は基本的に他の人に、一生懸命働き、決してあきらめないように動機づけをしていることがわかります。

NLPベースのテクニックを使って上記の段落を要約するには、一連のステップに従う必要があります。

パラグラフをセンテンスに変換する

まず、段落全体を文に変換する必要があります。

段落を文に変換する最も一般的な方法は、ピリオドが来るたびに段落を分割することです。

そこで、今論争中の段落を文に分割すると、次のような文になります。

  1. だから、仕事を続けなさい
  2. 努力し続けること
  3. 決してあきらめないこと
  4. 7度倒れても8度起き上がる
  5. 楽は苦難よりも進歩への大きな脅威である
  6. 楽は苦難よりも進歩への大きな脅威である。
  7. だから、前進し続け、成長し続け、学び続けよ
  8. 職場でお会いしましょう

テキスト前処理

パラグラフをセンテンスに変換した後、すべてのセンテンスから特殊文字、ストップワード、数字を削除する必要があります。

前処理の結果、以下のような文章が得られる。

1.働き続ける
2.努力し続ける
3.決して与えない
4.七転び八起き
5.大きな脅威を和らげる 進歩する苦難
6.大きな脅威を和らげる 進歩する苦難
7.動き続ける成長し続ける学び続ける
8.仕事を見る

文のトークン化

文中に存在するすべての単語を取得するために、すべての文をトークン化する必要がある。

文章をトークン化すると、以下の単語のリストが得られる。

['keep',
 'working',
 'keep',
 'striving',
 'never',
 'give',
 'fall',
 'seven',
 'time',
 'get',
 'eight',
 'ease',
 'greater',
 'threat',
 'progress',
 'hardship',
 'ease',
 'greater',
 'threat',
 'progress',
 'hardship',
 'keep',
 'moving',
 'keep',
 'growing',
 'keep',
 'learning',
 'see',
 'work']


発生頻度の重み付けを求める

次に、すべての単語の重み付き出現頻度を求める必要があります。

各単語の重み付き頻度は、その頻度を最も多く出現する単語の頻度で割ることによって求めることができます。

次の表は、各単語の重み付けされた頻度を含んでいます。

| 単語|頻度|重み付き頻度
| — | — | — |
| 容易さ|2|0.40
| エイト|1|0.20
| 落ちる|1|0.20
| ゲット|1|0.20
| 与える|1|0.20
| 大きい|2|0.40
| 成長する|1|0.20
| 苦労する| 2| 0.40
| 維持|5|1.00
| 学習|1|0.20
| 移動|1|0.20
| 一度もない|1|0.20
| 1|0.20|進歩|2|0.40
| 見る|1|0.20
| 1|0.20|セブン|1|0.20
| 努力|1|0.20|。

| 脅威| 2 | 0.40
| 時間|1|0.20||||。

| 仕事|1|0.20
|働く|1|0.20||。

keep “という単語の出現頻度が5と最も高いので、すべての単語の重み付き出現頻度を5で割って計算しました。

元の文の重み付けされた頻度で単語を置き換える。

最後のステップは、元の文の対応する単語の代わりに重み付けされた頻度を差し込み、それらの合計を求めることである。

前処理で削除された単語(ストップワード、句読点、数字など)の重み付き頻度はゼロになるので、以下のように追加する必要がないことに言及することは重要です。

| 文|重み付き頻度の総和| —-|文|重み付き頻度の総和| —-|文|重み付き頻度の総和

| だから、働き続けなさい|1 + 0.20 = 1.20|。

| 努力し続けなさい|1 + 0.20 = 1.20|…
| あきらめない|0.20 + 0.20 = 0.40|。

| 7回転んでも8回起き上がる|0.20 + 0.20 + 0.20 + 0.20 = 1.0|。

文章を和の降順で並べ替える

最後のステップは、文章をその合計の逆順に並べ替えることです。

最も高い頻度を持つ文は、テキストを要約しています。

例えば、加重頻度の合計が最も高い文章を見てみましょう。

となります。

だから、動き続け、成長し続け、学び続けよう。

となっています。

このパラグラフが何について書かれているのか、簡単に判断することができます。

同様に、加重頻度の合計が2番目に高い文章を追加すると、より情報量の多い要約になります。

次の文章を見てみましょう。

So, keep moving, keep growing, keep learning. 楽は苦難よりも進歩への大きな脅威である。

この2つの文章は、このパラグラフで語られたことをかなりよくまとめています。

ウィキペディアの記事を要約する

さて、非常にシンプルな自然言語処理技術を使ってテキストの要約がどのように行われるかがわかりました。

このセクションでは、PythonのNLTKライブラリを使って、Wikipediaの記事を要約してみます。

ウィキペディアから記事を取得する

Wikipediaの記事を要約する前に、ウェブから記事を取得する必要があります。

そのために、いくつかのライブラリを使用します。

最初にダウンロードする必要があるライブラリは、ウェブスクレイピングのための非常に便利なPythonユーティリティであるbeautiful soupです。

コマンドプロンプトで以下のコマンドを実行し、Beautiful Soupユーティリティをダウンロードします。

$ pip install beautifulsoup4


XMLやHTMLをパースするために必要なもう一つの重要なライブラリは、lxmlライブラリです。

コマンドプロンプトで以下のコマンドを実行し、lxmlをダウンロードしてください。

$ pip install lxml


それでは、ウェブからデータをスクレイピングするためのPythonのコードを書いてみましょう。

今回スクレイピングするのは、Wikipediaの人工知能に関する記事です。

以下のスクリプトを実行してください。

import bs4 as bs
import urllib.request
import re


scraped_data = urllib.request.urlopen('https://en.wikipedia.org/wiki/Artificial_intelligence')
article = scraped_data.read()


parsed_article = bs.BeautifulSoup(article,'lxml')


paragraphs = parsed_article.find_all('p')


article_text = ""


for p in paragraphs:
    article_text += p.text


上のスクリプトでは、まずウェブからデータをスクレイピングするために必要な重要なライブラリをインポートしています。

次に、urllib.request ユーティリティの urlopen 関数を使用して、データをスクレイピングします。

次に、データを読み込むために、urlopen関数から返されたオブジェクトに対してread関数を呼び出す必要があります。

データを解析するには、BeautifulSoup オブジェクトを使用して、スクラップしたデータオブジェクトである articlelxml パーサーを渡します。

Wikipedia の記事では、記事のすべてのテキストは <p タグで囲まれています。

テキストを取得するためには、 BeautifulSoup が返すオブジェクトに対して find_all 関数を呼び出す必要があります。

タグの名前は関数のパラメータとして渡されます。

find_all` 関数は、記事中のすべての段落をリスト形式で返します。

すべての段落が組み合わされて記事が再現されています。

記事をスクレイピングしたら、いくつかの前処理を行う必要があります。

前処理

最初の前処理は、記事から参考文献を削除することである。

Wikipediaでは、リファレンスは角括弧で囲まれています。

以下のスクリプトは角括弧を削除し、その結果生じる複数のスペースを一つのスペースに置き換える。

以下のスクリプトを見てみよう。

# Removing Square Brackets and Extra Spaces
article_text = re.sub(r'[[0-9]*]', ' ', article_text)
article_text = re.sub(r's+', ' ', article_text)


article_text` オブジェクトは括弧のないテキストを含んでいます。

しかし、これはオリジナルの記事なので、他のものは削除したくありません。

このテキストを使って要約を作成し、重み付き単語頻度をこの記事で置き換えるので、このテキストから他の数字、句読点、特殊文字を削除しないことにします。

テキストをきれいにし、重み付き頻度を計算するために、別のオブジェクトを作成します。

次のスクリプトを見てください。

# Removing special characters and digits
formatted_article_text = re.sub('[^a-zA-Z]', ' ', article_text )
formatted_article_text = re.sub(r's+', ' ', formatted_article_text)


これで、元の記事を含む article_text と、整形された記事を含む formatted_article_text の2つのオブジェクトができました。

formatted_article_textを使って、単語の重み付き頻度ヒストグラムを作成し、この重み付き頻度をarticle_text` オブジェクトの単語と置き換えます。

テキストを文章に変換する

この時点でデータの前処理を行いました。

次に、記事をセンテンスにトークン化する必要があります。

article_textオブジェクトはフルストップが含まれているため、トークン化に使用します。

formated_article_text には句読点が含まれていないため、パラメータとしてフルストップを使用してセンテンスに変換することはできません。

以下のスクリプトは文のトークン化を行います。

sentence_list = nltk.sent_tokenize(article_text)


発生頻度の重み付けを求める

各単語の出現頻度を求めるために、formatted_article_text変数を使用します。

この変数には句読点や数字などの特殊文字が含まれていないため、出現頻度を求めるためにこの変数を使用しました。

次のスクリプトを見てみよう。

stopwords = nltk.corpus.stopwords.words('english')


word_frequencies = {}
for word in nltk.word_tokenize(formatted_article_text):
    if word not in stopwords:
        if word not in word_frequencies.keys():
            word_frequencies[word] = 1
        else:
            word_frequencies[word] += 1


上のスクリプトでは、まず、nltkライブラリから取得した英語のストップワードをすべて stopwords 変数に格納する。

次に、すべての文とそれに対応する単語をループして、まずそれらがストップワードであるかどうかをチェックする。

もしそうでなければ、その単語が word_frequencies という辞書に存在するかどうかをチェックする。

その単語が初めて出現した場合、その単語をキーとして辞書に追加し、その値を1に設定する。

そうでない場合、その単語が以前から辞書に存在すれば、その値は単に1だけ更新される。

最後に、加重頻度を求めるには、以下に示すように、すべての単語の出現回数を最も多く出現した単語の頻度で単純に割ればよい。

maximum_frequncy = max(word_frequencies.values())


for word in word_frequencies.keys():
    word_frequencies[word] = (word_frequencies[word]/maximum_frequncy)


センテンススコアの計算

これで、すべての単語の重み付き頻度が計算できました。

次に、各文章のスコアを計算するために、その特定の文に出現する単語の重み付き頻度を追加します。

文のスコアを計算するスクリプトを以下に示す。

sentence_scores = {}
for sent in sentence_list:
    for word in nltk.word_tokenize(sent.lower()):
        if word in word_frequencies.keys():
            if len(sent.split(' ')) &lt; 30:
                if sent not in sentence_scores.keys():
                    sentence_scores[sent] = word_frequencies[word]
                else:
                    sentence_scores[sent] += word_frequencies[word]


上のスクリプトでは、まず空の sentence_scores 辞書を作成する。

この辞書のキーは文そのものであり、値はその文に対応するスコアである。

次に、sentence_list にある各文をループし、文を単語にトークン化します。

次に、その単語が word_frequencies 辞書内に存在するかどうかをチェックする。

このチェックは article_text オブジェクトから sentence_list リストを作成した際に行われます。

一方、単語の出現頻度は formatted_article_text オブジェクトを使用して計算されており、ストップワードや数値などは含まれていません。

我々は要約にあまり長い文章を入れたくないので、30ワード以下の文章のみに対してスコアを計算します(ただし、このパラメータは自分のユースケースに合わせて微調整することができます)。

次に、その文が sentence_scores の辞書に存在するかどうかを確認する。

文が存在しない場合は、その文をキーとして sentence_scores 辞書に追加し、その値として文中の最初の単語の重み付き頻度を代入します。

逆に、その文が辞書に存在する場合は、既存の値にその単語の重み付き頻度を追加するだけである。

要約の取得

これで sentence_scores という辞書ができ、文とその文に対応するスコアが格納されました。

記事を要約するためには、スコアの高い上位N個の文章を取得すればよい。

以下のスクリプトは上位7つの文章を取得し、画面に表示する。

import heapq
summary_sentences = heapq.nlargest(7, sentence_scores, key=sentence_scores.get)


summary = ' '.join(summary_sentences)
print(summary)


上のスクリプトでは、heapqライブラリの nlargest 関数を呼び出して、スコアの高い上位7つの文章を取得しています。

出力の概要は以下のようになる。

人工知能(AI)は、機械知能とも呼ばれ、人間や他の動物が示す自然知能とは対照的に、機械によって示される知能のことです。

AIには、探索や数学的最適化、人工ニューラルネットワーク、統計学・確率論・経済学に基づく手法など、多くのツールが使用されています。

AI研究の伝統的な問題(または目標)には、推論、知識表現、計画、学習、自然言語処理、知覚、物体の移動と操作の能力などがある。

1950年代半ばにデジタルコンピューターへのアクセスが可能になると、AI研究は、人間の知能が記号操作に還元される可能性を探り始めた。

これに対処する一つの案として、最初に一般的な知能を持つAIを「フレンドリーAI」とし、その後開発されるAIをコントロールできるようにすることが考えられる。

現在、AI研究者の大半は、扱いやすい「狭域AI」(医療診断やカーナビなど)のアプリケーションに取り組んでいる。

機械学習とは、経験によって自動的に改善されるコンピュータのアルゴリズムを研究するもので、AI研究開始当初からの基本概念である。

Wikipediaの記事は頻繁に更新されるので、スクリプトの実行時間によって異なる結果が得られる可能性があることを忘れないでください。

さらに上を目指す – 手作りのEnd to Endプロジェクト

好奇心旺盛なあなたは、もっと先を目指したいと思っていませんか?ガイド付きプロジェクトのチェックをお勧めします。

「CNNとKerasのTransformerを使った画像キャプション作成」をご覧ください。

をご覧ください。

このガイド付きプロジェクトでは、画像を入力として受け取り、出力としてテキストキャプションを生成する画像キャプションモデルの構築方法を学びます。

このプロジェクトでは、次のことを学びます。

  • テキストを前処理する
  • 入力されたテキストを簡単にベクトル化する
  • tf.data APIを使用し、パフォーマンスの高いデータセットを構築する。
  • TensorFlow/Keras と KerasNLP – 最先端の NLP モデルを構築するための Keras への公式な水平方向の追加機能 – を使用してゼロから Transformers を構築する。
  • あるネットワークの出力が別のネットワークにエンコードされるハイブリッドアーキテクチャの構築

画像キャプションをどのようにとらえるか?私たちはネットワークに説明を生成するように教えているので、ほとんどの人が生成的な深層学習の例だと考えています。

しかし、私はこれをニューラル機械翻訳の一例と見なしたいと思います。

つまり、画像の視覚的特徴を言葉に翻訳しているのです。

翻訳することで、単に新しい意味を生成するだけでなく、その画像の新しい表現を生成しているのです。

翻訳、ひいては生成と捉えることで、このタスクは別の観点から見ることができ、もう少し直感的に理解できるようになります。

問題を翻訳の問題としてとらえることで、どのアーキテクチャを使いたいかを考えることが容易になる。

エンコーダのみのトランスフォーマーは、エンコーダが意味のある表現をエンコードするため、テキストの理解(感情分析、分類など)に適している。

デコーダのみのモデルは、デコーダが意味のある表現を同じ意味を持つ別のシーケンスに推論することができるため、生成(GPT-3など)に最適である。

翻訳とは通常、エンコーダーとデコーダーのアーキテクチャによって行われ、エンコーダーは文(我々の場合は画像)の意味のある表現をエンコードし、デコーダーはこのシーケンスを我々にとってより解釈しやすい別の意味のある表現(文など)に変換することを学習するものである。

結論

この記事では、Python NLTKライブラリの助けを借りて、テキストの要約を行うプロセスを説明しました。

また、BeautifulSoapライブラリを使って記事をスクレイピングする過程も簡単に説明しました。

Wikipediaから他の記事をスクレイピングして、記事の良い要約が得られるかどうか見てみることをお勧めします。

タイトルとURLをコピーしました