テキストデータをNLPのコーパスとして活用するための事前処理


概要

web上から引っ張ってきたWikipediaのデータを元に、データ解析を行うための事前処理を行う。
具体的には以下の2点を導出する。

  • 単語の出現頻度(TF)

データ解析に使用する単語の選別時に使用。 TF に応じて、トレーニングデータに含めるか否か決める。

テキスト内にある単語すべてを解析対象とすると、解析時間のコストが増大する。
そこで TF が低い単語を解析対象から外すことで、時間コストの問題を低減する。

以下、単語の出現頻度 (TF) の一部サンプル。

単語ID 単語 テキスト内の出現頻度
30 使用 51
31 世紀 102
32 滞る 6



- テキストのインデックス化

TF 割り出し時に各単語に付けた インデックスによるテキスト管理を行うことで、one-hot encodingを使ったデータ解析を行いやすくする。

単語ID変換 【前】 のテキストサンプル
日本語は、主に日本国内や日本人同士の間で使用されている言語である。

単語ID変換 【後】
315, 8, 117, 26, 324, 484, 135, 1079, 797, 16, 235, 19, 30, 11, 22, 58, 59, 69, 13, 14

(単語ID 315: 日本語、単語ID 8: は)

手順

1. 準備

githubのコードをダウンロードし、 requirements.txtに記載の python ライブラリをインストール。

使用環境
python3.7.2
ライブラリのインストール
pip install -r requirements.txt

2. 単語の出現頻度(TF)を求め、DBに格納

2-1. 形態素解析を用い、テキストデータを単語に分割。分割した単語の出現頻度(TF)を求める

コーパス(ex.wikipedia)のデータを文単位に分割。
MeCabの形態素解析にかけて、さらに単語単位に分割。
単語の出現頻度は Counter クラスを用いて導出。

以下は、サンプル文に対しての処理の流れを記載

sample_sentence = '日本語は、主に日本国内や日本人同士の間で使用されている言語である。'

# 日本語の表層形でなく、基本形を使用するために、パーサーとしてOchasenを使用
tagger = MeCab.Tagger('-Ochasen')
# サンプル文を形態素解析した単語群にパース
node = tagger.parseToNode(sample_sentence)
words = []
while node:
    #  node.featureで、該当単語に対して以下の特徴抽出ができる
    # [品詞,品詞細分類1,品詞細分類2,品詞細分類3,活用型,活用形,原形,読み,発音]
    # 表層形でなく、基本形(原形)を採用
    word = node.feature.split(",")[6]
    # 日本語の表現だけを抽出
    if re.search(r'[ぁ-んァ-ヶ一-龥]+', word):
        words.append(word)
    node = node.next

words_frequency = Counter(words_list)

コーパスデータ内の全文に同様の処理を行い、 Counterクラス同士の加算演算をすることで、データ全体の単語出現頻度(TF)を算出。

2-2. DB(sqlite)の準備。単語の出現頻度(TF)をDBに格納

今後の処理を行いやすくするために、算出したデータをDBに格納。
以下、格納する wordsテープルの定義一覧

物理名 論理名 主キー AUTO INCREMENT
id インデックス INTEGER
word 単語 STRING
frequency 出現回数 STRING
wordsテーブルへの格納
# 以下<db_file_path>はsqliteのdbファイル格納場所
conn = sqlite3.connect('<db_file_path>')
cur = self.conn.cursor()

insert_word_sql = 'INSERT INTO words (word, frequency) values (?,?)'
inserted_info = []
# words テーブルに格納するデータを配列に格納し、一括でinsert
for word, frequency in dict(words_frequency).items():
    inserted_info.append((word, frequency))
cur.executemany(insert_word_sql, inserted_info)

3. テキスト内にある各単語をインデックス番号に変換し、DBに格納

3-1. テキスト内の各単語をインデックスに変換できるよう、dictionaryを作成

手順2で格納したテーブルデータから、 全単語のリストを抽出。
それを元に key:単語value:単語インデックスのdictionaryを作成。

# words テーブルから全データを抽出
cur.execute('SELECT * FROM words')
words_info = cur.fetchall()

word_stoi = {}
for word_info in words_info:
    word_stoi[word_info[1]] = word_info[0]

上で求めたdictionaryを使って、テキストデータを単語インデックスの配列に整形

words_indices = []
while node:
    word = node.feature.split(",")[6]
    # 日本語の表現だけを抽出
    if re.search(r'[ぁ-んァ-ヶ一-龥]+', word):
        words_indices.append(word_stoi[word])
    node = node.next
3-2. DBへの格納

元のテキストデータと単語をインデックス変換した配列のデータをDBに格納する
以下、格納する sentencesテープルの定義一覧

物理名 論理名 主キー AUTO INCREMENT
id インデックス INTEGER
word_sentence テキストデータ STRING
index_sentence 構成単語のID配列 STRING
insert_sentence_sql = '''
    INSERT INTO sentences (
        word_sentence, index_sentence
    ) values (?,?)
'''
inserted_info = [sample_sentence, str(words_indices)]
cur.execute(insert_sentence_sql, inserted_info)

結論

NLP処理を行うための前準備として、テキストデータの処理を行った。
またDBに格納することで、今後の処理を行いやすくした。

ここでは、サンプル文に対するデータ処理を掲載したが、wikipedia全データに対する処理の流れは、jupyter notebookに掲載。
全コードは、github参照。

参考