ルールベースで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
多段階のフィルタをかけた様子は以下の通り。
キレイな文章はそのまま残ります。
![](https://assets.st-note.com/img/1708239772999-vv793VkQVv.png?width=1200)
単語の羅列だらけの行などが、消えます。
![](https://assets.st-note.com/img/1708239857735-vQ1lpYGUAg.png?width=1200)
フィルタ解説
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
フィルタリング結果・まとめ
こちらの記事で自動抽出したテキストを、更にクリーニングしました。
体感では、かなりキレイになった気がします。
![](https://assets.st-note.com/img/1708243054576-WqoWaKYAUD.png?width=1200)
この記事が気に入ったらサポートをしてみませんか?