🐍

(学習ログ)Python008:複数CSVを結合して月次列を作る基本ワークフロー

に公開

1. はじめに

  • この記事の目的
    複数のCSVファイルを読み込み、縦結合・横結合(JOIN)し、金額列の計算や日付の整形(年月列の作成)までを身につけます。

  • この記事の概要
    pandas.read_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.dtypes
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[["payment_date", "payment_month"]].head()

ブロックごとの解説

  1. import pandas as pd

    • データ加工用ライブラリ pandas を読み込みます。
  2. pd.read_csv(...) ×4

    • 取引(transaction)と明細(transaction_detail)を ファイルごとに読み込み ます。ファイルが2つずつある前提。
  3. pd.concat([...], ignore_index=True) ×2

    • 同じ列構成のデータを縦に結合します。ignore_index=True で新しい連番インデックスを振り直します。
    • sample_transactionsample_transaction_detail が完成。
  4. pd.merge(..., on='transaction_id', how='left')

    • 明細に対して、取引の一部列(transaction_id, payment_date, customer_id)だけ左結合 します。
    • なぜ [[...]] で列指定?
      df[["col1","col2"]]DataFrame(2列以上)を返すため、結合の相手として安全です。df["col"]Series(1列)になりがちで、複数列を渡したい今回は不適切。
  5. pd.read_csv('.../sample_file.csv')merge(..., on="customer_id")

    • 顧客マスタ(例:顧客名・属性など)を 顧客ID で横結合します。
  6. pd.read_csv('.../sample_item_list.csv')merge(..., on="item_id")

    • 商品マスタ(例:商品名・単価など)を 商品ID で横結合します。
  7. sample_join_data["price"] = quantity * item_price

    • 計算列(金額)を追加します。型が数値でないとエラーや不正値になるので注意。
  8. sample_join_data.dtypes

    • 各列のデータ型を確認します(ここでは表示だけ。実務では printinfo() を併用)。
  9. to_datetimedt.strftime("%Y%m")

    • 文字列の payment_date日付型に変換し、YYYYMM 形式の 月次キー列 を作成します。
  10. sample_join_data[["payment_date", "payment_month"]].head()

    • 変換結果を先頭5行だけ確認します。

実行結果例

dtypes の一例

transaction_id             int64
item_id                    int64
quantity                   int64
payment_date      datetime64[ns]   # ← 後で to_datetime 済み
customer_id               string
item_price               float64
customer_name            string
item_name                string
price                     int64
payment_month            string
dtype: object

sample_join_data[["payment_date","payment_month"]].head() の一例

   payment_date payment_month
0    2024-07-01        202407
1    2024-07-15        202407
2    2024-08-03        202408
3    2024-08-03        202408
4    2024-09-20        202409

price の一例

0    1980   # quantity=2, item_price=990.0
1    9900   # quantity=10, item_price=990.0
2    1500   # quantity=3, item_price=500.0
3    3000   # quantity=2, item_price=1500.0
4    2480   # quantity=1, item_price=2480.0
Name: price, dtype: int64

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

代表的なエラー文

  1. FileNotFoundError: [Errno 2] No such file or directory
  • 原因:パスやファイル名の誤り。相対パスの基準が想定と違う。

  • 対処

    import os
    print(os.getcwd())           # 現在の作業ディレクトリ
    os.listdir('001_サンプル')      # フォルダ内のファイル確認
    
    • 必要に応じて絶対パスに変更、Colabなら /content/drive/MyDrive/... を確認。
  1. 文字化け/UnicodeDecodeError
  • 原因:文字コードが合っていない(例:UTF-8想定だが実際はSHIFT-JIS)。

  • 対処

    pd.read_csv('file.csv', encoding='cp932')  # 例: Windows-Excel系
    
  1. ValueError: unknown string formatto_datetime での失敗)
  • 原因:日付文字列の形式が混在・不正値を含む。

  • 対処

    pd.to_datetime(df['payment_date'], errors='coerce', format='%Y-%m-%d')
    # coerce で不正値は NaT に。format を指定して頑健化
    
  1. 結合後に想定外の NaN が大量発生(エラーにならない“事故”)
  • 原因:結合キーの 型不一致(例:片方 int64、もう片方 string)。

  • 確認&対処

    df1['transaction_id'].dtype, df2['transaction_id'].dtype
    df2['transaction_id'] = df2['transaction_id'].astype('int64')  # 片方に寄せる
    
    • 前後で value_counts()nunique() を見て、結合キーが妥当かチェック。
  1. 重複キーによる件数“爆増”(多対多結合)
  • 原因transaction_idcustomer_id が片方または双方で重複。

  • 確認&対処

    sample_transaction_detail['transaction_id'].duplicated().any()  # True/False
    sample_transaction_detail['transaction_id'].value_counts().head()
    # 必要なら明細のユニーク化、または集計してから結合
    
  1. price が思った型にならない / 小数が混じる
  • 原因item_price が float、quantity が string など。

  • 対処

    df['quantity'] = pd.to_numeric(df['quantity'], errors='coerce').fillna(0).astype('int64')
    df['item_price'] = pd.to_numeric(df['item_price'], errors='coerce')
    df['price'] = (df['quantity'] * df['item_price']).round().astype('Int64')  # 必要なら丸め
    

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

# 形と列
sample_join_data.shape              # (行数, 列数) 例: (1250, 12)
sample_join_data.columns.tolist()   # 列名一覧

# データ型・メモリ
sample_join_data.dtypes
sample_join_data.info()             # 欠損や型の俯瞰に便利

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

# 欠損・一意性
sample_join_data.isna().sum().sort_values(ascending=False)
sample_join_data['transaction_id'].nunique()

# キーの重複や結合検証
sample_join_data['transaction_id'].duplicated().any()
sample_join_data.merge(
    sample_transaction[['transaction_id']].drop_duplicates(),
    on='transaction_id', how='left', indicator=True
)['_merge'].value_counts()

列選択の豆知識

  • df["col"]Series(1列)
  • df[["col1","col2"]]DataFrame(複数列)
    結合の相手や複数列の前処理には 後者 を使うのが安全です。

読み込み時に品質を上げる引数(例)

pd.read_csv(
    'file.csv',
    dtype={'customer_id': 'string', 'transaction_id': 'Int64'},
    usecols=['transaction_id', 'payment_date', 'customer_id'],
    parse_dates=['payment_date'],   # 可能なら読み込み時に日付化
    na_values=['', 'NA', 'NULL'],
    encoding='utf-8'                # 必要に応じて 'cp932' など
)

4. まとめ

  • 縦結合(concat)→ 横結合(merge)→ 計算列 → 日付整形 の実務基本フローを一通り実装できるようになった。
  • [[...]] での複数列選択キーの型不一致重複キー といった“ハマり所”を、確認メソッド(dtypes, info, isna, nunique, duplicated)で検証する習慣が持てた。
  • 読み込み時の dtype/usecols/parse_dates/encoding 指定で、後続処理の安定性とパフォーマンスを高めるコツを理解した。

Discussion