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によるExcelファイル比較スクリプト

Last updated at Posted at 2025-01-30

概要

 このスクリプトは、Bashスクリプトの中でPythonを実行し、2つのExcelファイルを比較して差分を出力する。具体的には、以下のことを行う:
・第一列(キー列)を基準に、片方のファイルにしかない行をリストアップする。
・キー列が一致する行について、各列の差分をチェックし、違いがある場合にそれを出力する。

スクリプト


#!/bin/bash

if [ "$#" -ne 2 ]; then
    echo "使用方法: compare_excel <file1.xlsx> <file2.xlsx>"
    exit 1
fi

FILE1="$1"
FILE2="$2"

if [ ! -f "$FILE1" ]; then
    echo "エラー: ファイル $FILE1 が見つかりません。"
    exit 1
fi

if [ ! -f "$FILE2" ]; then
    echo "エラー: ファイル $FILE2 が見つかりません。"
    exit 1
fi


python3 <<EOF
import pandas as pd

def compare_excel(file1, file2):
    try:
        print(f"Comparing files: {file1} and {file2}")

        # Excelファイルを読み込む
        df1 = pd.read_excel(file1, dtype=str)
        df2 = pd.read_excel(file2, dtype=str)

        print("DF1:", df1.head(), sep="\n")
        print("DF1:", df1.tail(), sep="\n")
        print("DF2:", df2.head(), sep="\n")
        print("DF2:", df2.tail(), sep="\n")

        # 1列目(キー列)を動的に検出
        key_column = df1.columns[0]
        print(f"キー列: {key_column}")

        # 列ラベルの一致を確認し、共通列のみを使用
        common_columns = df1.columns.intersection(df2.columns)
        if not common_columns.any():
            print("共通する列がありません。比較できません。")
            return

        df1 = df1[common_columns]
        df2 = df2[common_columns]

        # デバッグ: インデックスの確認
        print("インデックス確認: df1インデックス:", df1.index)
        print("インデックス確認: df2インデックス:", df2.index)

        # デバッグ: 比較前のデータを表示
        print(f"比較開始: df1のサイズ: {df1.shape}, df2のサイズ: {df2.shape}")

        # 追加された行
        added_rows = df2[~df2[key_column].isin(df1[key_column])]
        print("\n[file2にのみ存在]")
        if not added_rows.empty:
            print(added_rows)

        # 削除された行
        removed_rows = df1[~df1[key_column].isin(df2[key_column])]
        print("\n[file1にのみ存在)]")
        if not removed_rows.empty:
            print(removed_rows)

        print("\n")

        # セルごとの比較(キー列が一致する行のみ)
        for col in common_columns:
            if col == key_column:
                continue  # キー列は比較しない
            merged = pd.merge(df1[[key_column, col]], df2[[key_column, col]], on=key_column, suffixes=('_file1', '_file2'))
            diff = merged[(merged[f"{col}_file1"] != merged[f"{col}_file2"]) &
                          ~(merged[f"{col}_file1"].isna() & merged[f"{col}_file2"].isna())]
            for _, row in diff.iterrows():
                print(f"'{row[key_column]}', 列 '{col}' の違い: '{row[f'{col}_file1']}' (file1) vs '{row[f'{col}_file2']}' (file2)")

    except Exception as e:
        print(f"エラーが発生しました: {e}")

if __name__ == "__main__":
    # Bashの変数をPythonに渡す
    file1 = "${FILE1}"
    file2 = "${FILE2}"

    compare_excel(file1, file2)
EOF

解説

Excelファイル読み込み

        # Excelファイルを読み込む
        df1 = pd.read_excel(file1, dtype=str)

 pandasのread_execelを用いてファイルを読み込む。dtype=strは全てのデータを文字列として読み込むオプション。

キー列検出

        # 1列目(キー列)を動的に検出
        key_column = df1.columns[0]

1列目をキー列として指定する。

共通列検出

        # 列ラベルの一致を確認し、共通列のみを使用
        common_columns = df1.columns.intersection(df2.columns)
        if not common_columns.any():
            print("共通する列がありません。比較できません。")
            return

 列ラベル同士を比較して両方のデータフレームに共通する列を見つける。共通列がなければ比較できない旨を表示して終了する。

行差分の検出

        added_rows = df2[~df2[key_column].isin(df1[key_column])]

・df2[key_column]: df2データフレームの key_column 列(キー列)の値を取得。
・.isin(df1[key_column]): df2のキー列の各値が df1のキー列に含まれているかどうかをチェック。ブール型を返し、Trueは df1に存在する値、Falseは存在しない値に対応。
・~ (チルダ): 論理否定演算子で、ブール値を反転させる。この場合、df1に存在しない値がTrueとなる。
・df2[...]: ここで、df2の各行について、~df2[key_column].isin(df1[key_column]) の条件を満たす行(Trueになる行)だけを選択して新しいデータフレームを作成する。

つまり、このコードの意味は:
「df2 に含まれるが df1 に含まれていないキー列の行」を added_rows に格納する ということ。これにより、file2 にだけ存在する行(追加された行)を抽出している。

セルの比較

        # セルごとの比較(キー列が一致する行のみ)
        for col in common_columns:
            if col == key_column:
                continue  # キー列は比較しない
            merged = pd.merge(df1[[key_column, col]], df2[[key_column, col]], on=key_column, suffixes=('_file1', '_file2'))
            diff = merged[(merged[f"{col}_file1"] != merged[f"{col}_file2"]) &
                          ~(merged[f"{col}_file1"].isna() & merged[f"{col}_file2"].isna())]
            for _, row in diff.iterrows():
                print(f"'{row[key_column]}', 列 '{col}' の違い: '{row[f'{col}_file1']}' (file1) vs '{row[f'{col}_file2']}' (file2)")

 両方のデータフレームに共通する列について比較する。キー列は比較対象外なのでスキップする。

merged = pd.merge(df1[[key_column, col]], df2[[key_column, col]], on=key_column, suffixes=('_file1', '_file2'))
・pd.merge は df1 と df2 の対応する列(key_columnとcol)を基にマージする。
・on=key_column はキー列をマージの基準にする。
・suffixes=('_file1', '_file2') は同じ名前の列に _file1 や _file2 というサフィックスを付け分けることで、どちらのファイルのデータかを区別する。

diff = merged[(merged[f"{col}_file1"] != merged[f"{col}_file2"]) &
~(merged[f"{col}_file1"].isna() & merged[f"{col}_file2"].isna())]
・file1 と file2 の対応する列(例えばcol)の値が異なる行を抽出。
・!= は不一致のチェック、isna() は NaN(欠損値)のチェック。~ は論理否定。
・&(アンパサンド) は論理積で、両方の条件が成り立つ行を選ぶ。特に、両方がNaNの場合も除外。

・diff.iterrows() で diff データフレームの各行を反復する。_,は本来はindexが入るのだが、使用しないので省略したという書き方
・print 文で、キー列の値と、その列で差異が生じた具体的な値を表示する。file1とfile2の値を比較して、どこに差異があるのかを明確に伝える。

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?