🎯 ステップ42: 総合プロジェクト:実データを分析しよう
これまで学んだスキルを総動員して、本格的なデータ分析に挑戦!
ステップ1〜41で学んだすべてのスキルを使って、実践的なデータ分析プロジェクトに挑戦します。「売上データ分析」と「アンケートデータ分析」の2つのプロジェクトを通じて、データ分析の一連の流れを体験しましょう。
📖 このステップで学ぶこと
・データ分析プロジェクトの進め方
・プロジェクト1:売上データ分析
・プロジェクト2:アンケートデータ分析
・分析レポートの作成方法
🌟 1. データ分析プロジェクトの進め方
実際のデータ分析は、決まった5つのステップで進めていきます。この流れを覚えておくと、どんなデータでも分析できるようになります。
📌 データ分析の5ステップ
| ステップ | 内容 | 使う機能 |
| 1. データの読み込み | CSVファイルなどからデータを取得 | pd.read_csv() |
| 2. データの確認 | 形状、型、欠損値などをチェック | head(), info(), describe() |
| 3. データの加工 | クリーニング、変換、集計 | groupby(), pivot_table() |
| 4. データの可視化 | グラフで傾向を把握 | matplotlib, seaborn |
| 5. 結果の解釈 | 分析結果から何が言えるか考える | print()でレポート出力 |
💡 プロジェクトに取り組むコツ
・コードを写すだけでなく、自分なりの分析も追加してみましょう
・データを変えたり、違うグラフを作ったりして、いろいろ試してください
・エラーが出ても大丈夫!エラーメッセージを読んで解決しましょう
💰 2. プロジェクト1:売上データ分析
ある店舗の1年間の売上データを分析します。以下の点を明らかにするのが目標です。
📌 分析の目標
・月別の売上推移はどうなっているか?
・どの商品が一番売れているか?
・季節による売上の違いはあるか?
・今後の改善提案は何か?
Step 1: サンプルデータの作成
まず、分析用のサンプルデータを作成します。実際のプロジェクトではCSVファイルを読み込みますが、ここでは練習用にPythonでデータを生成します。
コード:ライブラリのインポートとデータ準備
# 必要なライブラリをインポート
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 日本語フォントの設定(Google Colab用)
plt.rcParams['font.family'] = 'DejaVu Sans'
# Seabornのスタイル設定
sns.set_style("whitegrid")
# 乱数のシードを固定(同じ結果が再現できるように)
np.random.seed(42)
print("ライブラリの準備完了!")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
np.random.seed(42)
・乱数のシード(種)を固定する
・同じシードを使えば、毎回同じ乱数が生成される
・分析結果を再現できるようにするために重要
次に、1年間365日分の売上データを作成します。
コード:売上データの生成
# 日付の範囲を作成(2024年1月1日から365日間)
dates = pd.date_range('2024-01-01', periods=365, freq='D')
# 商品リスト
products = ['りんご', 'みかん', 'バナナ', 'いちご', 'ぶどう']
# データを格納するリスト
data = []
# 各日付・各商品の売上データを生成
for date in dates:
# 月を取得
month = date.month
# 季節による基本売上の変動
if month in [6, 7, 8]: # 夏
base_sales = 150
elif month in [12, 1, 2]: # 冬
base_sales = 80
else: # 春・秋
base_sales = 100
# 各商品のデータを作成
for product in products:
# 商品ごとの売上係数
if product == 'りんご':
product_base = base_sales * 1.2
elif product == 'みかん':
product_base = base_sales * 1.0
elif product == 'バナナ':
product_base = base_sales * 1.5
elif product == 'いちご':
product_base = base_sales * 0.8
else: # ぶどう
product_base = base_sales * 1.1
# ランダムな変動を追加(±20の範囲)
sales = int(product_base + np.random.normal(0, 20))
sales = max(0, sales) # マイナスにならないように
# データをリストに追加
data.append({
'日付': date,
'商品名': product,
'売上金額': sales * 100 # 1個100円と仮定
})
# DataFrameに変換
df = pd.DataFrame(data)
print("データの準備完了!")
print(f"データ件数: {len(df)}件")
print()
print("最初の10行:")
df.head(10)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
pd.date_range(‘2024-01-01′, periods=365, freq=’D’)
・2024年1月1日から365日分の日付を生成
・freq=’D’は「日単位」を意味する
date.month
・日付から月(1〜12)を取り出す
np.random.normal(0, 20)
・平均0、標準偏差20の正規分布からランダムな数値を生成
・売上に自然な変動を加えるため
max(0, sales)
・salesと0の大きい方を返す
・売上がマイナスにならないようにする
実行結果
データの準備完了!
データ件数: 1825件
(365日 × 5商品 = 1825件)
Step 2: データの確認
分析を始める前に、データの基本情報を確認します。これは分析の第一歩として必ず行う作業です。
コード:データの基本確認
# データの形状を確認
print("=== データの形状 ===")
print(f"行数: {df.shape[0]}, 列数: {df.shape[1]}")
print()
# データ型を確認
print("=== データ型 ===")
print(df.dtypes)
print()
# 基本統計量を確認
print("=== 売上金額の基本統計量 ===")
print(df['売上金額'].describe())
print()
# 欠損値を確認
print("=== 欠損値の確認 ===")
print(df.isnull().sum())
print()
# 商品の種類を確認
print("=== 商品の種類 ===")
print(df['商品名'].unique())
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 確認ポイントの解説
df.shape:データの大きさ(行数、列数)を確認
df.dtypes:各列のデータ型を確認(数値か文字列か)
df[‘列名’].describe():数値データの統計量(平均、標準偏差、最小、最大など)
df.isnull().sum():欠損値(空のセル)の数を確認
df[‘列名’].unique():その列に含まれるユニークな値を確認
実行結果
=== データの形状 ===
行数: 1825, 列数: 3
=== データ型 ===
日付 datetime64[ns]
商品名 object
売上金額 int64
=== 欠損値の確認 ===
日付 0
商品名 0
売上金額 0
→ 欠損値なし、データはきれいな状態です
Step 3: 月別売上の集計
まず、月ごとの売上を集計して、売上の推移を把握します。
コード:月別売上の集計
# 日付から「月」の列を追加
df['月'] = df['日付'].dt.month
# 月別の売上合計を集計
monthly_sales = df.groupby('月')['売上金額'].sum()
print("=== 月別売上合計 ===")
for month, sales in monthly_sales.items():
print(f"{month:2d}月: {sales:>10,}円")
print()
# 月別の売上平均(1日あたり)
monthly_avg = df.groupby('月')['売上金額'].mean()
print("=== 月別平均売上(1日・1商品あたり)===")
for month, avg in monthly_avg.items():
print(f"{month:2d}月: {avg:>8,.0f}円")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
df[‘日付’].dt.month
・datetime型の列から月(1〜12)を抽出
・.dtアクセサを使うとdatetime型の様々な要素を取り出せる
df.groupby(‘月’)[‘売上金額’].sum()
・月でグループ化して、売上金額の合計を計算
f”{month:2d}”
・2桁で表示(1月なら「 1」、12月なら「12」)
f”{sales:>10,}”
・10桁で右寄せ、3桁ごとにカンマ区切り
Step 4: 商品別売上の集計
コード:商品別売上ランキング
# 商品別の売上合計を集計(降順でソート)
product_sales = df.groupby('商品名')['売上金額'].sum().sort_values(ascending=False)
print("=== 商品別売上ランキング ===")
for rank, (product, sales) in enumerate(product_sales.items(), 1):
print(f"{rank}位: {product:8s} {sales:>12,}円")
print()
# 商品別の平均売上
product_avg = df.groupby('商品名')['売上金額'].mean().sort_values(ascending=False)
print("=== 商品別平均売上(1日あたり)===")
for product, avg in product_avg.items():
print(f"{product:8s} {avg:>8,.0f}円")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
.sort_values(ascending=False)
・値の大きい順(降順)にソート
・ascending=Trueだと昇順(小さい順)
enumerate(product_sales.items(), 1)
・items()でキーと値のペアを取得
・enumerate()で番号をつける(1から開始)
Step 5: 月別・商品別のクロス集計
ピボットテーブルを使って、月と商品の組み合わせで売上を集計します。
コード:ピボットテーブルの作成
# ピボットテーブルを作成
pivot_table = df.pivot_table(
values='売上金額', # 集計する値
index='月', # 行に配置
columns='商品名', # 列に配置
aggfunc='sum' # 集計方法(合計)
)
print("=== 月別・商品別売上(ピボットテーブル)===")
print(pivot_table)
print()
# 各月の売上トップ商品を表示
print("=== 各月の売上トップ商品 ===")
for month in range(1, 13):
top_product = pivot_table.loc[month].idxmax() # 最大値のインデックス(商品名)
top_sales = pivot_table.loc[month].max() # 最大値
print(f"{month:2d}月: {top_product} ({top_sales:,.0f}円)")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
df.pivot_table()
・データをクロス集計する関数
・Excelのピボットテーブルと同じ機能
pivot_table.loc[month]
・特定の月の行を取得
.idxmax()
・最大値を持つインデックス(この場合は商品名)を返す
Step 6: 売上推移の可視化
集計したデータをグラフで視覚化します。まずは月別の売上推移を折れ線グラフで表示します。
コード:月別売上の折れ線グラフ
# グラフのサイズを設定
plt.figure(figsize=(12, 6))
# 折れ線グラフを描画
plt.plot(monthly_sales.index, monthly_sales.values,
marker='o', linewidth=2, markersize=8, color='steelblue')
# グラフの装飾
plt.title('Monthly Sales Trend (月別売上推移)', fontsize=16, fontweight='bold')
plt.xlabel('Month (月)', fontsize=12)
plt.ylabel('Sales (円)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.xticks(range(1, 13))
# 最大値と最小値にマーカーを追加
max_month = monthly_sales.idxmax()
min_month = monthly_sales.idxmin()
plt.scatter(max_month, monthly_sales[max_month], color='red', s=200, zorder=5, label='Max')
plt.scatter(min_month, monthly_sales[min_month], color='blue', s=200, zorder=5, label='Min')
plt.legend()
plt.tight_layout()
plt.show()
# 最大・最小の月を表示
print(f"売上が最も多かった月: {max_month}月 ({monthly_sales[max_month]:,}円)")
print(f"売上が最も少なかった月: {min_month}月 ({monthly_sales[min_month]:,}円)")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
monthly_sales.idxmax()
・最大値を持つインデックス(月)を返す
plt.scatter(…, zorder=5)
・散布図で点を追加
・zorder=5で他の要素より前面に表示
s=200
・点のサイズを200に設定(目立つように大きく)
Step 7: 商品別売上の棒グラフ
コード:商品別売上の棒グラフ
# グラフのサイズを設定
plt.figure(figsize=(10, 6))
# 色のリスト
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A', '#98D8C8']
# 棒グラフを描画
bars = plt.bar(product_sales.index, product_sales.values, color=colors, edgecolor='black')
# 各棒の上に金額を表示
for bar in bars:
height = bar.get_height()
plt.text(bar.get_x() + bar.get_width()/2., height,
f'{int(height):,}',
ha='center', va='bottom', fontsize=10, fontweight='bold')
# グラフの装飾
plt.title('Sales by Product (商品別売上)', fontsize=16, fontweight='bold')
plt.xlabel('Product', fontsize=12)
plt.ylabel('Sales (円)', fontsize=12)
plt.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
for bar in bars:
・各棒グラフのオブジェクトをループ処理
bar.get_height()
・棒の高さ(値)を取得
bar.get_x() + bar.get_width()/2.
・棒の中央のX座標を計算
ha=’center’, va=’bottom’
・テキストの配置(水平:中央、垂直:下揃え)
Step 8: 商品別の月次推移
コード:商品別・月別売上推移
# グラフのサイズを設定
plt.figure(figsize=(14, 7))
# 各商品の月別売上を折れ線グラフで表示
for product in products:
# 特定の商品のデータを抽出して月別に集計
product_monthly = df[df['商品名'] == product].groupby('月')['売上金額'].sum()
plt.plot(product_monthly.index, product_monthly.values,
marker='o', label=product, linewidth=2)
# グラフの装飾
plt.title('Monthly Sales by Product (商品別・月別売上推移)', fontsize=16, fontweight='bold')
plt.xlabel('Month', fontsize=12)
plt.ylabel('Sales (円)', fontsize=12)
plt.legend(title='Product', fontsize=10)
plt.grid(True, alpha=0.3)
plt.xticks(range(1, 13))
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
df[df[‘商品名’] == product]
・特定の商品のデータだけを抽出
for product in products:
・各商品について順番にグラフを描画
・自動的に異なる色が割り当てられる
Step 9: 分析結果のまとめ(レポート作成)
分析結果をレポート形式でまとめます。数字だけでなく、ビジネス的な解釈と提案を加えることが重要です。
コード:分析レポートの出力
print("=" * 60)
print("売上データ分析レポート")
print("=" * 60)
print()
# 1. 年間総売上
total_sales = df['売上金額'].sum()
print("【1. 年間総売上】")
print(f" {total_sales:,}円")
print()
# 2. 月別の傾向
max_month = monthly_sales.idxmax()
min_month = monthly_sales.idxmin()
print("【2. 月別傾向】")
print(f" 最高売上月: {max_month}月 ({monthly_sales[max_month]:,}円)")
print(f" 最低売上月: {min_month}月 ({monthly_sales[min_month]:,}円)")
print(f" 差額: {monthly_sales[max_month] - monthly_sales[min_month]:,}円")
print()
# 3. 季節性の分析
summer_sales = monthly_sales[[6, 7, 8]].sum()
winter_sales = monthly_sales[[12, 1, 2]].sum()
growth_rate = ((summer_sales / winter_sales) - 1) * 100
print("【3. 季節による違い】")
print(f" 夏季(6-8月)売上: {summer_sales:,}円")
print(f" 冬季(12-2月)売上: {winter_sales:,}円")
print(f" 夏季は冬季より {growth_rate:.1f}% 高い")
print()
# 4. 商品別の傾向
print("【4. 商品別ランキング】")
for rank, (product, sales) in enumerate(product_sales.items(), 1):
share = (sales / total_sales) * 100
print(f" {rank}位: {product} - {sales:,}円 ({share:.1f}%)")
print()
# 5. 改善提案
print("【5. 改善提案】")
print(f" ✓ 夏季は売上が{growth_rate:.1f}%増加 → 夏の在庫を増やす")
print(f" ✓ {product_sales.index[0]}が売上トップ → 関連商品の展開を検討")
print(f" ✓ {min_month}月の売上が低い → 冬季キャンペーンの実施")
print(f" ✓ {product_sales.index[-1]}の売上が最下位 → プロモーション強化")
print()
print("=" * 60)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
monthly_sales[[6, 7, 8]].sum()
・6月、7月、8月の売上を合計
・リストで複数のインデックスを指定できる
product_sales.index[0]
・ソート済みなので、最初の要素がトップ商品
product_sales.index[-1]
・最後の要素が最下位商品
💡 プロジェクト1のポイント
✓ データを多角的に集計して傾向を把握
✓ グラフで視覚的に表現することで理解しやすくする
✓ 数字だけでなく、ビジネス的な解釈を加える
✓ 分析結果から具体的なアクション(改善提案)を導く
📊 3. プロジェクト2:アンケートデータ分析
次は、顧客満足度アンケートのデータを分析します。
📌 分析の目標
・全体的な満足度の傾向はどうか?
・年齢層によって満足度に違いはあるか?
・改善が必要な項目はどれか?
・リピート意向はどのくらいか?
Step 1: アンケートデータの作成
コード:アンケートデータの生成
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# 乱数シードを固定
np.random.seed(42)
# 回答者数
n_responses = 200
# 年齢層(確率で分布を設定)
age_groups = ['10代', '20代', '30代', '40代', '50代以上']
ages = np.random.choice(age_groups, n_responses,
p=[0.1, 0.3, 0.3, 0.2, 0.1])
# 性別
genders = np.random.choice(['男性', '女性'], n_responses,
p=[0.45, 0.55])
# 総合満足度(5段階評価)- 年齢により傾向を変える
satisfaction = []
for age in ages:
if age in ['10代', '20代']:
# 若い世代は満足度が高め
score = np.random.choice([3, 4, 5], p=[0.2, 0.5, 0.3])
elif age in ['30代', '40代']:
# 中年層は標準的
score = np.random.choice([2, 3, 4, 5], p=[0.1, 0.3, 0.4, 0.2])
else:
# シニア層は少し厳しめ
score = np.random.choice([2, 3, 4], p=[0.2, 0.5, 0.3])
satisfaction.append(score)
# 商品の質(5段階評価)
product_quality = np.random.choice([2, 3, 4, 5], n_responses,
p=[0.05, 0.25, 0.45, 0.25])
# 接客態度(5段階評価)
service_quality = np.random.choice([2, 3, 4, 5], n_responses,
p=[0.1, 0.2, 0.4, 0.3])
# 価格満足度(5段階評価)- やや厳しめの評価
price_satisfaction = np.random.choice([1, 2, 3, 4, 5], n_responses,
p=[0.05, 0.15, 0.35, 0.3, 0.15])
# リピート意向
repeat_intention = np.random.choice(['はい', 'いいえ', 'わからない'],
n_responses, p=[0.6, 0.1, 0.3])
# DataFrameに格納
survey_df = pd.DataFrame({
'年齢層': ages,
'性別': genders,
'総合満足度': satisfaction,
'商品の質': product_quality,
'接客態度': service_quality,
'価格満足度': price_satisfaction,
'リピート意向': repeat_intention
})
print("アンケートデータの準備完了!")
print(f"回答者数: {len(survey_df)}人")
print()
print("最初の10行:")
survey_df.head(10)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
np.random.choice(choices, size, p=[…])
・choicesから確率pに従ってランダムに選択
・sizeは選択する回数
・pは各選択肢の確率(合計が1になる必要あり)
例:p=[0.1, 0.3, 0.3, 0.2, 0.1]
・10代が10%、20代が30%、30代が30%、40代が20%、50代以上が10%
Step 2: 基本統計の確認
コード:アンケートデータの基本確認
# データ型と欠損値の確認
print("=== データの基本情報 ===")
print(survey_df.info())
print()
# 数値項目の統計量
print("=== 数値項目の統計量 ===")
numeric_cols = ['総合満足度', '商品の質', '接客態度', '価格満足度']
print(survey_df[numeric_cols].describe().round(2))
print()
# 年齢層の分布
print("=== 年齢層の分布 ===")
age_counts = survey_df['年齢層'].value_counts().sort_index()
for age, count in age_counts.items():
print(f"{age}: {count}人 ({count/len(survey_df)*100:.1f}%)")
print()
# 性別の分布
print("=== 性別の分布 ===")
gender_counts = survey_df['性別'].value_counts()
for gender, count in gender_counts.items():
print(f"{gender}: {count}人 ({count/len(survey_df)*100:.1f}%)")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
Step 3: 満足度の集計
コード:満足度の詳細分析
# 総合満足度の分布
print("=== 総合満足度の分布 ===")
satisfaction_dist = survey_df['総合満足度'].value_counts().sort_index()
for score, count in satisfaction_dist.items():
percentage = (count / len(survey_df)) * 100
bar = '█' * int(percentage / 2) # 簡易的な棒グラフ
print(f"{score}点: {count:3d}人 ({percentage:5.1f}%) {bar}")
print()
# 各項目の平均点
print("=== 各項目の平均点 ===")
avg_scores = {
'総合満足度': survey_df['総合満足度'].mean(),
'商品の質': survey_df['商品の質'].mean(),
'接客態度': survey_df['接客態度'].mean(),
'価格満足度': survey_df['価格満足度'].mean()
}
for item, score in avg_scores.items():
stars = '★' * int(score) + '☆' * (5 - int(score))
print(f"{item:10s}: {score:.2f}点 {stars}")
print()
# リピート意向の集計
print("=== リピート意向 ===")
repeat_dist = survey_df['リピート意向'].value_counts()
for intention, count in repeat_dist.items():
percentage = (count / len(survey_df)) * 100
print(f"{intention:10s}: {count:3d}人 ({percentage:5.1f}%)")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
‘█’ * int(percentage / 2)
・パーセンテージに応じた長さの棒を文字で表現
・簡易的なテキストグラフを作成
‘★’ * int(score) + ‘☆’ * (5 – int(score))
・スコアを星で視覚化
・例:3.5点なら「★★★☆☆」
Step 4: 年齢層別の分析
コード:年齢層別の満足度分析
# 年齢層別の総合満足度
age_order = ['10代', '20代', '30代', '40代', '50代以上']
age_satisfaction = survey_df.groupby('年齢層')['総合満足度'].agg(['mean', 'count'])
age_satisfaction = age_satisfaction.reindex(age_order)
print("=== 年齢層別の総合満足度 ===")
print(f"{'年齢層':8s} {'平均点':>8s} {'回答数':>8s}")
print("-" * 30)
for age, row in age_satisfaction.iterrows():
print(f"{age:8s} {row['mean']:8.2f} {int(row['count']):8d}人")
print()
# 年齢層別の各項目平均
print("=== 年齢層別の各項目平均 ===")
age_analysis = survey_df.groupby('年齢層')[numeric_cols].mean()
age_analysis = age_analysis.reindex(age_order)
print(age_analysis.round(2))
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
.agg([‘mean’, ‘count’])
・複数の集計を一度に実行
・平均(mean)と件数(count)を同時に計算
.reindex(age_order)
・指定した順序でインデックスを並び替え
・年齢層を若い順に表示するため
Step 5: クロス集計
コード:クロス集計の作成
# 年齢層×リピート意向のクロス集計
print("=== 年齢層別リピート意向(%)===")
age_repeat = pd.crosstab(
survey_df['年齢層'],
survey_df['リピート意向'],
normalize='index' # 行方向で正規化(各年齢層の合計が100%)
) * 100
age_repeat = age_repeat.reindex(age_order)
print(age_repeat.round(1))
print()
# 性別×総合満足度のクロス集計
print("=== 性別×総合満足度(%)===")
gender_satisfaction = pd.crosstab(
survey_df['性別'],
survey_df['総合満足度'],
normalize='index'
) * 100
print(gender_satisfaction.round(1))
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
pd.crosstab(行, 列)
・2つのカテゴリ変数の組み合わせで集計
・行に1つ目の変数、列に2つ目の変数
normalize=’index’
・行方向で正規化(各行の合計が1になる)
・’columns’なら列方向、’all’なら全体で正規化
Step 6: 満足度の可視化
コード:アンケート結果のダッシュボード
# 2×2のダッシュボードを作成
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
fig.suptitle('Customer Satisfaction Analysis', fontsize=18, fontweight='bold')
# 1. 総合満足度の分布(棒グラフ)
ax1 = axes[0, 0]
satisfaction_dist.plot(kind='bar', ax=ax1, color='steelblue', edgecolor='black')
ax1.set_title('Overall Satisfaction Distribution', fontsize=14)
ax1.set_xlabel('Score', fontsize=12)
ax1.set_ylabel('Count', fontsize=12)
ax1.set_xticklabels(ax1.get_xticklabels(), rotation=0)
# 各棒に人数を表示
for i, v in enumerate(satisfaction_dist.values):
ax1.text(i, v + 2, str(v), ha='center', fontweight='bold')
# 2. 各項目の平均点(横棒グラフ)
ax2 = axes[0, 1]
items = list(avg_scores.keys())
scores = list(avg_scores.values())
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA07A']
bars = ax2.barh(items, scores, color=colors, edgecolor='black')
ax2.set_title('Average Score by Category', fontsize=14)
ax2.set_xlabel('Score', fontsize=12)
ax2.set_xlim(0, 5)
ax2.axvline(x=3, color='red', linestyle='--', alpha=0.5, label='Middle (3)')
# 各棒に点数を表示
for bar, score in zip(bars, scores):
ax2.text(score + 0.1, bar.get_y() + bar.get_height()/2,
f'{score:.2f}', va='center', fontweight='bold')
# 3. 年齢層別の総合満足度(棒グラフ)
ax3 = axes[1, 0]
age_satisfaction['mean'].plot(kind='bar', ax=ax3, color='coral', edgecolor='black')
ax3.set_title('Satisfaction by Age Group', fontsize=14)
ax3.set_xlabel('Age Group', fontsize=12)
ax3.set_ylabel('Average Score', fontsize=12)
ax3.set_xticklabels(ax3.get_xticklabels(), rotation=45)
ax3.set_ylim(0, 5)
ax3.axhline(y=3, color='red', linestyle='--', alpha=0.5)
# 各棒に点数を表示
for i, v in enumerate(age_satisfaction['mean'].values):
ax3.text(i, v + 0.1, f'{v:.2f}', ha='center', fontweight='bold')
# 4. リピート意向(円グラフ)
ax4 = axes[1, 1]
colors_pie = ['#90EE90', '#FFB6C1', '#FFD700']
repeat_dist.plot(kind='pie', ax=ax4, autopct='%1.1f%%', colors=colors_pie)
ax4.set_title('Repeat Intention', fontsize=14)
ax4.set_ylabel('')
plt.tight_layout()
plt.show()
※ 画面が小さい場合は、コードブロックを横にスクロールできます
Step 7: 分析結果のまとめ
コード:アンケート分析レポート
print("=" * 60)
print("アンケートデータ分析レポート")
print("=" * 60)
print()
# 1. 回答者の属性
print("【1. 回答者プロフィール】")
print(f" 総回答数: {len(survey_df)}人")
main_age = age_counts.idxmax()
print(f" 主な年齢層: {main_age}が最多 ({age_counts[main_age]}人)")
print(f" 性別比率: 女性{gender_counts['女性']/len(survey_df)*100:.0f}%、男性{gender_counts['男性']/len(survey_df)*100:.0f}%")
print()
# 2. 満足度の現状
high_satisfaction = (survey_df['総合満足度'] >= 4).sum()
low_satisfaction = (survey_df['総合満足度'] <= 2).sum()
print("【2. 満足度の現状】")
print(f" 総合満足度平均: {survey_df['総合満足度'].mean():.2f}点")
print(f" 満足層(4点以上): {high_satisfaction}人 ({high_satisfaction/len(survey_df)*100:.0f}%)")
print(f" 不満層(2点以下): {low_satisfaction}人 ({low_satisfaction/len(survey_df)*100:.0f}%)")
print()
# 3. 項目別の評価
best_item = max(avg_scores, key=avg_scores.get)
worst_item = min(avg_scores, key=avg_scores.get)
print("【3. 項目別評価】")
print(f" 最高評価: {best_item} ({avg_scores[best_item]:.2f}点)")
print(f" 最低評価: {worst_item} ({avg_scores[worst_item]:.2f}点)")
print(f" 改善余地: {worst_item}が他項目より{avg_scores[best_item] - avg_scores[worst_item]:.2f}点低い")
print()
# 4. 年齢層による違い
highest_age = age_satisfaction['mean'].idxmax()
lowest_age = age_satisfaction['mean'].idxmin()
print("【4. 年齢層による違い】")
print(f" 最も満足度が高い: {highest_age} ({age_satisfaction.loc[highest_age, 'mean']:.2f}点)")
print(f" 最も満足度が低い: {lowest_age} ({age_satisfaction.loc[lowest_age, 'mean']:.2f}点)")
print(f" 傾向: 若年層ほど満足度が高い")
print()
# 5. リピート意向
repeat_yes = repeat_dist['はい']
repeat_no = repeat_dist['いいえ']
repeat_unknown = repeat_dist['わからない']
print("【5. リピート意向】")
print(f" リピート希望: {repeat_yes}人 ({repeat_yes/len(survey_df)*100:.0f}%)")
print(f" リピート否定: {repeat_no}人 ({repeat_no/len(survey_df)*100:.0f}%)")
print(f" 保留層: {repeat_unknown}人 ({repeat_unknown/len(survey_df)*100:.0f}%)")
print()
# 6. 改善提案
print("【6. 改善提案】")
print(f" ✓ {worst_item}が最も低い → 価格戦略の見直しが必要")
print(f" ✓ {lowest_age}の満足度が低い → シニア層向けサービスの改善")
print(f" ✓ {best_item}は高評価 → この強みをアピールすべき")
print(f" ✓ 保留層が{repeat_unknown/len(survey_df)*100:.0f}% → 具体的な改善で取り込める可能性")
print()
print("=" * 60)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
💡 コードの解説
max(avg_scores, key=avg_scores.get)
・辞書の値が最大のキーを取得
・key=avg_scores.getで値を比較基準にする
(survey_df['総合満足度'] >= 4).sum()
・条件を満たす行数をカウント
・TrueをSum()すると1として数えられる
💡 プロジェクト2のポイント
✓ クロス集計で属性別の違いを明らかにする
✓ 複数の視点からデータを分析する
✓ 数字の背景にある意味を考察する
✓ 改善につながる具体的な提案を行う
📝 チャレンジ課題
課題1:売上データの深掘り分析(発展)
📋 課題
プロジェクト1の売上データを使って、以下の分析を追加してください:
・曜日別の売上傾向を分析
・前月比の成長率を計算
・累計売上のグラフを作成
ヒントを見る
ヒント
・曜日の取得: df['日付'].dt.dayofweek または dt.day_name()
・前月比の計算: monthly_sales.pct_change()
・累計の計算: monthly_sales.cumsum()
課題2:アンケートデータの詳細分析(発展)
📋 課題
プロジェクト2のアンケートデータを使って、以下の分析を追加してください:
・満足度とリピート意向の関係を分析
・性別×年齢層のクロス集計
・ヒートマップで項目間の相関を可視化
ヒントを見る
ヒント
・相関行列の計算: survey_df[numeric_cols].corr()
・ヒートマップ: sns.heatmap(corr, annot=True, cmap='coolwarm')
・クロス集計: pd.crosstab(survey_df['性別'], survey_df['年齢層'])
課題3:オリジナルプロジェクト(応用)
📋 課題
興味のあるテーマで自分独自のデータを作成し、分析してみましょう:
・学校の成績データ
・スポーツチームの成績
・読書記録
・家計簿データ
分析の流れ: データ作成 → 集計 → 可視化 → 考察・提案
🎯 このステップのまとめ
✅ 学んだこと
✓ データ分析プロジェクトの5ステップ(読み込み→確認→加工→可視化→解釈)
✓ 売上データの分析手法(月別集計、商品別集計、ピボットテーブル)
✓ アンケートデータの分析手法(分布、クロス集計、属性別分析)
✓ 分析結果から改善提案を導く方法
✓ レポート形式でまとめる技術
💡 実務での活用
ビジネス: 売上分析、顧客分析、在庫管理
マーケティング: アンケート分析、A/Bテスト
教育: 成績分析、学習効果測定
個人: 家計管理、健康管理、趣味の記録
❓ よくある質問
Q1: 実際のCSVファイルを読み込むにはどうすればいいですか?
A: df = pd.read_csv('ファイル名.csv', encoding='utf-8')を使います。Google Colabの場合、左のファイルアイコンからアップロードできます。文字化けする場合はencoding='shift-jis'を試してください。
Q2: 分析結果をどのようにまとめればいいですか?
A: 結論→詳細→提案の順でまとめると良いです。最初に重要な発見を述べ、その根拠となるデータを示し、最後に具体的なアクションを提案します。
Q3: グラフが多すぎる気がします。どれを選ぶべきですか?
A: 伝えたいメッセージに合わせて選択します。すべてのグラフを載せる必要はありません。最も重要な発見を示すグラフ2〜3個に絞るのが効果的です。
Q4: データ分析で最も大切なことは何ですか?
A: データの背景を理解することです。数字だけ見るのではなく、「なぜそうなったのか」「これはビジネスにとって何を意味するのか」を考えることが重要です。
Q5: もっと複雑な分析をするには何を学べばいいですか?
A: 統計学と機械学習を学ぶと良いでしょう。回帰分析、クラスタリング、予測モデルなどに進むことができます。Scikit-learnというライブラリが役立ちます。
学習メモ
Pythonデータ分析入門 - Step 42