AI処理下準備：学習データに含まれる個人情報データをローカルPC上でマスキングする

# (1) 今回やりたいこと（概要）

個人情報（名前・住所など）をバリバリに含むテキストデータを、クラウドAIサービスに投げる前に、ローカル環境で個人情報をマスキングして隠す処理を施す。

```
利用客の山田太郎様が世田谷区から来られて、一泊二日されました。
```
↓
```
利用客の●●●●様が●●から来られて、一泊二日されました。
```


# (2) 経緯

ChatGPT、便利ですよね。

LLM系に限らず、世の中便利なAIサービスが多数出てきているので、色々なデータを喰わせてみて、どのような活用ができるか探るのはとても楽しいことです。

でも、手元のデータに個人情報が含まれる場合は、気の赴くまま気軽にやっちゃいけません。うっかりすると個人情報保護違反になる恐れが。

信頼できるAIサービス業者に委ねればいい。そういう考え方もありますね。

例えばChatGPT系だと、本家OpenAI社やAzure経由でサービス提供しているMicrosoft社は、ユーザから受け取ったデータをAI学習に利用しない（＝外部に漏洩させない）というオプション規約を用意しています。注意してデータを委ねれば、データの安全性は守られると見込まれます。

しかし絶対安全安心ではありません。先方のプログラムのバグや、設定ミスや、悪意ある内部犯によって、預けたサービスが外部に流出してしまう可能性は、常に考えておくべきです。

実際に、一部の企業や行政がChatGPTの活用に当たって業務機密や個人情報を含むデータでの利用を禁止するルールを定めていますが、そういうことだと思います。

ということで、ローカル環境で一旦データを処理して、危ないデータを消す方法になります。

:::note warn
組織が保有する個人情報データについては、当該組織の然るべき部署に事前に相談をした上で、慎重に行いましょう。
:::

:::note alert
100%完全完璧な個人情報除去ができるものではありません。処理の抜け漏れが無いか、自分の目で最終チェックする必要があります。

個人情報を全部マスキングしても、文脈でどこの誰についての情報か推測できることもあるので、そういうのも気をつけて下さい。
:::


# (3）動作環境
- 簡単な python プログラムです（ChatGPT 4 さんが主に作ってくれました）
- 入力されたテキストファイルを形態素解析して、個人情報と思われる種別の単語をマスキングして、出力します
- 日本語の形態素解析に、GiNZA を利用します（https://megagonlabs.github.io/ginza/）
- linux、もしくは、windows の WSL 環境で動きます

# (4）環境設定

以下コマンドで、必要なモジュールをインストールします。
（pythonの環境構築と、windows の WSL 環境構築については、別途調べてください）

```
pip install ginza
pip install spacy
pip install -U ginza ja-ginza 
```

# (5）プログラム

１ファイルです。適当なフォルダに、配置して下さい。

```mask_personal_info.py
import spacy
import argparse

'''
#要件
・テキストに含まれる個人情報を伏せ字に置き換えて、個人情報を含まないテキストとしてクリーニングする

# 動作
1.指定されたテキストファイルを読み込む
2.テキストファイルの文面に含まれる個人情報（名前・住所、等）を検出して、マスキングする
3.マスキングされた処理済みテキストを、テキストファイルとして保存する

# モジュールインストール
pip install ginza
pip install spacy
pip install -U ginza ja-ginza 

# コマンド例
python3 mask_personal_info.py input.txt output.txt --entities "名詞-固有名詞-人名-姓", "名詞-固有名詞-人名-名","名詞-固有名詞-地名-一般"
'''

def read_input_file(input_file):
    with open(input_file, "r", encoding="utf-8") as f:
        return f.read()

def write_output_file(output_file, processed_text):
    with open(output_file, "w", encoding="utf-8") as f:
        f.write(processed_text)

# text の中の個人情報をマスキングする
# entity_types には、マスキングするエンティティのタイプを指定する
def mask_personal_info(text, entity_types):
    nlp = spacy.load("ja_ginza")
    doc = nlp(text)

    masked_text = ""

    for sent in doc.sents:
        for token in sent:
            if token.tag_ in entity_types:
                masked_text += '●●' # token.orth_ をマスキングする
            else:
                masked_text += token.orth_

    return masked_text

def main():
    parser = argparse.ArgumentParser(description="Mask personal information in a text file.")
    parser.add_argument("input_file", help="Path to the input text file.")
    parser.add_argument("output_file", help="Path to the output text file.")
    parser.add_argument("--entities", nargs="+", default=["名詞-固有名詞-人名-姓", "名詞-固有名詞-人名-名", "名詞-固有名詞-地名-一般"], help="List of entity types to mask (default: Name Address)")
    args = parser.parse_args()

    text = read_input_file(args.input_file)
    masked_text = mask_personal_info(text, args.entities)
    write_output_file(args.output_file, masked_text)

if __name__ == "__main__":
    main()
```


# (6）実行のさせかた

- 個人情報マスキングしたいテキストファイルを、プログラムファイルと同じフォルダに、"input.txt" というファイル名で保存します。

- 以下のコマンドで、プログラムを動作させます。
```
python3 mask_personal_info.py input.txt output.txt --entities "名詞-固有名詞-人名-姓", "名詞-固有名詞-人名-名","名詞-固有名詞-地名-一般"
```

- 処理結果は、同じフォルダに "output.txt" として保存されます。

（デフォルトでは、【人名】【地名】の２種類をマスキング対象としていますが、対象データに合わせて他種別の単語もマスキング可能です。--entities の項目を調整してみて下さい）

（クレジットカード番号や顧客IDみたいなのは、別途、正規表現パターンでも使ってマスキングするのが良いかと思います）


# (7）注意

:::note warn
組織が保有する個人情報データについては、当該組織の然るべき部署に事前に相談をした上で、慎重に行いましょう。
:::

:::note alert
100%完全完璧な個人情報除去ができるものではありません。処理の抜け漏れが無いか、自分の目で最終チェックする必要があります。

個人情報を全部マスキングしても、文脈でどこの誰についての情報か推測できることもあるので、そういうのも気をつけて下さい。
:::