😺

【Team JINIAC】 個人情報(名前、電話番号、メールアドレス)のマスキング(Hojicharを活用したデータセットの前処理)

2024/08/20に公開

この記事で分かること

  • 日本語テキストデータにおける、個人名等のフィルタリングの手法
  • Hojicharパイプラインによる、データセットの前処理

はじめに

大規模言語モデルの事前学習においては大量のテキストデータが必要であり、そのデータセット作成が一つの課題となっています。特に、個人情報保護の観点から、事前学習に使用するデータセットの作成においては、テキストデータに含まれる個人情報の除去が必須となります。

今回、私たち(Team JINIAC Daichi Kohmoto、山口 裕輝、辻 大地)は、CulturaXというデータセットから日本語データを抽出し、その前処理を行いました。

その中で、Hojicharというフレームワークを活用して、テキストデータのフィルタリングを行いました。しかし、Hojicharの既存のフィルタリングパイプラインには、日本語の個人名をフィルタリングする機能が含まれていませんでした。そこで、私たちは新たにreplace_entitiesというフィルターを作成しました。

  • CulturaX: CommonCrawl から抽出された 、mC4 および OSCAR データセット
  • HojiChar: テキストデータの前処理のためのPythonモジュール

replace_entitiesフィルター

replace_entitiesは、"名前+敬称(さん、くん、君、様)"となっている箇所を抽出し、名前部分をランダムな姓に置換するフィルターです。具体的には、次のようなコードで実装されています。

def replace_entities(text): 

    # 名前を置換 
    text = re.sub( 
        r"(?P<name>\p{Script=Han}+)(?P<honorific>さん|くん|様|君)", 
        lambda m: fake.last_name() + m.group("honorific"), 
        text, 
    ) 
 
    # 電話番号を置換 
    text = re.sub(r"\d{2,4}-?\d{2,4}-?\d{2,4}", lambda x: fake.phone_number(), text) 

    # メールアドレスを置換 
    text = re.sub(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", fake.email(), text) 
    return text 

上のコードの解説は、次のとおりです。

  1. 名前の置換

    text = re.sub(r'(?P<name>\p{Script=Han}+)(?P<honorific>さん|くん|様|君)',
    lambda m: fake.last_name() + m.group('honorific'), text)
    

    この行では、テキスト内の漢字で書かれた名前とそれに続く敬称(さん、くん、様、君)を検出し、それらをダミーの名前に置換します。

    **re.sub関数を用いて、正規表現パターンに一致するすべての部分文字列を検出し、fake.last_name()**を使用してダミーの名前を生成して置き換え、元の敬称をその後に追加しています。

  2. 電話番号の置換

    text = re.sub(r'\d{2,4}-?\d{2,4}-?\d{2,4}', lambda x: fake.phone_number(), text)
    

    この行では、テキスト内の電話番号を検出し、それらをダミーの電話番号に置換します。2〜4桁の数字、オプションのハイフン、2〜4桁の数字、オプションのハイフン、2〜4桁の数字で構成されている箇所を検出し、**fake.phone_number()**を使用してダミーの電話番号を生成して置換します。

  3. メールアドレスの置換

    text = re.sub(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', fake.email(), text)
    

    この行では、テキスト内のメールアドレスを検出し、それらをダミーのメールアドレスに置換します。メールアドレスは通常、一部の文字、記号、数字、@記号、ドメイン名、ピリオド、および2文字以上のトップレベルドメインの形式で構成されている箇所を検出し、**fake.email()**を使用して生成するダミーのメールアドレスに置き換えます。

このフィルターは、Fakerというライブラリを使用して、実際の個人情報をダミーデータに置き換えています。これにより、元のテキストの構造を保ちつつ、個人情報を適切にマスキングすることができます。

Hojicharによる正規化、JSON変換と組み合わせてフィルタリング

Google Colaboratry での実行を想定したコードは次のとおりです。

!pip install -U hojichar==0.9.0
!pip show hojichar
!pip install regex
!pip install faker

import regex as re
import json
import random
import hojichar
from multiprocessing import Pool, cpu_count
from faker import Faker

fake = Faker('ja_JP')  # 日本語のダミーデータを生成するためのFakerインスタンス

num_samples = 100000
dummy_texts = [
    "こんにちは田中君、これはテストデータです。電話番号は08098765432です。佐藤さんのメールアドレスはdef@example.comです。",
    "山田くんのメールアドレスはjtwmdagp@gmail.comで、電話番号は03-1234-5678です。",
    "HojiCharを使用して前処理を行います。村上様の電話番号は、075-4329-9899です。",
]

def replace_entities(text):
    # 名前を置換
    text = re.sub(r'(?P<name>\p{Script=Han}+)(?P<honorific>さん|くん|様|君)',
                  lambda m: fake.last_name() + m.group('honorific'), text)

    # 電話番号を置換
    text = re.sub(r'\d{2,4}-?\d{2,4}-?\d{2,4}', lambda x: fake.phone_number(), text)

    # メールアドレスを置換
    text = re.sub(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', fake.email(), text)

    return text

def process_text(text):
    replaced_text = replace_entities(text)
    # HojiCharの処理
    cleaner = hojichar.Compose([
        hojichar.document_filters.DocumentNormalizer(),
        hojichar.document_filters.JSONDumper(),
    ])
    document = hojichar.Document(json.dumps({"text": replaced_text}))
    cleaned_text = cleaner.apply(document).text
    return cleaned_text

def main():
    random_texts = [random.choice(dummy_texts) for _ in range(num_samples)]
    num_cores = cpu_count()

    with Pool(num_cores) as pool:
        processed_texts = pool.map(process_text, random_texts)

    with open("your_text.jsonl", "w") as f:
        for processed_text in processed_texts:
            f.write(processed_text + "\n")

    # 結果の表示
    num_display = 100
    with open("your_text.jsonl", "r") as f:
        for i, line in enumerate(f):
            if i >= num_display:
                break
            data = json.loads(line)
            actual_text = json.loads(data['text'])
            print(actual_text)

if __name__ == "__main__":
    main()

まとめ

データセットの前処理は、大規模な言語モデルの訓練において重要なステップです。特に個人情報のマスキングは、プライバシー保護の観点から必須となります。

今回、私たちはHojicharを活用し、新たにreplace_entitiesというフィルターを追加してCulturaXデータセットのフィルター処理を行いました。

一方、この手法では名前をランダムに置換してしまうため、マルチターン形式のデータセットには使用できない点に留意が必要です。

💡 この成果は、NEDO(国立研究開発法人新エネルギー・産業技術総合開発機構)の助成事業「ポスト5G情報通信システム基盤強化研究開発事業」(JPNP20017)の結果得られたものです。

東大松尾・岩澤研究室 | LLM開発 プロジェクト[GENIAC]

Discussion