🐍

(学習ログ)Python024:複数テーブルの結合と顧客データ集計分析

に公開

1. はじめに

本記事では、pandasを使った実務的なデータ分析の基本パターンを学びます。

複数のCSVファイルを読み込み、それらを結合して集計・抽出を行う一連の流れを解説します。顧客マスター、クラスマスター、キャンペーンマスターなど、実務でよく見る複数テーブルの扱い方と、日付条件での絞り込み、グループ集計の実践方法を習得できます。

2. サンプルコード

コード全文

import pandas as pd

# データ読み込み
sample_usagelog = pd.read_csv('003_サンプル/usage_log.csv')
sample_customer_master = pd.read_csv('003_サンプル/customer_master.csv')
sample_class_master = pd.read_csv('003_サンプル/class_master.csv')
sample_campaign_master = pd.read_csv('003_サンプル/campaign_master.csv')

# テーブル結合:顧客マスター + クラスマスター
sample_customer_join = pd.merge(sample_customer_master, sample_class_master, on="class", how="left")

# さらにキャンペーンマスターを結合
sample_customer_join = pd.merge(sample_customer_join, sample_campaign_master, on="campaign_id", how="left")

# 各属性での顧客数集計
sample_customer_join.groupby("class_name").count()["customer_id"]
sample_customer_join.groupby("campaign_name").count()["customer_id"]
sample_customer_join.groupby("gender").count()["customer_id"]
sample_customer_join.groupby("is_deleted").count()["customer_id"]

# 日付型への変換と条件抽出
sample_customer_join["start_date"] = pd.to_datetime(sample_customer_join["start_date"])

# 2018年4月1日より後に開始した顧客を抽出
sample_customer_start = sample_customer_join.loc[sample_customer_join["start_date"]>pd.to_datetime("20180401")]
print(len(sample_customer_start))

# 終了日での絞り込み:2019年3月31日以降または終了日がNULL
sample_customer_join["end_date"] = pd.to_datetime(sample_customer_join["end_date"])
sample_customer_newer = sample_customer_join.loc[(sample_customer_join["end_date"]>=pd.to_datetime("20190331"))|(sample_customer_join["end_date"]).isna()]
print(len(sample_customer_newer))

# 絞り込み後のデータ確認
sample_customer_newer["end_date"].unique()
sample_customer_newer.groupby("class_name").count()["customer_id"]
sample_customer_newer.groupby("campaign_name").count()["customer_id"]
sample_customer_newer.groupby("gender").count()["customer_id"]

コード解説

ブロック1:データの読み込み

sample_usagelog = pd.read_csv('003_サンプル/usage_log.csv')
sample_customer_master = pd.read_csv('003_サンプル/customer_master.csv')
sample_class_master = pd.read_csv('003_サンプル/class_master.csv')
sample_campaign_master = pd.read_csv('003_サンプル/campaign_master.csv')

何をしているか:4つのCSVファイルをそれぞれDataFrameとして読み込んでいます。

なぜそうするか:実務では顧客情報、会員ランク、キャンペーン情報などが別々のテーブルで管理されています。それぞれを個別に読み込むことで、後で必要な情報同士を結合できます。

初心者ポイント:ファイルパスは相対パスでも絶対パスでも指定可能です。ファイルが見つからない場合はFileNotFoundErrorが発生するので、ファイルの場所を確認しましょう。

ブロック2:複数テーブルの結合

sample_customer_join = pd.merge(sample_customer_master, sample_class_master, on="class", how="left")
sample_customer_join = pd.merge(sample_customer_join, sample_campaign_master, on="campaign_id", how="left")

何をしているか:pd.merge()で複数のDataFrameを順次結合しています。

なぜそうするか:顧客マスターにはclass列とcampaign_id列しかないため、それぞれのマスターテーブルと結合することで、クラス名やキャンペーン名などの詳細情報を取得できます。how="left"は左側(顧客マスター)の全レコードを保持する左結合です。

初心者ポイント:onパラメータには結合キーとなる列名を指定します。両テーブルに同じ名前の列が存在する必要があります。存在しない場合はマージできません。

ブロック3:属性別の集計

sample_customer_join.groupby("class_name").count()["customer_id"]
sample_customer_join.groupby("campaign_name").count()["customer_id"]
sample_customer_join.groupby("gender").count()["customer_id"]
sample_customer_join.groupby("is_deleted").count()["customer_id"]

何をしているか:クラス名、キャンペーン名、性別、削除フラグごとに顧客数をカウントしています。

なぜそうするか:データの全体像を把握するための基本的な集計です。各属性の分布を確認することで、データの偏りや特徴を理解できます。["customer_id"]で特定の列のみを表示することで、見やすい結果を得られます。

ブロック4:日付型変換と期間による抽出

sample_customer_join["start_date"] = pd.to_datetime(sample_customer_join["start_date"])
sample_customer_start = sample_customer_join.loc[sample_customer_join["start_date"]>pd.to_datetime("20180401")]
print(len(sample_customer_start))

何をしているか:start_date列を文字列から日付型に変換し、2018年4月1日より後に開始した顧客を抽出しています。

なぜそうするか:CSVから読み込んだ日付は文字列型として扱われます。日付型に変換することで、大小比較や期間計算が正確に行えます。特定期間のデータ抽出は分析の基本操作です。

初心者ポイント:pd.to_datetime()は様々な日付形式を自動認識します。"20180401"や"2018-04-01"など、多くの形式に対応しています。

ブロック5:複合条件での抽出と再集計

sample_customer_join["end_date"] = pd.to_datetime(sample_customer_join["end_date"])
sample_customer_newer = sample_customer_join.loc[(sample_customer_join["end_date"]>=pd.to_datetime("20190331"))|(sample_customer_join["end_date"]).isna()]
print(len(sample_customer_newer))

sample_customer_newer.groupby("class_name").count()["customer_id"]
sample_customer_newer.groupby("campaign_name").count()["customer_id"]
sample_customer_newer.groupby("gender").count()["customer_id"]

何をしているか:終了日が2019年3月31日以降、またはNULL(未終了)の顧客を抽出し、再度属性別に集計しています。

なぜそうするか:アクティブな顧客や継続中の顧客を分析するための典型的な処理です。|(OR演算子)で複数条件を組み合わせ、.isna()で欠損値を判定します。抽出後の集計で、条件に合う顧客の属性分布を確認できます。

初心者ポイント:複数条件を使う場合、各条件を()で囲む必要があります。囲まないと演算子の優先順位でエラーが発生します。

実行結果例

クラス名ごとの顧客数(全体)

class_name
ゴールド    250
シルバー    380
ブロンズ    420
レギュラー  650
Name: customer_id, dtype: int64

キャンペーン名ごとの顧客数(全体)

campaign_name
春のキャンペーン    420
夏のキャンペーン    380
秋のキャンペーン    320
初回登録特典       580
Name: customer_id, dtype: int64

2018年4月1日以降に開始した顧客数

542

2019年3月31日以降も継続中の顧客数

687

絞り込み後のクラス別顧客数

class_name
ゴールド    198
シルバー    245
ブロンズ    156
レギュラー  88
Name: customer_id, dtype: int64

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

代表的なエラー

エラー1:FileNotFoundError

FileNotFoundError: [Errno 2] No such file or directory: '003_サンプル/usage_log.csv'

原因:指定したファイルパスにファイルが存在しません。

対処法:カレントディレクトリを確認し、ファイルの場所を正しく指定します。os.getcwd()で現在のディレクトリを確認できます。

エラー2:KeyError

KeyError: 'class'

原因:結合キーに指定した列名がDataFrameに存在しません。

対処法:df.columnsで列名一覧を確認し、正しい列名を使用します。スペースや大文字小文字の違いに注意しましょう。

エラー3:TypeError(日付比較時)

TypeError: '>' not supported between instances of 'str' and 'Timestamp'

原因:文字列型の日付とTimestamp型を比較しようとしています。

対処法:pd.to_datetime()で文字列を日付型に変換してから比較します。

よく使う確認メソッド

メソッド1:データ型の確認

sample_customer_join.dtypes

出力例:

customer_id       int64
class            object
start_date       object
gender           object
campaign_id       int64
dtype: object

データ型を確認することで、日付型への変換が必要かどうか判断できます。

メソッド2:欠損値の確認

sample_customer_join.isnull().sum()

出力例:

customer_id       0
class_name        0
end_date        243
gender            0
campaign_name     5
dtype: int64

各列の欠損値数を確認できます。NULLが多い列は注意が必要です。

メソッド3:データの先頭確認

sample_customer_join.head(3)

出力例:

   customer_id  class  start_date  gender  class_name  campaign_name
0         1001  gold  2018-05-12    male     ゴールド      春のキャンペーン
1         1002  silv  2017-11-23  female    シルバー      初回登録特典
2         1003  bron  2019-01-08    male    ブロンズ      冬のキャンペーン

結合後のデータ構造を視覚的に確認できます。

メソッド4:ユニーク値の確認

sample_customer_join["class_name"].unique()

出力例:

array(['ゴールド', 'シルバー', 'ブロンズ', 'レギュラー'], dtype=object)

カテゴリ列の種類を把握し、集計結果の妥当性を確認できます。

4. まとめ

  • 複数CSVファイルの読み込みと結合:pd.merge()を使った左結合の基本パターンと、段階的な結合方法
  • groupbyによる集計分析:属性ごとの件数集計で、データ全体の分布や特徴を把握する手法
  • 日付型への変換と条件抽出:pd.to_datetime()での型変換と、日付条件や複合条件での絞り込み技術
  • 実務的なデータ分析の流れ:読み込み→結合→集計→条件抽出という、実際の業務で頻出する一連の処理パターン

Discussion