🐍

(学習ログ)Python004:複数CSVの結合と必要列の抽出で「分析用の1枚テーブル」を作る

に公開

1. はじめに

  • この記事の目的

    • 複数のCSVファイルを読み込み、縦結合(concat)と横結合(merge)で“分析に使える1枚のテーブル”を作る基本手順を身につけます。
  • この記事の概要

    • pandas.read_csvconcat(明細/トランザクションの結合) → merge(必要なキーで横結合) → 最終確認(head)という流れで解説します。

2. サンプルコード

コード全文

import pandas as pd

# 1) 取引(トランザクション)を2つのCSVから読み込み → 縦結合で1つにする
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)

# 2) 明細(トランザクションの行明細)も同様に2つから読み込み → 縦結合
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)

# 3) 明細に、「取引の基本情報(支払日・顧客ID)」を結合(横結合)
#    ポイント:結合前に使う列だけを抽出([[...]])してデータを“軽く”する
sample_join_data = pd.merge(
    sample_transaction_detail,
    sample_transaction[["transaction_id", "payment_date", "customer_id"]],
    on='transaction_id',
    how="left"
)

# 4) 顧客マスタを結合(顧客属性を付与)
sample_file = pd.read_csv('001_サンプル/sample_file.csv')
sample_join_data = pd.merge(
    sample_join_data,
    sample_file,
    on="customer_id",
    how="left"
)

# 5) 商品マスタを結合(商品名やカテゴリを付与)
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"
)

# 6) 仕上がり確認(先頭5行)
sample_join_data.head()
  • 行ごと、またはブロックごとに簡潔に説明

    1. read_csv ×2 → concat:同じ列構成のファイルを縦に繋いで、全期間・全バッチの取引データを1本化します。
    2. 明細も同様に縦結合:1つの取引に複数行の明細があるケースを想定。
    3. merge(明細 × 取引):キーは transaction_idhow="left" で「明細を基準に、取引の情報(支払日・顧客ID)を付ける」。[["transaction_id","payment_date","customer_id"]] は“必要列だけ”を取り出して効率化。
    4. merge(顧客属性):キーは customer_id。顧客名や会員区分などを付与。
    5. merge(商品属性):キーは item_id。商品名やカテゴリ、単価などを付与。
    6. head():最終テーブルの形を素早く確認。

実行結果例

   transaction_id  detail_id  item_id  quantity payment_date customer_id customer_name membership item_name        category  unit_price
0           T0001       1011     A101         2   2024-12-01      C00123         田中 太郎        Gold     ノートPC  エレクトロニクス       98000
1           T0001       1012     A203         1   2024-12-01      C00123         田中 太郎        Gold   ワイヤレスマウス        周辺機器        3200
2           T0002       1021     B510         3   2024-12-03      C00456         佐藤 花子        Silver    コーヒー豆  食品・飲料         980
3           T0003       1031     A101         1   2024-12-05      C00777         李 健            Regular  ノートPC  エレクトロニクス       98000
4           T0003       1032     C330         2   2024-12-05      C00777         李 健            Regular  ノートPC用バッグ        周辺機器        4200

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

代表的なエラー文

  • FileNotFoundError: [Errno 2] No such file or directory
    → パスが誤り/作業ディレクトリが違う。os.getcwd() で現在地を確認、相対パスなら実在するかを見直す。
  • ParserError: Error tokenizing data
    → 区切り文字や引用符の崩れ。read_csv(..., sep=",", quotechar='"', engine="python") など調整。
  • UnicodeDecodeError: 'utf-8' codec can't decode ...
    → 文字コードがUTF-8でない。read_csv(..., encoding="cp932")(Windows想定)等を試す。
  • KeyError: 'transaction_id'
    → 指定列が存在しない/表記ゆれ。df.columns で列名を確認し、綴り・大文字小文字を揃える。
  • MergeError: No common columns to perform merge on
    on= で指定したキーが両方にない。キー列が両データに存在するか・dtypeが一致するかを確認。
  • DtypeWarning: Columns have mixed types
    → 数値と文字が混在。read_csv(..., dtype={'transaction_id': str}) のように明示指定すると安定。

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

# 形状・列
sample_join_data.shape            # (行数, 列数) 例: (12543, 11)
sample_join_data.columns.tolist() # 列名の確認

# 先頭・末尾・ランダム確認
sample_join_data.head(3)
sample_join_data.tail(3)
sample_join_data.sample(3, random_state=0)

# 欠損と重複
sample_join_data.isna().sum()     # 列ごとの欠損数を確認
sample_join_data.duplicated().sum()  # 完全重複行の件数

# キーの粒度検証(中級者向け)
# 取引テーブル:transaction_id はユニークであるべき ⇒ True ならOK
sample_transaction['transaction_id'].nunique() == len(sample_transaction)

# merge検証(期待する関係を指定)
pd.merge(
    sample_transaction_detail,
    sample_transaction[['transaction_id']],
    on='transaction_id',
    how='left',
    validate='many_to_one'  # 明細→取引 は多対一を期待
)

# 結合結果のヒット状況を可視化(どちらにマッチしたか)
check = pd.merge(
    sample_transaction_detail,
    sample_transaction[['transaction_id']],
    on='transaction_id',
    how='left',
    indicator=True
)
check['_merge'].value_counts()    # 'both','left_only','right_only' の件数

補足([[...]] の理由)
sample_transaction[["transaction_id", "payment_date", "customer_id"]] のように 二重角括弧 で列名リストを指定すると、

  • “必要な列だけ”を取り出した新しいDataFrameを作れる(=無駄列を持ち込まない)。
  • メモリ効率・可読性が上がり、結合時の列名衝突のリスクも下がる。
  • 一重角括弧(['col'])はSeriesになりがち。結合の相手に渡すのはDataFrameが安全。

4. まとめ

本記事で理解できるようになったこと(3点)

  • 縦結合pd.concat)と横結合pd.merge)を組み合わせて、分析用の“1枚テーブル”を作る基本フロー。
  • how='left'on='...[[列リスト]] の使いどころ(基準テーブルを決め、必要列だけを持ち込む)。
  • 品質確認の勘所:shape/head/isna/duplicatedvalidateindicator=True を使った結合検証の実践。

小さなコツ:結合のたびに「基準はどっち?」「キーの関係は1対1?多対1?」「本当に必要な列だけを持ち込んだか?」を口癖にすると、実務での事故(重複・欠損・誤集計)が激減します。

Discussion