(学習ログ)Python009:複数CSVの結合→集計→ピボットで月×商品を可視化
1. はじめに
-
この記事の目的
複数のCSVファイルを読み込み、行方向の結合、キー結合、派生列の作成を経て、月×商品の売上・数量をgroupbyとピボットテーブルで集計する一連の流れを学びます。 -
この記事の概要
-
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_dateをto_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. エラーと確認のポイント
代表的なエラー文
-
FileNotFoundError: [Errno 2] No such file or directory
- 原因:ファイルパスやフォルダ名の誤り、実行場所の違い。
-
対処:相対パス/絶対パスを見直す。
os.getcwd()でカレントディレクトリ確認。
import os print(os.getcwd()) -
KeyError: '列名'(例:
'item_price'がない)- 原因:ファイルの列名が想定と異なる、結合後に列が欠けた。
-
対処:
df.columnsで列名を確認。結合前に必要列を[[...]]で明示。
-
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" ) -
原因:
-
列の型が数値でないために計算エラー(例:
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_datetime→strftime)で月キーを作り、groupbyとpivot_tableで月×商品の集計表を作れる。 - つまずきやすいFileNotFoundError / KeyError / 型問題への対処と、
shape/info/isna().sum()などの確認メソッドでデータ品質を自己点検できる。
Discussion