🐍

(学習ログ)Python007:複数CSVを読み込み→縦結合→主キーで結合→集計の基本

に公開

1. はじめに

  • この記事の目的

    • 複数のCSVファイルを読み込み、concatで縦に結合し、mergeで主キー結合し、最終的に数値列の生成・基本統計・欠損確認まで行う「実務の最小ワークフロー」を身につけます。
  • この記事の概要

    • コード全体を提示し、処理ブロックごとに「何をしているか」を簡潔に説明します。

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.isnull().sum()
sample_join_data.describe()
print(sample_join_data["payment_date"].min())
print(sample_join_data["payment_date"].max())

ブロックごとの解説(要点だけ)

  • import pandas as pd

    • データ分析の定番ライブラリpandasを読み込み。
  • pd.read_csv(...) × 5

    • 取引(transaction)・注文明細(transaction_detail)・顧客ファイル・商品マスタをそれぞれ読み込み。
    • ポイント:実務では列名・文字コード(encoding='utf-8' など)・型(dtype=)・日付(parse_dates=)の指定が安定運用に効きます。
  • pd.concat([df1, df2], ignore_index=True) × 2

    • 月次などに分かれたCSVを「同じ列構造」で縦結合。ignore_index=Trueで連番に振り直し。
  • sample_transaction[["transaction_id", "payment_date", "customer_id"]]

    • 不要列を落とし、結合に必要な列だけを選択。メモリ節約&思わぬ重複列の混入を防ぎます。
  • pd.merge(..., on='transaction_id', how='left')

    • 注文明細に対して、取引ヘッダ側の「支払日・顧客ID」を左外部結合。明細が主、ヘッダを付け足すイメージ。
  • pd.merge(..., on='customer_id', how='left')

    • 顧客属性(例:顧客名・会員区分など)を付与。
  • pd.merge(..., on='item_id', how='left')

    • 商品マスタ(例:商品名・単価)を付与。
  • sample_join_data["price"] = quantity * item_price

    • 明細行の金額を計算。算出列の基本パターン。
  • isnull().sum()

    • 列ごとの欠損数を一括確認。結合漏れ・データ欠落の早期発見に必須。
  • describe()

    • 数値列の要約統計(件数・平均・標準偏差・四分位など)。異常値の目安に。
  • print(payment_date.min()/max())

    • 期間の下限・上限を確認。レポート対象期間の妥当性チェックに便利。
    • payment_dateが文字列型だと「辞書順」比較になります。日付として扱うには後述の「中級Tips」を参照。

実行結果例

実際のファイル内容に依存しますが、再現の目安としてご覧ください。

欠損数の例(isnull().sum()

transaction_id      0
item_id             0
quantity            0
payment_date        0
customer_id         0
customer_name       5
membership_rank     5
item_name           0
item_price          0
price               0
dtype: int64
  • 顧客マスタに存在しないIDが少数混ざり、customer_name 等が欠損になっている想定。

要約統計の例(describe() 抜粋)

          quantity    item_price        price
count  1200.000000   1200.000000  1200.000000
mean      1.42           980.50      1392.31
std       0.68           320.10       910.22
min       1.00           120.00       120.00
25%       1.00           800.00       800.00
50%       1.00          1000.00      1000.00
75%       2.00          1200.00      2000.00
max       5.00          2980.00      8940.00

期間チェック(min()/max()

2024-01-01
2024-03-31
  • ※この出力はpayment_date日付型であることを前提にしています。もし文字列のままなら "2024-01-01""2024-12-9" のように辞書順比較になる点に注意。

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

代表的なエラー文(原因と対処)

  • FileNotFoundError: [Errno 2] No such file or directory: '...csv'

    • 原因:パスやファイル名の誤り。作業ディレクトリが想定と違う。
    • 対処:相対パスの基準(os.getcwd()で確認)を見直す/絶対パスで指定/Pathを使って組み立てる。
  • KeyError: 'transaction_id'(または他の列名)

    • 原因:CSVの列名が想定と不一致、前処理で列が落ちた、スペル・大文字小文字の違い。
    • 対処df.columnsで列名を確認、前段のusecols=rename()を活用。
  • ValueError: You are trying to merge on object and int64 columns

    • 原因:結合キーの型不一致(例:片方が文字列、もう片方が整数)。
    • 対処astype(str) などで結合前に型を合わせる。
  • ParserError: Error tokenizing data

    • 原因:CSVの区切りや引用符が乱れている。
    • 対処sep=','quotechar='"' を明示、問題行の特定には on_bad_lines='skip'(検証目的に限定)も。
  • DtypeWarning: Columns (X) have mixed types

    • 原因:同じ列に数値と文字列が混在。
    • 対処dtype= を指定、読み込み後に to_numeric(errors='coerce') で揃える。

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

1) 形と列名

sample_join_data.shape
# 例: (1200, 10)

list(sample_join_data.columns)
# 例: ['transaction_id','item_id','quantity','payment_date','customer_id',
#      'customer_name','membership_rank','item_name','item_price','price']

2) 先頭・末尾の確認

sample_join_data.head(3)
sample_join_data.tail(3)

3) 型の確認と修正(重要)

sample_join_data.dtypes
# payment_date    object  ← 文字列の可能性

# 日付に直す(推奨)
sample_join_data['payment_date'] = pd.to_datetime(sample_join_data['payment_date'], errors='coerce')

4) 結合キーの品質確認

# 重複チェック(主キー想定の列に)
sample_transaction['transaction_id'].duplicated().sum()
# 例: 0(0なら一意)

5) 結合漏れの特定

# どの顧客がマッチしなかったか
unmatched = sample_join_data[sample_join_data['customer_name'].isna()][['customer_id']].drop_duplicates()
print(unmatched.head())

6) 読み込みの安定化(中級Tips)

# 日付・型・必要列を安定指定して読み込む(例)
sample_transaction1 = pd.read_csv(
    '001_サンプル/sample_transaction_data1.csv',
    usecols=['transaction_id','payment_date','customer_id'],
    dtype={'transaction_id':'string','customer_id':'string'},
    parse_dates=['payment_date']
)

4. まとめ

  • 縦結合(concat)と横結合(merge)の基本パターンを押さえ、必要列だけを選んで安全に結合できるようになりました。
  • 品質確認の要点(isnull().sum(), describe(), 期間のmin/max を通じて、早期に異常を見つける流れを学びました。
  • 実務でハマりやすい論点(パス・列名・型不一致・日付型) への具体的な対処(dtype, parse_dates, astype, to_datetime)を理解しました。

Discussion