🐍

(学習ログ)Python009:複数CSVの結合→集計→ピボットで月×商品を可視化

に公開

1. はじめに

  • この記事の目的
    複数のCSVファイルを読み込み、行方向の結合、キー結合、派生列の作成を経て、月×商品の売上・数量をgroupbyピボットテーブルで集計する一連の流れを学びます。

  • この記事の概要

    1. read_csvで読み込み → 2) concatで縦結合 → 3) mergeで横結合 → 4) 金額・月などの列を作成 → 5) groupbyで確認 → 6) pivot_tableで表形式に整形、という順で解説します。

2. サンプルコード

コード全文

import pandas as pd
sample_transaction1 = pd.read_csv('001_サンプル/sample_transaction_data1.csv')
sample_transaction2 = pd.read_csv('001_サンプル/sample_transaction_data2.csv')
sample_transaction = pd.concat([sample_transaction1, sample_transaction2], ignore_index=True)
sample_transaction_detail1 = pd.read_csv('001_サンプル/sample_transaction_detail1.csv')
sample_transaction_detail2 = pd.read_csv('001_サンプル/sample_transaction_detail2.csv')
sample_transaction_detail = pd.concat([sample_transaction_detail1, sample_transaction_detail2], ignore_index=True)
sample_join_data = pd.merge(sample_transaction_detail, sample_transaction[["transaction_id", "payment_date", "customer_id"]], on='transaction_id', how="left")
sample_file = pd.read_csv('001_サンプル/sample_file.csv')
sample_join_data = pd.merge(sample_join_data, sample_file, on="customer_id", how="left")
sample_item_list = pd.read_csv('001_サンプル/sample_item_list.csv')
sample_join_data = pd.merge(sample_join_data, sample_item_list, on="item_id", how="left")
sample_join_data["price"] = sample_join_data["quantity"] * sample_join_data["item_price"]
sample_join_data["payment_date"] = pd.to_datetime(sample_join_data["payment_date"])
sample_join_data["payment_month"] = sample_join_data["payment_date"].dt.strftime("%Y%m")
sample_join_data.groupby(["payment_month", "item_name"])[["price", "quantity"]].sum()
pd.pivot_table(sample_join_data, index='item_name', columns='payment_month', values=['price', 'quantity'], aggfunc='sum')

行・ブロックごとの要点だけ解説

  • import pandas as pd
    ライブラリ読み込み。以降は pd.関数名 で使用。

  • pd.read_csv(...1.csv / ...2.csv) ×2
    取引(ヘッダー:transaction_id, payment_date, customer_id など)をファイルごとに読み込み。

  • pd.concat([...], ignore_index=True)(取引)
    2つの同じ列構成のDataFrameを縦に連結ignore_index=Trueで新しい連番インデックスに。

  • pd.read_csv(...detail1.csv / ...detail2.csv)concat(明細)
    明細(transaction_id, item_id, quantity など)も同様に縦結合

  • pd.merge(detail, transaction[[...]], on='transaction_id', how='left')
    明細の各行に、親の取引情報(payment_date, customer_id)を左外部結合で付与。
    [[...]]複数列をDataFrameとして選ぶため(一重['col']はSeriesになりがち)。

  • pd.read_csv('.../sample_file.csv')merge(..., on='customer_id')
    顧客マスタ(例:customer_id, customer_name, prefectureなど)と横結合。

  • pd.read_csv('.../sample_item_list.csv')merge(..., on='item_id')
    商品マスタ(item_id, item_name, item_priceなど)も横結合。

  • sample_join_data["price"] = quantity * item_price
    明細単位の金額列を新規作成。

  • payment_dateto_datetime
    文字列→日付型に変換。後続の月抽出のために必須。

  • payment_month = payment_date.dt.strftime("%Y%m")
    YYYYMM形式の月キーを作成(例:202501)。

  • groupby(["payment_month","item_name"])[["price","quantity"]].sum()
    月×商品で合計をざっと確認する中間集計

  • pd.pivot_table(..., index='item_name', columns='payment_month', values=['price','quantity'], aggfunc='sum')
    行=商品、列=月、セル=合計(price / quantity)のピボットテーブルを生成。

実行結果例

中間のgroupby結果(抜粋)

payment_month  item_name
202501         Apple        price       12,000
                             quantity         8
               Banana       price        8,400
                             quantity         7
202502         Apple        price        9,000
                             quantity         6
               Orange       price        5,600
                             quantity         4
Name: sum, dtype: int64

最終のピボットテーブル(抜粋・見やすさのためカンマ区切り)

payment_month      202501                202502
                  price  quantity       price  quantity
item_name
Apple             12,000         8       9,000         6
Banana             8,400         7           0         0
Orange                 0         0       5,600         4

※ その月に販売がない場合は0(実際はNaN)。ゼロ埋めしたい場合は最後に.fillna(0)を追加すると良いです。

pt = pd.pivot_table(..., aggfunc='sum').fillna(0)

3. エラーと確認のポイント

代表的なエラー文

  1. FileNotFoundError: [Errno 2] No such file or directory

    • 原因:ファイルパスやフォルダ名の誤り、実行場所の違い。
    • 対処:相対パス/絶対パスを見直す。os.getcwd()でカレントディレクトリ確認。
    import os
    print(os.getcwd())
    
  2. KeyError: '列名'(例:'item_price'がない)

    • 原因:ファイルの列名が想定と異なる、結合後に列が欠けた。
    • 対処df.columnsで列名を確認。結合前に必要列を[[...]]で明示。
  3. ValueError: Unknown string format / to_datetime失敗

    • 原因payment_dateに不正な日付文字列が混在。
    • 対処errors='coerce'でNaTにし、後で欠損処理。
    sample_join_data["payment_date"] = pd.to_datetime(
        sample_join_data["payment_date"], errors="coerce"
    )
    
  4. 列の型が数値でないために計算エラー(例:quantityが文字列)

    • 対処:明示的に型変換。
    sample_join_data["quantity"] = pd.to_numeric(sample_join_data["quantity"], errors="coerce").fillna(0)
    sample_join_data["item_price"] = pd.to_numeric(sample_join_data["item_price"], errors="coerce").fillna(0)
    

よく使う確認メソッドや出力例

# レコード数・列数を確認
sample_join_data.shape        # 例: (1200, 12)

# 先頭をざっと確認
sample_join_data.head(3)

# 列名・型・欠損を俯瞰
sample_join_data.info()

# 欠損の個数を列ごとに確認
sample_join_data.isna().sum()

# 重複の有無(例:transaction_id×item_idで重複していないか)
sample_join_data.duplicated(subset=["transaction_id", "item_id"]).sum()

# 列名一覧
sample_join_data.columns.tolist()

# 型の一覧
sample_join_data.dtypes

補足(なぜ[[...]]を使うの?)
sample_transaction[["transaction_id", "payment_date", "customer_id"]]二重角括弧は、複数列をDataFrameとして取り出すためです。
一重角括弧(例:sample_transaction['payment_date'])はSeriesになり、mergeの右辺に渡すと列落ちや意図しない結合になることがあります。結合の相手にはDataFrameを渡すのが安全です。


4. まとめ

  • 縦結合(concat)と横結合(merge)の役割が分かり、明細×マスタの典型的な結合手順を再現できる。
  • 日付処理(to_datetimestrftimeで月キーを作り、groupbypivot_table で月×商品の集計表を作れる。
  • つまずきやすいFileNotFoundError / KeyError / 型問題への対処と、shape / info / isna().sum() などの確認メソッドでデータ品質を自己点検できる。

Discussion