Luhnの要約アルゴリズムの前処理

入門 ソーシャルデータ ―データマイニング、分析、可視化のテクニック

入門 ソーシャルデータ ―データマイニング、分析、可視化のテクニック

入門 ソーシャルデータ ―データマイニング、分析、可視化のテクニックの8.4章に、Luhnのプリミティブな要約アルゴリズムの解説がある。 このアルゴリズムは非常にシンプルであるものの、そこそこの精度が出せる。 解説では英語のみの対応となっていたため、日本語にも適用できるようにしてみた。

アルゴリズムは、基本的な自然言語処理を行う前処理と、Luhnの要約アルゴリズムとなる本処理、 要約を出力するための後処理に別れる。 ここではまず前処理について説明する。

要約対象テキスト

Google翻訳は人間レベルの翻訳精度を目指して人工知能を活用 の記事本文を要約対象としてみる。

text = "スマートフォンでもPCでもオフラインでも使え、100以上の言語に対応しているGoogleの翻訳サービス「Google翻訳」が、ちょうど10周年を迎えるタイミングでより自然な翻訳を可能にする人工知能(AI)を活用した「GNMT」システムを発表しました。\
AI研究で複数の大手IT企業とのパートナーシップを結んだばかりのGoogleは、AIを駆使した翻訳システム「GNMT(Google Neural Machine Translation)」を発表しました。Google翻訳ではこれまでフレーズベースで機械翻訳するPBMTという\
システムが採用されていましたが、このような単語やフレーズごとに機械的に文章を翻訳する方法ではなく、文章全体をひとつの翻訳単位として捉えることができるのがGNMTだそうです。Googleの研究者によると、「GNMTの『文章全体をひとつの翻訳単位\
として捉える』アプローチの長所は、工学的設計の選択肢がPBMTよりも少なくて済むことです」とのこと。実際にGNMTを駆使した最初の翻訳では、既存のGoogle翻訳と遜色ない翻訳精度がみられたそうです。さらに、何度も翻訳を重ねることで、\
GNMTは優れた翻訳と素早い翻訳スピードの両立が可能になっている模様。Googleによると、GNMTを用いることでGoogle翻訳は翻訳ミスを55~85%も軽減できるようになるとのこと。GoogleによるとGNMTは一部のケースでは人間レベルの翻訳が\
可能なレベルに達しているとのこと。以下のグラフは人間・GNMT・PBMTの3つによる翻訳を6段階評価して比較したもので、最も翻訳精度が高いのは人間による翻訳ですが、フランス語から英語に翻訳する場合や英語からスペイン語に翻訳する場合、\
人間とGNMTの間にそれほど大きな差は存在しないそうです。"

テキストを文に分割

自作の日本語の自然言語処理ライブラリー nltkjp.py (詳しくはここここを参照) に、「。」で分割してリスト化するだけの処理を行うメソッド sent_tokenize() を追加した。

def sent_tokenize(self, doc):
    sents = [d.decode("utf-8") for d in doc.split(u'。')]

    return sents

まずはテキストをこれにかける。

nltkjp = NLTKJP()

# テキストを文に分割
sents = nltkjp.sent_tokenize(text)
>>> for sent in sents:
>>>     print sent
スマートフォンでもPCでもオフラインでも使え、100以上の言語に対応しているGoogleの翻訳サービス「Google翻訳」が、ちょうど10周年を迎えるタイミングでより自然な翻訳を可能にする人工知能(AI)を活用した「GNMT」システムを発表しました
AI研究で複数の大手IT企業とのパートナーシップを結んだばかりのGoogleは、AIを駆使した翻訳システム「GNMT(Google Neural Machine Translation)」を発表しました
Google翻訳ではこれまでフレーズベースで機械翻訳するPBMTというシステムが採用されていましたが、このような単語やフレーズごとに機械的に文章を翻訳する方法ではなく、文章全体をひとつの翻訳単位として捉えることができるのがGNMTだそうです
...

文をすべて小文字に変換

英語の大文字を小文字に変換する。 本当は日本語の動詞もすべて基本形にするとかしないといけないのかもしれないけど、また今後。

normalized_sents = [sent.lower() for sent in sents]
>>> for ns in normalized_sents:
>>>     print ns
スマートフォンでもpcでもオフラインでも使え、100以上の言語に対応しているgoogleの翻訳サービス「google翻訳」が、ちょうど10周年を迎えるタイミングでより自然な翻訳を可能にする人工知能(ai)を活用した「gnmt」システムを発表しました
ai研究で複数の大手it企業とのパートナーシップを結んだばかりのgoogleは、aiを駆使した翻訳システム「gnmt(google neural machine translation)」を発表しました
google翻訳ではこれまでフレーズベースで機械翻訳するpbmtというシステムが採用されていましたが、このような単語やフレーズごとに機械的に文章を翻訳する方法ではなく、文章全体をひとつの翻訳単位として捉えることができるのがgnmtだそうです
...

各文を単語に分割して1つにまとめる

各文章を分かち書きにしてすべてまとめる。

words = [word.lower() for sent in normalized_sents for word in nltkjp.word_tokenize(sent)]
>>> for word in words[:10]:
>>>     print word
スマート
フォン
で
も
pc
で
も
オフライン
で
も
...

頻出単語を抽出する

ここで本家のnltkが登場。FreqDistに単語のリストを入れると、単語をカウントしてソートしてくれる。

fdist = nltk.FreqDist(words)
>>> for k,v in fdist.items()[:10]:
>>>     print k, '\t', v
printの    24
翻訳  23151414131211
gnmt    10
google  10
...

ストップワードでない上位N個の単語を抽出する

頻出単語からストップワードを除き、そのうちの上位N個を取得する。 100にしてるのは、解説がそうだったからだけど、今回の例では多い気がする。 ストップワードの取得については、以下の結果に"("が含まれていたりとまだ不備があるけど、アルゴリズム簡易的な日本語ストップワードの取得メソッドを参照。 ただし、今回はストップワードの品詞は名詞以外としている。

stopwords = nltkjp.stopwords(text)
N = 100
top_n_words = [w[0] for w in fdist.items() if w[0] not in stopwords][:N]
>>> for tnw in top_n_words[:10]:
>>>     print tnw
翻訳
gnmt
google
人間
ai
pbmt
システム
可能
文章
(
...

まとめ

以上が前処理となる。 各処理をまとめると以下のようになる。

import nltk
from nltkjp import NLTKJP

N = 100  # 考慮する単語の数

def main(text):
    nltkjp = NLTKJP()

    # テキストを文に分割
    sents = nltkjp.sent_tokenize(text)

    # 文をすべて小文字に変換
    normalized_sents = [sent.lower() for sent in sents]

    # 各文を単語に分割して1つにまとめる
    words = [word.lower() for sent in normalized_sents for word in nltkjp.word_tokenize(sent)]

    # 頻出単語を抽出する
    fdist = nltk.FreqDist(words)

    # ストップワードでない上位N個の単語を抽出する
    stopwords = nltkjp.stopwords(text)
    top_n_words = [w[0] for w in fdist.items() if w[0] not in stopwords][:N]