ルールベースでWebページから日本語のテキストを清掃する


はじめに

mc4などのコーパスを清掃するコードを調べたり書いたりしています。
本記事では、こちらのGitのコードを模倣しながら、若干の追記修正を入れてクリーニングしてみました。

2/21追記
関連コードをgithubにuploadしました。


要するにどうなったのか?

以下のコード(MITライセンス)を実行することで、テキストが清掃されます。

def do_filter(text):
    text = text_normalizer.normalize(text) #正規化
    text = clean_text.do_clean(text, 100)  # 文末が...などを削除 (webページでよくある)
    text = clean_text2.do_filter(text)  # 繰り返しの多い文などを削除
    text = linewise_filtering.do_filter(text)  # ルールベースで行を削除
    text = freq_filter.do_filter(text)  # 単語だらけの行を削除

    return text

多段階のフィルタをかけた様子は以下の通り。
キレイな文章はそのまま残ります。

単語の羅列だらけの行などが、消えます。

フィルタ解説

1段階目

文字列を正則化します。以下のコードをそのまま使いました。
https://github.com/lighttransport/japanese-llama-experiment/blob/main/02_normalize/text_normalizer.py

2段階目

ルールベースでおかしな行を消していきます。
(ひらがなが全く含まれていない文、カンマで終わっている文など)
このタイミングで、bunkaiというライブラリが動きます。これによって、変な箇所での改行などが修正されます。

https://github.com/lighttransport/japanese-llama-experiment/blob/main/03_clean_step1/clean_text.py

3段階目

長すぎる文章などを消します。
元のscriptでは、is_repetition_removalという関数で、重複の多い文を消すアルゴリズムも実装されていたんですが、体感的には普通の文章も、相当数、消されたしまったので、コメントアウトしました。
(また、この処理は、かなり時間がかかるようです。これがあると、5it/sec、これがないと、500it/sec程度でした)

https://github.com/lighttransport/japanese-llama-experiment/blob/main/03_clean_step2/clean_mc4_task.py

4段階目

ルールベースで文章をキレイにします。'...(続きを表示)', '[ 続きを見る ]'などを消します
https://github.com/lighttransport/japanese-llama-experiment/blob/main/03_clean_step3_linewise/linewise_filtering.py

5段階目

本記事の追加実装です。
「脂肪吸引モニター体験 脂肪吸引の基礎知識[385] [386] [387] [388] [389] [390] [391]」のような、日本語として成立していない行を消していきます。
形態素解析を行い、名詞や記号だらけの行を削除するアルゴリズムです。


import MeCab
from collections import Counter

# テキスト
tagger = MeCab.Tagger()


def do_filter(text):
    if text is None:
        return None

    lines = text.split("\n")
    out_lines = []
    for line in lines:
        out_line = frequency_filter(line)
        if out_line is not None:
            out_lines.append(out_line)
    if len(out_lines) == 0:
        return None
    return "\n".join(out_lines)


def frequency_filter(text, threshold=0.8):

    # テキストを解析
    parsed = tagger.parse(text)

    # 品詞をカウントするためのCounterオブジェクト
    pos_counter = Counter()

    # 解析結果を行ごとに処理
    all_counts = 0
    for line in parsed.split('\n'):
        # EOSまたは空行の場合はスキップ
        if line == 'EOS' or line == '':
            continue
        # タブで分割し、形態素情報を取得
        pos_info = line.split('\t')
        pos = pos_info[4]
        pos = pos.split("-")[0]
        # 品詞をカウント
        pos_counter[pos] += 1
        all_counts += 1

    meishi_and_symbol_counts = pos_counter['名詞'] + \
        pos_counter['記号']+pos_counter['補助記号']

    ratio = meishi_and_symbol_counts/all_counts
    # print(ratio, pos_counter)
    if ratio > threshold:
        return None
    else:
        return text

6段階目(未実装)

元のscriptでは、perplexityによって日本語らしさを判定する処理が入っていましたが、環境設定に時間がかかりそうだったので、一旦、割愛しました。
https://github.com/lighttransport/japanese-llama-experiment/tree/main/04_lm_scoring

フィルタリング結果・まとめ

こちらの記事で自動抽出したテキストを、更にクリーニングしました。

体感では、かなりキレイになった気がします。

いいなと思ったら応援しよう!