404 Not Found

404 Not Found


nginx

【Pandas実践】データアナリシスプロジェクト:ユーザー購買行動の端到端分析

22レッスンにわたるツールと技術を学んだところで、いよいよすべてを組み合わせるときが来ました。本レッスンでは、実世界のデータアナリシスプロジェクトをシミュレーションします。「第1四半期〜第3四半期のユーザー購買行動を分析せよ」というタスクを受け取り、CSVの読み込み、探索、クリーニング、特徴量エンジニアリング、グループ化、可視化から結論導出まで、完全なワークフローを順に進めていきます。実際のデータ分析では、時間の80%はクリーニングに費やされ、分析に使われるのは20%ですが、結論はその20%に完全に依存します。

⚠️ 注意: 以下のコードはローカルのPython環境で実行する必要があります。

1. 学べること



2. プロジェクト背景:ECユーザー購買行動分析

(1) タスク

チャーリーは課題を受け取りました。「当社の第1四半期〜第3四半期のユーザー購買行動を分析してほしい。高価値ユーザー、人気カテゴリ、消費トレンドを特定し、運営に向けた実行可能な提言を示してください。」

(2) 分析ワークフロー

100%
graph TB
    A["1. データ読み込み"] --> B["2. 探索(EDA)"]
    B --> C["3. クリーニングパイプライン"]
    C --> D["4. 特徴量エンジニアリング"]
    D --> E["5. グループ集計"]
    E --> F["6. 可視化レポート"]
    F --> G["7. 結論と提言"]
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。


3. データの読み込みと探索

▶ サンプル:データ読み込みとEDA(難易度 ⭐⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。
PYTHON
import pandas as pd
import numpy as np

# ============================================
# ステップ1〜2:読み込みと探索
# ============================================

# ECデータのシミュレーション(実際のプロジェクトでは pd.read_csv を使用)
np.random.seed(42)
n = 2000
users = pd.DataFrame({
    'user_id': range(1, n + 1),
    'name': [f'User_{i:04d}' for i in range(1, n + 1)],
    'age': np.random.randint(18, 70, n),
    'gender': np.random.choice(['M', 'F'], n),
    'city': np.random.choice(['NYC', 'LA', 'Chicago', 'Houston', 'Phoenix'], n),
    'join_date': pd.to_datetime(np.random.choice(
        pd.date_range('2023-01-01', '2024-09-30'), n
    ))
})

orders = pd.DataFrame({
    'order_id': [f'O{i:06d}' for i in range(1, 5001)],
    'user_id': np.random.randint(1, n + 1, 5000),
    'product_id': np.random.randint(1, 51, 5000),
    'category': np.random.choice(['Electronics', 'Clothing', 'Home', 'Sports', 'Books'], 5000),
    'amount': np.round(np.random.exponential(100, 5000), 2),
    'quantity': np.random.randint(1, 5, 5000),
    'order_date': pd.to_datetime(np.random.choice(
        pd.date_range('2024-01-01', '2024-09-30'), 5000
    ))
})

# データ品質の問題を注入
orders.loc[np.random.choice(5000, 200, replace=False), 'amount'] = np.nan
orders.loc[np.random.choice(5000, 100, replace=False), 'category'] = np.nan
duplicates = orders.sample(50)
orders = pd.concat([orders, duplicates], ignore_index=True)

# EDA:shape、dtypes、欠損、重複
print(f"ユーザー数: {users.shape}, 注文数: {orders.shape}")
print(f"\n列ごとの欠損数:\n{orders.isnull().sum()}")
print(f"\n重複注文数: {orders.duplicated(subset='order_id').sum()}")
print(f"\n日付範囲: {orders['order_date'].min()} から {orders['order_date'].max()}")
print(f"\n金額の統計量:\n{orders['amount'].describe()}")
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。


4. クリーニングパイプライン

▶ サンプル:pipeクリーニングパイプライン(難易度 ⭐⭐⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。
PYTHON
# ============================================
# ステップ3:クリーニングパイプライン(pipe)
# ============================================

def remove_duplicates(df):
    """重複注文を削除し、最新を残す"""
    before = len(df)
    df = df.drop_duplicates(subset='order_id', keep='last')
    print(f"  削除した重複: {before - len(df)}")
    return df

def fill_missing(df):
    """欠損値を適切な戦略で補完する"""
    df = df.copy()
    # amountはカテゴリごとの中央値で補完
    df['amount'] = df.groupby('category')['amount'].transform(
        lambda x: x.fillna(x.median())
    )
    # categoryは最頻値で補完
    df['category'] = df.fillna({'category': df['category'].mode()[0]})
    return df

def fix_types(df):
    """データ型を修正する"""
    df = df.copy()
    df['order_date'] = pd.to_datetime(df['order_date'])
    df['category'] = df['category'].astype('category')
    return df

def add_derived(df):
    """派生カラムを追加する"""
    df = df.copy()
    df['total_price'] = df['amount'] * df['quantity']
    df['month'] = df['order_date'].dt.to_period('M')
    return df

# パイプラインの実行
clean_orders = (orders
    .pipe(remove_duplicates)
    .pipe(fill_missing)
    .pipe(fix_types)
    .pipe(add_derived)
)
print(f"\nクリーニング後の注文数: {clean_orders.shape}")
print(f"残存欠損数: {clean_orders.isnull().sum().sum()}")
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。


5. 特徴量エンジニアリングと集計

▶ サンプル:RFM特徴量+グループ分析(難易度 ⭐⭐⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。
PYTHON
# ============================================
# ステップ4〜5:特徴量エンジニアリング+集計
# ============================================

# RFM分析(Recency:最新性、Frequency:頻度、Monetary:金額)
reference_date = clean_orders['order_date'].max() + pd.Timedelta(days=1)

rfm = clean_orders.groupby('user_id').agg(
    recency=('order_date', lambda x: (reference_date - x.max()).days),
    frequency=('order_id', 'count'),
    monetary=('total_price', 'sum')
).reset_index()

# RFMスコアリング(四分位ベース)
rfm['R_score'] = pd.qcut(rfm['recency'], 4, labels=[4, 3, 2, 1]).astype(int)
rfm['F_score'] = pd.qcut(rfm['frequency'].rank(method='first'), 4, labels=[1, 2, 3, 4]).astype(int)
rfm['M_score'] = pd.qcut(rfm['monetary'].rank(method='first'), 4, labels=[1, 2, 3, 4]).astype(int)
rfm['RFM_score'] = rfm['R_score'] + rfm['F_score'] + rfm['M_score']

# ユーザーのセグメント分け
rfm['segment'] = pd.cut(rfm['RFM_score'], bins=[0, 5, 8, 10, 12],
                         labels=['At-Risk', 'Average', 'Good', 'Champions'])

print("=== ユーザーセグメント ===")
print(rfm['segment'].value_counts())

# 月次売上トレンド
monthly_rev = clean_orders.groupby('month')['total_price'].sum()
print(f"\n=== 月次売上 ===\n{monthly_rev}")

# カテゴリ分析
cat_stats = clean_orders.groupby('category').agg(
    orders=('order_id', 'count'),
    revenue=('total_price', 'sum'),
    avg_amount=('amount', 'mean')
).sort_values('revenue', ascending=False)
print(f"\n=== カテゴリ統計 ===\n{cat_stats}")
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。


6. 可視化レポートと結論

▶ サンプル:可視化レポート(難易度 ⭐⭐⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。
PYTHON
# ============================================
# ステップ6〜7:可視化と結論
# ============================================

import matplotlib.pyplot as plt

# サマリーレポート(実際のプロットはなし — ローカル実行用のコード)
print("=" * 50)
print("  ECユーザー行動分析レポート")
print("=" * 50)

print(f"\n📊 データセット概要:")
print(f"  ユーザー数: {len(users):,}")
print(f"  注文数: {len(clean_orders):,}")
print(f"  期間: {clean_orders['order_date'].min().date()} から {clean_orders['order_date'].max().date()}")

print(f"\n🏆 上位カテゴリ:")
for i, row in cat_stats.head(3).iterrows():
    print(f"  {i}: ${row['revenue']:,.0f}({row['orders']} 件)")

print(f"\n👤 ユーザーセグメント:")
for seg, count in rfm['segment'].value_counts().items():
    pct = count / len(rfm) * 100
    print(f"  {seg}: {count}({pct:.1f}%)")

print(f"\n📈 月次トレンド:")
monthly_growth = monthly_rev.pct_change().dropna() * 100
print(f"  平均月次成長率: {monthly_growth.mean():.1f}%")
print(f"  ピーク月: {monthly_rev.idxmax()}")
print(f"  最低月: {monthly_rev.idxmin()}")

print(f"\n💡 提言:")
print(f"  1. Championsセグメント({(rfm['segment']=='Champions').sum()} 人)→ VIPプログラム")
print(f"  2. At-Riskセグメント({(rfm['segment']=='At-Risk').sum()} 人)→ 呼び戻しキャンペーン")
print(f"  3. Electronicsが最多カテゴリ → 品揃えを拡充")
print(f"  4. Fスコアの高いユーザーにクロスセルを集中")
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。


7. データ検証と品質レポート

▶ サンプル:データ検証と品質レポート(難易度 ⭐⭐)

TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。
PYTHON
# ============================================
# ステップ:データ検証と品質レポート
# 欠損率/重複率/外れ値比率を算出し、
# 品質レポートを生成する
# ============================================

# 1. 欠損率の分析
missing_count = orders.isnull().sum()
missing_rate = (missing_count / len(orders) * 100).round(2)
print("=== 欠損率レポート ===")
for col in missing_count[missing_count > 0].index:
    print(f"  {col}: {missing_count[col]} 行欠損({missing_rate[col]}%)")

# 2. 重複率の分析
dup_count = orders.duplicated(subset='order_id').sum()
dup_rate = dup_count / len(orders) * 100
print(f"\n=== 重複率レポート ===")
print(f"  重複注文: {dup_count}({dup_rate:.2f}%)")

# 3. 外れ値検出(金額が高すぎる、または低すぎるもの)
q1 = orders['amount'].quantile(0.25)
q3 = orders['amount'].quantile(0.75)
iqr = q3 - q1
lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr
outliers = orders[(orders['amount'] < lower_bound) | (orders['amount'] > upper_bound)]
outlier_rate = len(outliers) / len(orders) * 100
print(f"\n=== 外れ値レポート ===")
print(f"  金額の外れ値: {len(outliers)} 行({outlier_rate:.2f}%)")
print(f"  正常範囲: ${lower_bound:.2f} 〜 ${upper_bound:.2f}")

# 4. データ品質スコアの総合評価
quality_score = 100 - (missing_rate.sum() + dup_rate + outlier_rate) / 3
print(f"\n=== データ品質スコア: {quality_score:.1f}/100 ===")
print(f"  {'✅ 品質良好' if quality_score > 90 else '⚠️ 要注意'}")
TEXT
> 出力: ローカルのPython環境(pandas 2.x)で実行してください。Pistonサーバーにはpandasがプリインストールされていません。ローカルにインストール(`pip install pandas`)してから順に進めてください。実際の値はpandasのバージョンにより若干異なる場合があります。

❓ よくある質問

Q 分析はどこから始めるべきですか?
A EDA(探索的データ分析)から始めてください。読み込み後は、まずshape/dtypes/missing/describeを確認し、データに対する直感を養います。すぐにモデリングやプロットに飛びつかないでください。分析上の問題の80%はEDAの段階で発見できます(欠損値、外れ値、型の誤り)。質の高いEDAが分析の質を決定します。
Q どの程度きれいにすれば十分ですか?
A データが「もはや結論に影響しなくなる」までクリーニングしてください。重要なフィールド(ID、金額、日付)は完全にきれいである必要があり、副次的なフィールドは軽微な欠損を許容できます。目安として、主要カラムの欠損は0%、非主要カラムは5%未満です。クリーニングは完璧を目指すものではなく、ノイズを取り除くものです。
Q 特徴量エンジニアリングには何が含まれますか?
A 分析のために生のデータから有用なカラムを導出することです。一般的な例として、時間特徴量(月/四半期/曜日)、集計特徴量(RFM)、比率特徴量(利益率)、カテゴリ特徴量(価格帯)などがあります。特徴量エンジニアリングとは「ビジネス知識から情報を生み出すこと」です。優れた特徴量は複雑なモデルよりも価値があります。
Q 分析結果はどのように検証しますか?
A 3段階の検証を行います。(1) 数値の整合性(総売上=カテゴリ合計=月合計);(2) 論理的な妥当性(プロモーションがない限り月次成長率が200%を超えることはないはず);(3) 交差検証(同じ指標を異なる方法で算出し、一致することを確認)。いずれかの段階で失敗したら、原因を遡って追跡してください。
Q レポートはどのように構成すべきですか?
A 構成は、結論を先に、その後に裏付けデータ、そして提言の順にします。形式としては、エグゼクティブサマリー(1段落)、主要な発見(データ付きで3〜5項目)、詳細分析(チャート+解釈)、提言(実行可能なもの)です。「データの垂れ流し」は避けてください。すべてのチャートに要点を持たせ、すべての要点をデータで裏付けます。
Q RFMとは何ですか?
A Recency(最終購入からの日数)、Frequency(購入回数)、Monetary(総支払額)のことで、ユーザー価値を測る3つの次元です。Rが低く+Fが高く+Mが高い=Champions(最も価値が高い);Rが高く+Fが低く+Mが低い=At-Risk(離脱寸前)となります。RFMは最も古典的かつ実用的なユーザーセグメンテーション手法です。
Q pipeの利点は何ですか?
A pipeは複数ステップのクリーニングを、上から下へ読めるパイプラインに変えます。各関数は単一の責任を持ち、テスト可能で再利用可能です。f3(f2(f1(df))) のようなネスト呼び出しや、df = df... のような繰り返しの再代入よりも明確です。クリーニングのステップが多いほど、pipeの真価が発揮されます。

📖 まとめ


📝 練習問題

  1. 基礎(難易度 ⭐):シミュレーションしたECデータを読み込み、EDA(shape/missing/describe)を完了して、データ品質に関する発見を3つ書き出してください。
  2. 応用(難易度 ⭐⭐):3ステップのpipeクリーニングパイプライン(重複排除、補完、型修正)を構築し、クリーニング後に欠損=0、重複=0であることを検証してください。
  3. チャレンジ(難易度 ⭐⭐⭐):端到端の完全な分析を完成させてください。読み込み、pipeクリーニング、RFM特徴量、セグメント分類、月次/カテゴリ集計を行い、結論と提言のレポートを出力してください。

← 前へ:出力のスタイリング · 次へ:プロジェクト - 時系列 →

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%