🐶

n-gramによるテキスト処理を実装する

2024/02/29に公開

はじめに

n-gramは自然言語処理における基本的な考え方であり、自然言語で構成された文章の特徴を定量的に調べるために開発された解析手法です。比較的理解しやすい概念であり、簡潔なプログラムで実装も可能なため今回は自然言語処理初学者の方向けにその概観をまとめていきたいと思います。

n-gramの概観

n-gramとはn個の連続した単語や文字のまとまりを意味します。例として以下の文章を見てみましょう。


「東京は日本の首都で日本で最も人口が多い地域です。」


以上の文章をn文字ずつのまとまりに分解します。皆さんもペンとメモを用意して一緒に分割してみましょう。
例えば最も簡単な1-gramでは元のテキストを1文字ずつに分解するため、


「東」「京」「は」「日」「本」「の」「首」「都」「で」「日」「本」「で」「最」「も」「人」「口」「が」「多」「い」「地」「域」「で」「す」「。」


上のように分割できますね。
日本語のテキストを解析する際には一般的には3文字ずつ分解する3-gramが用いられます。
実際に3-gramで上の文章を分解してみましょう。ここでは単純に3文字ずつに分けるだけではなくスタート文字を1文字ずつずらしながら3文字の組みを作っていきます。


「東京は」「京は日」「は日本」「日本の」「本の首」「の首都」「首都で」「都で日」「で日本」「日本で」「本で最」「で最も」「最も人」「も人口」「人口が」「口が多」「が多い」「多い地」「い地域」「地域で」「域です」「です。」


少し数が多くなってしまいましたが、皆さんは正しく分割できましたか?
n文字のテキストから3-gramを作るとn-2個の3-gramが作れるはずです。(今回は24文字のテキストを使用したため、22個に分割できれば正解です。)

以上の分割した3-gramは全て異なる種類で単語としての意味も破綻していますが、「日本」というワードを含むものは4回も出現しています。このことからこの文章は日本に関する主張を述べていることが推測できます。このようにn-gramを用い出現する単語の分布を調べることで元テキストの特徴を表現することが可能です。

次に、より長く実用的なモデルテキストを用いて解析を行ってみましょう。今回は太宰治の単行小説「斜陽」の第1章部分をモデルテキストに用いました。「斜陽」の電子テキストは青空文庫公式webページよりお借りしました。

以下は「斜陽」のモデルテキストを3-gramにより解析し、その出現頻度の分布をまとめたものです。

順位 3-gram 出現回数(回)
1 お母さ 109
2 母さま 109
3 った。 86
4 って、 52
5 になっ 50

数百にも及ぶ3-gramを取得しましたが、その出現頻度上位5つは以上になります。「斜陽」は失礼ながら未読ですが、この作品の冒頭部分には語り手の「お母さま」が登場します。必然的に出現回数の上位は彼女が独占していますね。また終止の「った。」や文脈接続の「って、」なども数多く出現しているようです。

私が以上に示したものはとても簡単な例ですが、n-gramの考え方やアルゴリズムを応用することで、モデルテキストの特徴を表現することができます。また、複数の文章に同様の解析を行うことで文章同士の類似性を推測したりテキストの誤った表現を発見することも可能です。

では、実際にモデルテキストからgram分布を表現するまでの具体的な実装方法を見ていきましょう。

pythonによる具体的な実装

テキストデータの前処理

それでは実際に規模の大きい日本語のモデルテキストを利用して解析を行います。上記の青空文庫のwebページからダウンロードしたテキストデータを「shayou.txt」として保存しました。
しかしこのデータには注釈やルビ、記号など解析に必要のないデータが含まれている可能性があります。そこで元データからこれらの不要なデータを除去する前処理のためのプログラムを作成する必要があります。
以下は今回作成した「prep.py」の抜粋です。

prep.py
import sys
import re

inputtext = sys.stdin.read()

outputtext = inputtext.replace("¥n","") #改行コードの削除

outputtext = re.sub("<<.+?>>","",outputtext) #ルビの削除
outputtext = re.sub("|","",outputtext) #ルビ開始記号の削除
outputtext = re.sub("[.+?]","",outputtext) #入力者注の削除  

print(outputtext)

元テキストから解析対象と無関係な要素を削除するために正規表現を利用した文字列の置換プログラムを作成しました。pythonによる正規表現についてはここでは詳しくは取り上げませんが、replace()メソッドre.sub()関数を用いています。第一引数は特定の記号と任意の文字列を示す記法です。

https://ai-inter1.com/python-regex/

作成したプログラムは以下のように実行してください。「prep.py」においてshayou.txtからの入力を指示するとともに実行結果をresult.txtというファイルに書き出すことを指定しています。

> python prep.py < shayou.txt > result.txt

3-gramによる解析

データの前処理が済んだので、実際に加工後テキストデータから3-gramを作成し解析するプログラムを作成しましょう。
以下は今回作成した「3-gram.py」の抜粋です。具体的には文字列を一定幅ごとに切り出し集計するスクリプトを書きます。

3-gram.py
import sys
import collections
import pprint

#文字列の読み込み
inputtext = sys.stdin.read()

#3-gramの作成
ngram = []
for i in range(len(inputtext) - 2):
    ngram.append(inputtext[i:i+3])

#並べ替え
c = collections.Counter(ngram)
pprint.pprint(c)

元データをスライスで3文字ごとに区切り、ngramというリストに格納しています。collections.Counter()メソッドは引数にリストや配列を渡すと、その要素と要素数からなる辞書型を返します。今回はこのメソッドを用いて3-gramを整列し、その結果をpprint()関数を用いて出力しました。

3-gramの応用例

今回は単純に元データから得られた3-gramを出現回数によりソートしただけですが、このアルゴリズムを基盤に考え得る応用例を以下に列挙します。

  • 元文章の特徴を表現し視覚化
  • 複数の文章の類似性を推測
  • n-gramの分類、接続によるテキスト生成

n-gramは文書のクラスタリングや分類、検索エンジンの性能向上などに応用することができる他、マルコフ連鎖と呼ばれる確率的な考え方を用いたテキスト処理を実装する際の最も基本的な技術となります。n-gramを利用してテキストを生成する場合、前後の文脈を考慮した自然な文章を生成することが可能です。

最後に

この記事では、n-gramの基本的な概念から具体的な実装方法までを紹介しました。テキストデータの前処理が解析の正確性に大きく影響することや、実装方法についても触れました。これらの知識を活用することで、テキストデータから情報を抽出し、さまざまな応用に活かすことが可能です。自然言語処理に興味を持つ方にとって、基礎を習得するための第一歩となれば幸いです。

Discussion