0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Python×生成AI】初級編:Python × 生成AIでExcelデータの表記ゆれを自動修正しよう!(OpenAI API)

0
Posted at

はじめに

前に、VBA×生成AIの記事を初級・中級・上級と3回連続でアップしました。

ここでは同じようにPython×生成AIの記事を初級・中級・上級と3回連続でアップしていきます。

======

Excelのデータを整理していて、こんな経験はありませんか?

  • 「株式会社ABC」と「(株)ABC」と「ABC株式会社」が混在している
  • 「東京都港区」と「東京都 港区」で半角スペースが入っていたりいなかったり
  • 「田中太郎」と「田中 太郎」で氏名の区切りがバラバラ

これらの表記ゆれは、VLOOKUP やピボットテーブルが正しく動かない原因になります。手作業で直すのは大変ですし、VBA で対応しようとしても「どのパターンに統一するか」のルール作りが膨大になりがちです。

この記事では、Python と OpenAI API(GPT) を使って、生成AIに表記ゆれの判断と修正を任せるツールを作ります。

この記事のシリーズ

レベル 内容
初級(本記事) Python + OpenAI API で Excel の表記ゆれを自動修正
中級(次回) Coming Soon
上級(次々回) Coming Soon

対象読者

  • Excel の表記ゆれに悩んだことがある方
  • Python をこれから学びたい方・始めたばかりの方
  • VBA でデータクレンジングをしていたが限界を感じている方

完成イメージ

こんな表記ゆれだらけの Excel ファイルが…

No 会社名 住所
1 株式会社ABC 東京都港区赤坂1-1-1
2 (株)ABC 東京都 港区 赤坂1-1-1
3 ABC株式会社 東京都港区赤坂1−1−1
4 株式会社エービーシー 東京都港区赤坂1丁目1番1号

↓ 生成AIが自動で統一!

No 会社名 住所
1 株式会社ABC 東京都港区赤坂1-1-1
2 株式会社ABC 東京都港区赤坂1-1-1
3 株式会社ABC 東京都港区赤坂1-1-1
4 株式会社ABC 東京都港区赤坂1丁目1番1号

注意: 「赤坂1丁目1番1号」と「赤坂1-1-1」のように意味は同じでも表記形式が異なるケースは、生成AIでも完全な統一が難しい場合があります。プロンプトの調整次第で改善可能ですので、4章のカスタマイズも参考にしてください。


1. 環境構築

1-1. 必要なもの

項目 説明
Python 3.9 以上
OpenAI API キー OpenAI Platform で取得
テキストエディタ VS Code 推奨

1-2. ライブラリのインストール

pip install openai python-dotenv openpyxl
ライブラリ 用途
openai OpenAI API を Python から呼び出す
python-dotenv API キーを安全に管理する
openpyxl Excel ファイル(.xlsx)の読み書き

1-3. プロジェクトフォルダの作成

まず、作業用のフォルダを作ります。エディタのターミナルを開いてください(メニューの「ターミナル」→「新しいターミナル」、またはショートカット Ctrl + `)。

ターミナルに以下を入力して Enter を押します。

mkdir excel-cleansing
cd excel-cleansing

すると、excel-cleansingフォルダに移動します。

1-4. API キーの設定

  1. エディタの左側エクスプローラーで「新しいファイル」アイコンをクリック

  2. ファイル名を .env と入力してEnter
    excel-cleansingフォルダ内に.envファイルを作成
    image.png

  3. OPENAI_API_KEY=sk-xxxxxxxx... と入力
    image.png

  4. ctrl + S で保存

.env
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

sk-xxxxxxxx... の部分は、自分の API キーに置き換えてください。
API キーは OpenAI Platform の API keys ページ で発行できます。

1-5. サンプルデータの準備

動作確認用の Excel ファイルを Python スクリプトで作成します。

手順1: エディタの左側エクスプローラーで「新しいファイル」アイコンをクリックし、create_sample.py というファイル名で作成します。

手順2: 以下のコードをそのままコピーして貼り付け、保存します。

create_sample.py
import openpyxl

wb = openpyxl.Workbook()
ws = wb.active
ws.title = "顧客リスト"

# ヘッダー
ws.append(["No", "会社名", "住所", "電話番号"])

# 表記ゆれを含むサンプルデータ
data = [
    [1, "株式会社ABC",         "東京都港区赤坂1-1-1",     "03-1234-5678"],
    [2, "(株)ABC",             "東京都 港区 赤坂1-1-1",   "03(1234)5678"],
    [3, "ABC株式会社",          "東京都港区赤坂1−1−1",    "03−1234−5678"],
    [4, "株式会社エービーシー",   "東京都港区赤坂1丁目1番1号", "03-1234-5678"],
    [5, "株式会社 ABC",         "東京都港区赤坂 1-1-1",    "03 1234 5678"],
    [6, "株式会社XYZ",        "大阪府大阪市北区梅田2-2",  "06-9876-5432"],
    [7, "(株)XYZ",             "大阪府大阪市北区梅田2-2",  "06(9876)5432"],
    [8, "XYZ株式会社",          "大阪府大阪市 北区 梅田2-2", "06−9876−5432"],
]

for row in data:
    ws.append(row)

# 列幅の調整
ws.column_dimensions["A"].width = 5
ws.column_dimensions["B"].width = 25
ws.column_dimensions["C"].width = 30
ws.column_dimensions["D"].width = 20

wb.save("sample_data.xlsx")
print("sample_data.xlsx を作成しました")
python create_sample.py

sample_data.xlsx を作成しました と表示されれば成功です。
excel-cleansing フォルダ内に Excel ファイルが生成されています。
image.png

この時点で、フォルダの中身は以下のようになっています。

image.png


2. 表記ゆれ修正スクリプトを作ろう

2-1. 全体のコード

エディタの左側エクスプローラーで「新しいファイル」アイコンをクリックし、excel_cleansing.py というファイル名で作成します。
注意:excel-cleansingフォルダ内に作成すること。

image.png

次に、この新しいexcel_cleansing.pyファイルに以下のコードをそのままコピーして貼り付け、保存してください。

excel_cleansing.py
import os
import json
from openai import OpenAI
from dotenv import load_dotenv
import openpyxl

# .envファイルからAPIキーを読み込む
load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))


def normalize_column(values: list[str], column_name: str) -> list[str]:
    """
    生成AIを使って列データの表記ゆれを修正する関数

    Args:
        values: 修正対象の値リスト
        column_name: 列名(会社名、住所など)

    Returns:
        修正後の値リスト
    """

    prompt = f"""
以下は「{column_name}」列のデータ一覧です。
表記ゆれを検出し、統一されたデータに修正してください。

【修正ルール】
- 同じ意味のデータは最も一般的・正式な表記に統一してください
- 会社名の場合: 「株式会社」は前につける形に統一(例: 株式会社ABC)
- 住所の場合: 余分なスペースを除去し、数字は半角に統一してください
- 電話番号の場合: 「03-1234-5678」の形式(半角ハイフン区切り)に統一してください
- 全角英数字は半角に変換してください
- 元のデータの意味や内容は変えないでください

【入力データ】
{json.dumps(values, ensure_ascii=False)}

【出力形式】
修正後のデータをJSON配列で返してください。
入力と同じ要素数・同じ順序で返してください。
JSON配列のみを返し、それ以外のテキストは含めないでください。
"""

    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {
                "role": "system",
                "content": "あなたはデータクレンジングの専門家です。指示に従ってJSON配列のみを返してください。"
            },
            {"role": "user", "content": prompt}
        ],
        temperature=0.0    # 表記統一なので創造性は不要
    )

    result_text = response.choices[0].message.content.strip()

    # JSON文字列の前後にマークダウンのコードブロックがついている場合に除去する
    if result_text.startswith("```"):
        result_text = result_text.split("\n", 1)[1]  # 最初の行を除去
    if result_text.endswith("```"):
        result_text = result_text.rsplit("\n", 1)[0]  # 最後の行を除去

    result = json.loads(result_text)

    return result


def cleanse_excel(input_file: str, output_file: str, target_columns: list[str]):
    """
    Excelファイルの指定列の表記ゆれを修正する関数

    Args:
        input_file: 入力Excelファイルのパス
        output_file: 出力Excelファイルのパス
        target_columns: 修正対象の列名リスト
    """

    wb = openpyxl.load_workbook(input_file)
    ws = wb.active

    # ヘッダー行から列名とインデックスの対応を取得
    headers = {}
    for col_idx, cell in enumerate(ws[1], start=1):
        headers[cell.value] = col_idx

    # 対象列ごとに処理
    for column_name in target_columns:
        if column_name not in headers:
            print(f"警告: 「{column_name}」列が見つかりません。スキップします。")
            continue

        col_idx = headers[column_name]

        # 列のデータを取得(ヘッダー行を除く)
        values = []
        for row in ws.iter_rows(min_row=2, min_col=col_idx, max_col=col_idx):
            cell = row[0]
            values.append(str(cell.value) if cell.value is not None else "")

        if not values:
            continue

        print(f"{column_name}」列を修正中...({len(values)}件)")

        # 生成AIで表記ゆれを修正
        normalized = normalize_column(values, column_name)

        # 修正結果をExcelに書き戻す
        for i, row in enumerate(ws.iter_rows(min_row=2, min_col=col_idx, max_col=col_idx)):
            cell = row[0]
            old_value = str(cell.value) if cell.value is not None else ""
            new_value = normalized[i]

            if old_value != new_value:
                print(f"  修正: {old_value} -> {new_value}")

            cell.value = new_value

    wb.save(output_file)
    print(f"\n{output_file} に保存しました")


def main():
    """メイン処理"""

    print("=" * 50)
    print("Excel 表記ゆれ自動修正ツール")
    print("=" * 50)

    # 設定
    input_file = "sample_data.xlsx"
    output_file = "sample_data_cleaned.xlsx"
    target_columns = ["会社名", "住所", "電話番号"]

    # ファイルの存在確認
    if not os.path.exists(input_file):
        print(f"エラー: {input_file} が見つかりません。")
        print("先に create_sample.py を実行してサンプルデータを作成してください。")
        return

    print(f"\n入力ファイル: {input_file}")
    print(f"出力ファイル: {output_file}")
    print(f"対象列: {', '.join(target_columns)}")
    print()

    # 表記ゆれ修正を実行
    cleanse_excel(input_file, output_file, target_columns)

    print("\n完了しました")


if __name__ == "__main__":
    main()

3. 実行してみよう

インプット

インプットデータは、先ほどコードを使って作成したサンプルファイルの通りです。
中身はこうなっています。
image.png

全体的に表記ゆれがあるので、それを先ほどのコードで整えていくということですね。

アウトプット

コードを実行します。
すると、ターミナルにはこう表示されます。

image.png

最終的に、エクセルファイルは「sample_data_cleaned.xlsx」という名前で別名保存され、画像の通り修正されました!

image.png

最初の時と違って表記ゆれが整理されていますね。

2-2. コードの解説

以下、コードの解説です。

ポイント1: 列単位でAIに渡す

values = []
for row in ws.iter_rows(min_row=2, min_col=col_idx, max_col=col_idx):
    cell = row[0]
    values.append(str(cell.value) if cell.value is not None else "")

normalized = normalize_column(values, column_name)

セル1つずつAIに渡すと API 呼び出し回数が増えてコストがかかります。そこで、列のデータをまとめてリストとして渡すことで、AIが全体を見て統一的な修正を行えるようにしています。

方法 API呼び出し回数 メリット デメリット
セル1つずつ データ件数 x 列数 個別に丁寧な処理 コスト高・低速
列単位でまとめて 列数のみ 低コスト・高速・統一性が高い 大量データには分割が必要

ポイント2: temperature=0.0

temperature=0.0    # 表記統一なので創造性は不要

日報生成のような文章作成では temperature=0.7 程度で多様性を持たせますが、表記ゆれ修正は正確さが最優先です。temperature=0.0 に設定することで、毎回同じ入力に対して同じ出力を返すようになります。

ポイント3: JSON形式で受け取る

prompt = f"""
...
出力形式
修正後のデータをJSON配列で返してください
入力と同じ要素数同じ順序で返してください
JSON配列のみを返しそれ以外のテキストは含めないでください
"""

生成AIの出力をプログラムで処理するには、構造化されたフォーマットで返してもらう必要があります。JSON配列で返すよう指示することで、json.loads() でそのままPythonのリストに変換できます。

ただし、GPT はたまにマークダウンのコードブロック(```json ... ```)で囲んで返すことがあるため、以下のように除去処理を入れています。

if result_text.startswith("```"):
    result_text = result_text.split("\n", 1)[1]
if result_text.endswith("```"):
    result_text = result_text.rsplit("\n", 1)[0]

ポイント4: 修正内容のログ表示

if old_value != new_value:
    print(f"  修正: {old_value} -> {new_value}")

どのデータが修正されたかを表示することで、AIの判断を目視確認できるようにしています。生成AIの出力は必ずしも正しいとは限らないため、特にデータクレンジングのような用途では確認の仕組みが重要です。



4. カスタマイズしてみよう

4-1. 修正ルールを変える

プロンプトの 【修正ルール】 を変えることで、統一ルールを自由にカスタマイズできます。

# 例: 会社名を略称に統一したい場合
"""
- 会社名の場合: 「(株)」の形式に統一(例: (株)ABC)
"""

# 例: 住所の丁目表記を維持したい場合
"""
- 住所の場合: 「1丁目1番1号」の形式はそのまま維持してください
- 「1-1-1」の形式は変換しないでください
"""

4-2. 対象列を変える

main() 関数内の target_columns を変えるだけで、任意の列を修正対象にできます。

# 例: 氏名と部署名だけ修正したい場合
target_columns = ["氏名", "部署名"]

4-3. 大量データへの対応

データが多い場合、一度に全件をAPIに送ると制限に引っかかることがあります。以下のようにバッチ処理を入れると安全です。

def normalize_column_batch(values: list[str], column_name: str, batch_size: int = 50) -> list[str]:
    """大量データをバッチに分割して処理する"""

    all_results = []

    for i in range(0, len(values), batch_size):
        batch = values[i:i + batch_size]
        print(f"  バッチ処理中... {i + 1}{min(i + batch_size, len(values))}件目")
        result = normalize_column(batch, column_name)
        all_results.extend(result)

    return all_results

5. VBA との比較

VBA でも表記ゆれ修正は可能ですが、生成AIを使うアプローチとの違いを整理します。

観点 VBA Python + 生成AI
ルール作成 全パターンを手動で定義する必要がある AIが文脈から判断してくれる
未知のパターン 定義していないパターンには対応できない 初見のパターンにも柔軟に対応
処理速度 高速(ローカル処理) API通信があるため比較的遅い
コスト 無料 API利用料がかかる
精度の保証 ルール通り確実に動く まれに誤変換の可能性がある
導入の手軽さ Excel さえあれば動く Python環境とAPIキーが必要

使い分けの指針: パターンが明確で件数が多いなら VBA、パターンが複雑・不定で判断が必要なら生成AI、というように併用するのがおすすめです。


6. よくあるエラーと対処法

JSON のパースに失敗する

json.JSONDecodeError: Expecting value

→ AIの出力がJSON形式になっていない場合に発生します。プロンプトに「JSON配列のみを返してください」と明記しているか確認してください。それでも発生する場合はリトライ処理の追加を検討しましょう。

修正結果の件数が合わない

→ AIが要素を追加・削除してしまうケースです。normalize_column 関数にチェックを追加すると安全です。

result = json.loads(result_text)

if len(result) != len(values):
    print(f"  警告: 入力 {len(values)}件に対し出力 {len(result)}件。修正をスキップします。")
    return values  # 元のデータをそのまま返す

API の料金が心配

この記事のサンプルデータ(8件 x 3列)を処理した場合の目安です。

モデル 1回あたりのコスト目安
gpt-4o-mini 約 0.01 円以下
gpt-4o 約 0.1 円程度

gpt-4o-mini であれば、数百件のデータを処理しても数円程度です。


まとめ

この記事では、Python と OpenAI API を使って Excel データの表記ゆれを自動修正するツールを作りました。

今回学んだこと

  • openpyxl で Excel ファイルを読み書きする方法
  • 生成AIに構造化データ(JSON)を返させるプロンプトの書き方
  • temperature=0.0 で出力の安定性を確保する手法
  • VBA と生成AIの使い分けの考え方

生成AIに任せる際の注意点

表記ゆれの修正を生成AIに任せるということは、判断をAIに委ねるということです。AIの判断が常に正しいとは限らないため、以下の点に注意してください。

過剰な修正: 「株式会社ABC」と「株式会社エービーシー」が実際には別会社なのに、AIが同じ会社と判断して統一してしまう可能性があります
判断のブレ: temperature=0.0 でもAPIのバージョンアップなどで挙動が変わり、実行するたびに結果が異なることがあります
文脈の見落とし: 「1-1-1」と「1丁目1番1号」のどちらに統一すべきかは会社のルール次第ですが、AIにはその背景がわかりません

だからこそ、だからこそ、本記事のコードに入れた「修正: 旧データ -> 新データ」のターミナル表示が重要です。AIに任せっぱなしにするのではなく、「AIが下書きして、人間が確認する」 という運用を心がけるのが良さそうです。
慣れてきたら楽になるかなと思います。ぜひお試しを!


参考リンク


この記事は「Python x 生成AI 業務自動化シリーズ」の初級編です。
いいねやストックしていただけると励みになります!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?