🔗 ステップ30: データの結合(merge, concat)
複数のデータを組み合わせて、より豊かな分析を!
ステップ29では、グループ化と集計を学びました。今回は、複数のデータを結合して1つにまとめる方法を学びます。
📖 このステップで学ぶこと
・merge()で結合する方法
・結合の種類(inner, outer, left, right)
・concat()で連結する方法
・実践例:マスタデータとの結合
🎯 1. データ結合とは?
実際のデータ分析では、必要なデータが複数のファイルやテーブルに分かれていることが多いです。これらを組み合わせることで、より詳しい分析ができます。
🔰 なぜデータを結合するのか
📌 データ結合の例
・売上データ + 商品マスタ(商品名、価格など)
・顧客データ + 購入履歴
・1月のデータ + 2月のデータ + 3月のデータ
・社員情報 + 部署情報
売上データには「商品ID」しかないけど、商品名も知りたい。そんなとき、商品マスタと結合して商品名を追加します。
📘 2つの結合方法の違い
Pandasには、データを結合する方法が2種類あります。用途によって使い分けます。
| 方法 | 用途 | イメージ |
| merge() | 共通のキー(IDなど)で横に結合 | 売上データ + 商品情報 |
| concat() | 同じ構造のデータを縦に連結 | 1月 + 2月 + 3月のデータ |
💡 簡単な覚え方
merge():「この商品ID、名前は何?」→ 横に情報を追加
concat():「1月、2月、3月のデータを全部まとめたい」→ 縦に積み重ねる
🔗 2. merge()で結合
merge()は、共通の列(キー)を使って2つのDataFrameを結合します。データベースの「JOIN」と同じ考え方です。
🔰 基本的な結合の仕組み
まず、結合がどのように動くか、簡単な例で見てみましょう。
コード:merge()の基本
import pandas as pd
# 売上データ(商品IDと売上金額だけ)
sales = pd.DataFrame({
'商品ID': [1, 2, 3, 1, 2],
'売上': [1200, 900, 1500, 1100, 950]
})
# 商品マスタ(商品IDと商品名・価格)
products = pd.DataFrame({
'商品ID': [1, 2, 3],
'商品名': ['りんご', 'バナナ', 'みかん'],
'価格': [100, 150, 80]
})
print("売上データ:")
print(sales)
print("\n商品マスタ:")
print(products)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
売上データ: 商品ID 売上 0 1 1200 1 2 900 2 3 1500 3 1 1100 4 2 950 商品マスタ: 商品ID 商品名 価格 0 1 りんご 100 1 2 バナナ 150 2 3 みかん 80
💡 現状の問題
売上データには「商品ID」しかありません。
「この売上は何の商品だろう?」と思っても、商品名がわかりません。
そこで、商品マスタと結合して、商品名を追加します。
📝 merge()で結合する
コード:商品IDをキーに結合
# 商品IDをキーに結合
merged = pd.merge(sales, products, on='商品ID')
print("結合後:")
print(merged)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
結合後: 商品ID 売上 商品名 価格 0 1 1200 りんご 100 1 1 1100 りんご 100 2 2 900 バナナ 150 3 2 950 バナナ 150 4 3 1500 みかん 80
💡 コードの解説
pd.merge(sales, products, on=’商品ID’)
・pd.merge():2つのDataFrameを結合する関数
・sales:結合する1つ目のデータ(左側)
・products:結合する2つ目のデータ(右側)
・on=’商品ID’:どの列をキーにして結合するか指定
結合の仕組み:
1. salesの1行目の「商品ID: 1」を見る
2. productsで「商品ID: 1」の行を探す
3. 見つかったら、商品名「りんご」と価格「100」を追加
4. 全ての行で繰り返す
📌 merge()の基本構文
pd.merge(左のDF, 右のDF, on=’キー列名’)
・両方のDataFrameに同じ列名が必要
・その列の値が一致する行同士を結合
📘 列名が異なる場合
2つのDataFrameで列名が違う場合は、left_onとright_onを使います。
コード:列名が異なる場合の結合
# 列名が異なるデータ
orders = pd.DataFrame({
'order_id': [101, 102, 103],
'product_id': [1, 2, 1], # ここでは product_id
'数量': [5, 3, 7]
})
products2 = pd.DataFrame({
'id': [1, 2, 3], # ここでは id
'商品名': ['りんご', 'バナナ', 'みかん']
})
print("注文データ:")
print(orders)
print("\n商品データ:")
print(products2)
# left_onとright_onで別々の列名を指定
merged2 = pd.merge(orders, products2,
left_on='product_id',
right_on='id')
print("\n結合後:")
print(merged2)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
注文データ: order_id product_id 数量 0 101 1 5 1 102 2 3 2 103 1 7 商品データ: id 商品名 0 1 りんご 1 2 バナナ 2 3 みかん 結合後: order_id product_id 数量 id 商品名 0 101 1 5 1 りんご 1 103 1 7 1 りんご 2 102 2 3 2 バナナ
💡 コードの解説
left_on=’product_id’:左のデータ(orders)では product_id を使う
right_on=’id’:右のデータ(products2)では id を使う
列名が違っても、値が一致すれば結合できます。
📘 複数の列をキーにする
1つの列だけでは一意に特定できない場合、複数の列をキーにできます。
コード:複数列をキーに結合
# 日付と商品IDの両方で価格が変わるデータ
sales_detail = pd.DataFrame({
'日付': ['1/1', '1/1', '1/2', '1/2'],
'商品ID': [1, 2, 1, 2],
'売上': [1200, 900, 1500, 1100]
})
prices = pd.DataFrame({
'日付': ['1/1', '1/1', '1/2', '1/2'],
'商品ID': [1, 2, 1, 2],
'価格': [100, 150, 105, 155] # 日によって価格が違う
})
print("売上データ:")
print(sales_detail)
print("\n価格データ:")
print(prices)
# 日付と商品IDの両方で結合
merged3 = pd.merge(sales_detail, prices,
on=['日付', '商品ID'])
print("\n結合後:")
print(merged3)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
売上データ: 日付 商品ID 売上 0 1/1 1 1200 1 1/1 2 900 2 1/2 1 1500 3 1/2 2 1100 価格データ: 日付 商品ID 価格 0 1/1 1 100 1 1/1 2 150 2 1/2 1 105 3 1/2 2 155 結合後: 日付 商品ID 売上 価格 0 1/1 1 1200 100 1 1/1 2 900 150 2 1/2 1 1500 105 3 1/2 2 1100 155
💡 複数キーの書き方
on=[‘日付’, ‘商品ID’]
リストで複数の列名を指定します。
「1/1の商品ID=1」と「1/2の商品ID=1」は別の行として扱われます。
🔀 3. 結合の種類(how)
merge()には4種類の結合方法があります。howパラメータで指定します。
🔰 準備:サンプルデータ
まず、結合の違いを理解するためのデータを用意します。
コード:サンプルデータの準備
import pandas as pd
# 左のデータ(商品マスタ)
left_df = pd.DataFrame({
'商品ID': [1, 2, 3],
'商品名': ['りんご', 'バナナ', 'みかん']
})
# 右のデータ(在庫データ)
right_df = pd.DataFrame({
'商品ID': [2, 3, 4],
'在庫': [50, 30, 45]
})
print("左のデータ(商品マスタ):")
print(left_df)
print("\n右のデータ(在庫データ):")
print(right_df)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
左のデータ(商品マスタ): 商品ID 商品名 0 1 りんご 1 2 バナナ 2 3 みかん 右のデータ(在庫データ): 商品ID 在庫 0 2 50 1 3 30 2 4 45
💡 このデータのポイント
左にだけある:商品ID = 1(りんご)
両方にある:商品ID = 2, 3(バナナ、みかん)
右にだけある:商品ID = 4
結合方法によって、どのデータが残るかが変わります。
📝 1. Inner Join(内部結合)- デフォルト
両方に存在するデータだけを残します。
コード:Inner Join
# 両方に存在するデータだけ
inner_merge = pd.merge(left_df, right_df, on='商品ID', how='inner')
print("Inner Join(両方に存在):")
print(inner_merge)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
Inner Join(両方に存在): 商品ID 商品名 在庫 0 2 バナナ 50 1 3 みかん 30
💡 Inner Joinの動作
・商品ID=1(りんご):右にないので消える
・商品ID=2, 3:両方にあるので残る
・商品ID=4:左にないので消える
howを省略するとInner Joinになります(デフォルト)。
📝 2. Outer Join(外部結合)
すべてのデータを残します。一致しない部分はNaNになります。
コード:Outer Join
# すべてのデータを含める
outer_merge = pd.merge(left_df, right_df, on='商品ID', how='outer')
print("Outer Join(すべて含める):")
print(outer_merge)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
Outer Join(すべて含める): 商品ID 商品名 在庫 0 1 りんご NaN 1 2 バナナ 50.0 2 3 みかん 30.0 3 4 NaN 45.0
💡 Outer Joinの動作
・商品ID=1:右にないので、在庫がNaN
・商品ID=2, 3:両方にあるので、全ての情報あり
・商品ID=4:左にないので、商品名がNaN
データを失いたくない場合に使います。
📝 3. Left Join(左外部結合)
左のデータは全て残す。右にないデータはNaNになります。
コード:Left Join
# 左のデータは全て残す
left_merge = pd.merge(left_df, right_df, on='商品ID', how='left')
print("Left Join(左を全て残す):")
print(left_merge)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
Left Join(左を全て残す): 商品ID 商品名 在庫 0 1 りんご NaN 1 2 バナナ 50.0 2 3 みかん 30.0
💡 Left Joinの動作
・商品ID=1:左にあるので残る、在庫はNaN
・商品ID=2, 3:両方にあるので全ての情報あり
・商品ID=4:左にないので消える
最もよく使う結合方法です。メインのデータを全て残したい場合に使います。
📝 4. Right Join(右外部結合)
右のデータは全て残す。左にないデータはNaNになります。
コード:Right Join
# 右のデータは全て残す
right_merge = pd.merge(left_df, right_df, on='商品ID', how='right')
print("Right Join(右を全て残す):")
print(right_merge)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
Right Join(右を全て残す): 商品ID 商品名 在庫 0 2 バナナ 50 1 3 みかん 30 2 4 NaN 45
💡 Right Joinの動作
・商品ID=1:右にないので消える
・商品ID=2, 3:両方にあるので全ての情報あり
・商品ID=4:右にあるので残る、商品名はNaN
📘 結合方法のまとめ
📌 結合方法の使い分け
| how | 残るデータ | 使いどころ |
| inner | 両方に存在するデータだけ | 完全一致するデータだけ欲しい時 |
| left | 左のデータ全て | メインのデータを全て残したい時(最頻出) |
| right | 右のデータ全て | 右側を基準にしたい時 |
| outer | 全てのデータ | 全てのデータを含めたい時 |
📚 4. concat()で連結
concat()は、DataFrameを縦または横に積み重ねるときに使います。
🔰 縦に連結(行を追加)
同じ構造のデータを縦に連結します。例えば、月別のデータを1つにまとめる場合です。
コード:縦に連結
import pandas as pd
# 月別の売上データ
jan_sales = pd.DataFrame({
'商品': ['りんご', 'バナナ'],
'売上': [1200, 900]
})
feb_sales = pd.DataFrame({
'商品': ['りんご', 'バナナ'],
'売上': [1350, 950]
})
mar_sales = pd.DataFrame({
'商品': ['りんご', 'バナナ'],
'売上': [1400, 1000]
})
print("1月の売上:")
print(jan_sales)
print("\n2月の売上:")
print(feb_sales)
print("\n3月の売上:")
print(mar_sales)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
1月の売上: 商品 売上 0 りんご 1200 1 バナナ 900 2月の売上: 商品 売上 0 りんご 1350 1 バナナ 950 3月の売上: 商品 売上 0 りんご 1400 1 バナナ 1000
コード:concat()で縦に連結
# 縦に連結
all_sales = pd.concat([jan_sales, feb_sales, mar_sales])
print("連結後:")
print(all_sales)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
連結後: 商品 売上 0 りんご 1200 1 バナナ 900 0 りんご 1350 1 バナナ 950 0 りんご 1400 1 バナナ 1000
💡 コードの解説
pd.concat([jan_sales, feb_sales, mar_sales])
・pd.concat():DataFrameを連結する関数
・引数はリスト形式で渡します
・デフォルトで縦方向(axis=0)に連結されます
注意点:
インデックスが元のまま(0, 1, 0, 1, 0, 1)になっています。
📝 インデックスをリセット
ignore_index=Trueで、インデックスを0から振り直せます。
コード:インデックスをリセット
# インデックスを振り直す
all_sales_reset = pd.concat([jan_sales, feb_sales, mar_sales],
ignore_index=True)
print("インデックスをリセット:")
print(all_sales_reset)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
インデックスをリセット: 商品 売上 0 りんご 1200 1 バナナ 900 2 りんご 1350 3 バナナ 950 4 りんご 1400 5 バナナ 1000
📘 月の情報を追加(keysオプション)
連結時に、keysで識別子を追加できます。
コード:月の情報を追加
# keysで識別子を追加
all_sales_with_month = pd.concat(
[jan_sales, feb_sales, mar_sales],
keys=['1月', '2月', '3月']
)
print("月の情報付き:")
print(all_sales_with_month)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
月の情報付き:
商品 売上
1月 0 りんご 1200
1 バナナ 900
2月 0 りんご 1350
1 バナナ 950
3月 0 りんご 1400
1 バナナ 1000
📘 横に連結(列を追加)
axis=1で横方向に連結できます。
コード:横に連結
# 別々のデータ
product_info = pd.DataFrame({
'商品': ['りんご', 'バナナ', 'みかん']
})
prices = pd.DataFrame({
'価格': [100, 150, 80]
})
stock = pd.DataFrame({
'在庫': [50, 30, 45]
})
# 横に連結(axis=1)
combined = pd.concat([product_info, prices, stock], axis=1)
print("横に連結:")
print(combined)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
横に連結: 商品 価格 在庫 0 りんご 100 50 1 バナナ 150 30 2 みかん 80 45
📌 concat()のポイント
axis=0:縦に連結(デフォルト)→ 行が増える
axis=1:横に連結 → 列が増える
ignore_index=True:インデックスをリセット
keys:連結元を識別する
💼 5. 実践例
📘 例1:売上データと商品マスタの結合
コード:実践的な売上分析
import pandas as pd
# 実際の売上データ
sales_data = pd.DataFrame({
'売上ID': [1, 2, 3, 4, 5],
'日付': ['2024-01-01', '2024-01-01', '2024-01-02',
'2024-01-02', '2024-01-03'],
'商品コード': ['P001', 'P002', 'P001', 'P003', 'P002'],
'数量': [10, 5, 12, 8, 6],
'地域': ['東京', '大阪', '東京', '名古屋', '大阪']
})
# 商品マスタ
product_master = pd.DataFrame({
'商品コード': ['P001', 'P002', 'P003'],
'商品名': ['りんご', 'バナナ', 'みかん'],
'単価': [100, 150, 80],
'カテゴリ': ['果物', '果物', '果物']
})
print("売上データ:")
print(sales_data)
print("\n商品マスタ:")
print(product_master)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
売上データ: 売上ID 日付 商品コード 数量 地域 0 1 2024-01-01 P001 10 東京 1 2 2024-01-01 P002 5 大阪 2 3 2024-01-02 P001 12 東京 3 4 2024-01-02 P003 8 名古屋 4 5 2024-01-03 P002 6 大阪 商品マスタ: 商品コード 商品名 単価 カテゴリ 0 P001 りんご 100 果物 1 P002 バナナ 150 果物 2 P003 みかん 80 果物
コード:結合して売上金額を計算
# 結合
sales_with_product = pd.merge(sales_data, product_master,
on='商品コード', how='left')
# 売上金額を計算
sales_with_product['売上金額'] = sales_with_product['単価'] * sales_with_product['数量']
print("結合後(売上金額付き):")
print(sales_with_product)
# 商品別の売上集計
print("\n商品別の売上集計:")
summary = sales_with_product.groupby('商品名').agg({
'数量': 'sum',
'売上金額': 'sum'
})
print(summary)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
結合後(売上金額付き):
売上ID 日付 商品コード 数量 地域 商品名 単価 カテゴリ 売上金額
0 1 2024-01-01 P001 10 東京 りんご 100 果物 1000
1 2 2024-01-01 P002 5 大阪 バナナ 150 果物 750
2 3 2024-01-02 P001 12 東京 りんご 100 果物 1200
3 4 2024-01-02 P003 8 名古屋 みかん 80 果物 640
4 5 2024-01-03 P002 6 大阪 バナナ 150 果物 900
商品別の売上集計:
数量 売上金額
商品名
みかん 8 640
バナナ 11 1650
りんご 22 2200
📘 例2:複数月のデータ連結と分析
コード:月別データの連結と分析
# 1月〜3月のデータ
jan = pd.DataFrame({
'商品': ['A', 'B', 'C'],
'売上': [100, 150, 120]
})
feb = pd.DataFrame({
'商品': ['A', 'B', 'C'],
'売上': [110, 160, 130]
})
mar = pd.DataFrame({
'商品': ['A', 'B', 'C'],
'売上': [105, 155, 125]
})
# 月情報を追加して連結
jan['月'] = '1月'
feb['月'] = '2月'
mar['月'] = '3月'
all_data = pd.concat([jan, feb, mar], ignore_index=True)
print("3ヶ月分のデータ:")
print(all_data)
# 商品ごとの合計と平均
product_summary = all_data.groupby('商品')['売上'].agg(['sum', 'mean'])
print("\n商品ごとの集計:")
print(product_summary)
# 月ごとの合計
monthly_summary = all_data.groupby('月')['売上'].sum()
print("\n月ごとの売上:")
print(monthly_summary)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
3ヶ月分のデータ:
商品 売上 月
0 A 100 1月
1 B 150 1月
2 C 120 1月
3 A 110 2月
4 B 160 2月
5 C 130 2月
6 A 105 3月
7 B 155 3月
8 C 125 3月
商品ごとの集計:
sum mean
商品
A 315 105.000000
B 465 155.000000
C 375 125.000000
月ごとの売上:
月
1月 370
2月 400
3月 385
Name: 売上, dtype: int64
📝 練習問題
ここまで学んだことを、実際に手を動かして確認しましょう。
問題1:基本的なmerge(初級)
📋 問題
以下の2つのDataFrameを「ID」をキーに結合してください。
df1 = pd.DataFrame({
'ID': [1, 2, 3],
'名前': ['太郎', '花子', '次郎']
})
df2 = pd.DataFrame({
'ID': [1, 2, 3],
'年齢': [25, 30, 28]
})
※ 画面が小さい場合は、コードブロックを横にスクロールできます
解答例を見る
コード
import pandas as pd
df1 = pd.DataFrame({
'ID': [1, 2, 3],
'名前': ['太郎', '花子', '次郎']
})
df2 = pd.DataFrame({
'ID': [1, 2, 3],
'年齢': [25, 30, 28]
})
print("df1:")
print(df1)
print("\ndf2:")
print(df2)
# 結合
merged = pd.merge(df1, df2, on='ID')
print("\n結合後:")
print(merged)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
df1: ID 名前 0 1 太郎 1 2 花子 2 3 次郎 df2: ID 年齢 0 1 25 1 2 30 2 3 28 結合後: ID 名前 年齢 0 1 太郎 25 1 2 花子 30 2 3 次郎 28
問題2:concat で縦に連結(初級)
📋 問題
以下の3つのDataFrameを縦に連結してください。
df1 = pd.DataFrame({'商品': ['A'], '売上': [100]})
df2 = pd.DataFrame({'商品': ['B'], '売上': [150]})
df3 = pd.DataFrame({'商品': ['C'], '売上': [120]})
※ 画面が小さい場合は、コードブロックを横にスクロールできます
解答例を見る
コード
import pandas as pd
df1 = pd.DataFrame({'商品': ['A'], '売上': [100]})
df2 = pd.DataFrame({'商品': ['B'], '売上': [150]})
df3 = pd.DataFrame({'商品': ['C'], '売上': [120]})
# 縦に連結
result = pd.concat([df1, df2, df3], ignore_index=True)
print("連結後:")
print(result)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
連結後: 商品 売上 0 A 100 1 B 150 2 C 120
問題3:Left Join(中級)
📋 問題
以下のデータをleft joinで結合してください。左のデータ(売上)は全て残してください。
sales = pd.DataFrame({
'商品ID': [1, 2, 3, 4],
'売上': [1000, 1500, 1200, 800]
})
products = pd.DataFrame({
'商品ID': [1, 2, 5],
'商品名': ['りんご', 'バナナ', 'ぶどう']
})
※ 画面が小さい場合は、コードブロックを横にスクロールできます
解答例を見る
コード
import pandas as pd
sales = pd.DataFrame({
'商品ID': [1, 2, 3, 4],
'売上': [1000, 1500, 1200, 800]
})
products = pd.DataFrame({
'商品ID': [1, 2, 5],
'商品名': ['りんご', 'バナナ', 'ぶどう']
})
print("売上データ:")
print(sales)
print("\n商品マスタ:")
print(products)
# left join
result = pd.merge(sales, products, on='商品ID', how='left')
print("\nLeft Join結果:")
print(result)
print("\n商品名がNaNの行:")
print(result[result['商品名'].isnull()])
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
売上データ: 商品ID 売上 0 1 1000 1 2 1500 2 3 1200 3 4 800 商品マスタ: 商品ID 商品名 0 1 りんご 1 2 バナナ 2 5 ぶどう Left Join結果: 商品ID 売上 商品名 0 1 1000 りんご 1 2 1500 バナナ 2 3 1200 NaN 3 4 800 NaN 商品名がNaNの行: 商品ID 売上 商品名 2 3 1200 NaN 3 4 800 NaN
問題4:集計してから結合(中級)
📋 問題
以下の売上データを商品ごとに集計してから、商品マスタと結合してください。
sales = pd.DataFrame({
'商品ID': [1, 2, 1, 2, 1],
'売上': [100, 150, 120, 140, 110]
})
products = pd.DataFrame({
'商品ID': [1, 2],
'商品名': ['りんご', 'バナナ']
})
※ 画面が小さい場合は、コードブロックを横にスクロールできます
解答例を見る
コード
import pandas as pd
sales = pd.DataFrame({
'商品ID': [1, 2, 1, 2, 1],
'売上': [100, 150, 120, 140, 110]
})
products = pd.DataFrame({
'商品ID': [1, 2],
'商品名': ['りんご', 'バナナ']
})
print("売上データ:")
print(sales)
# 商品ごとに集計
sales_summary = sales.groupby('商品ID')['売上'].sum().reset_index()
sales_summary.columns = ['商品ID', '売上合計']
print("\n集計後:")
print(sales_summary)
# 商品マスタと結合
result = pd.merge(sales_summary, products, on='商品ID')
print("\n商品名を追加:")
print(result)
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
売上データ: 商品ID 売上 0 1 100 1 2 150 2 1 120 3 2 140 4 1 110 集計後: 商品ID 売上合計 0 1 330 1 2 290 商品名を追加: 商品ID 売上合計 商品名 0 1 330 りんご 1 2 290 バナナ
問題5:総合演習(上級)
📋 問題
以下の3つのデータを結合して、総合的な売上レポートを作成してください。
1. 売上データと商品マスタを結合
2. 商品ごとの売上合計と平均を計算
3. カテゴリごとの売上合計を計算
sales = pd.DataFrame({
'商品コード': ['P001', 'P002', 'P001', 'P003', 'P002', 'P003'],
'数量': [10, 5, 12, 8, 6, 7],
'日付': ['1/1', '1/1', '1/2', '1/2', '1/3', '1/3']
})
products = pd.DataFrame({
'商品コード': ['P001', 'P002', 'P003'],
'商品名': ['りんご', 'バナナ', 'みかん'],
'単価': [100, 150, 80],
'カテゴリ': ['果物A', '果物B', '果物A']
})
※ 画面が小さい場合は、コードブロックを横にスクロールできます
解答例を見る
コード
import pandas as pd
sales = pd.DataFrame({
'商品コード': ['P001', 'P002', 'P001', 'P003', 'P002', 'P003'],
'数量': [10, 5, 12, 8, 6, 7],
'日付': ['1/1', '1/1', '1/2', '1/2', '1/3', '1/3']
})
products = pd.DataFrame({
'商品コード': ['P001', 'P002', 'P003'],
'商品名': ['りんご', 'バナナ', 'みかん'],
'単価': [100, 150, 80],
'カテゴリ': ['果物A', '果物B', '果物A']
})
print("="*50)
print("売上分析レポート")
print("="*50)
# 1. データ結合
merged = pd.merge(sales, products, on='商品コード', how='left')
merged['売上金額'] = merged['数量'] * merged['単価']
print("\n【1. 結合データ】")
print(merged)
# 2. 商品ごとの集計
product_summary = merged.groupby(['商品名', 'カテゴリ']).agg({
'売上金額': ['sum', 'mean'],
'数量': 'sum'
}).round(0)
print("\n【2. 商品ごとの売上集計】")
print(product_summary)
# 3. カテゴリごとの集計
category_summary = merged.groupby('カテゴリ')['売上金額'].sum()
print("\n【3. カテゴリごとの売上合計】")
print(category_summary)
print(f"\n【総売上】: {merged['売上金額'].sum()}円")
※ 画面が小さい場合は、コードブロックを横にスクロールできます
実行結果
==================================================
売上分析レポート
==================================================
【1. 結合データ】
商品コード 数量 日付 商品名 単価 カテゴリ 売上金額
0 P001 10 1/1 りんご 100 果物A 1000
1 P002 5 1/1 バナナ 150 果物B 750
2 P001 12 1/2 りんご 100 果物A 1200
3 P003 8 1/2 みかん 80 果物A 640
4 P002 6 1/3 バナナ 150 果物B 900
5 P003 7 1/3 みかん 80 果物A 560
【2. 商品ごとの売上集計】
売上金額 数量
sum mean sum
商品名 カテゴリ
みかん 果物A 1200.0 600.0 15
バナナ 果物B 1650.0 825.0 11
りんご 果物A 2200.0 1100.0 22
【3. カテゴリごとの売上合計】
カテゴリ
果物A 3400
果物B 1650
Name: 売上金額, dtype: int64
【総売上】: 5050円
🎯 このステップのまとめ
✅ 学んだこと
✓ merge()で共通キーでデータを結合できる
✓ inner, outer, left, rightの4種類の結合方法
✓ concat()でデータを縦または横に連結できる
✓ 複数の列をキーにした結合ができる
✓ 実務的なマスタデータとの結合パターン
💡 次のステップに進む前に確認
以下のことができるようになったか確認しましょう:
□ merge()でデータを結合できる
□ 4種類の結合方法の違いがわかる
□ concat()でデータを連結できる
□ マスタデータとの結合ができる
これらができたら、次のステップに進みましょう!
❓ よくある質問
Q1: merge()とconcat()の使い分けは?
A: merge():共通のキー(ID、コードなど)で横に結合
concat():同じ構造のデータを縦に積み重ねる
例:売上+商品情報ならmerge、1月+2月+3月ならconcat
Q2: inner joinとleft joinの違いは?
A: inner:両方に存在するデータだけ(完全一致)
left:左のデータは全て残す(マスタにない商品もOK)
実務ではleftをよく使います。売上データは全て残したい場合が多いため。
Q3: 結合後に重複した列名(_xと_y)が付きます
A: 両方のDataFrameに同じ列名があると、自動的に_x、_yが付きます。suffixesパラメータで変更できます:
pd.merge(df1, df2, on='ID', suffixes=('_左', '_右'))
Q4: 3つ以上のDataFrameを結合したいです
A: merge():順番に結合
result = df1.merge(df2, on='ID').merge(df3, on='ID')
concat():リストで一度に
pd.concat([df1, df2, df3])
Q5: 結合に失敗したデータを確認したいです
A: indicator=Trueオプションを使うと、どちらにデータがあったか追跡できます:
pd.merge(df1, df2, on='ID', how='outer', indicator=True)
_merge列に’left_only’、’right_only’、’both’が表示されます。
学習メモ
Pythonデータ分析入門 - Step 30