404 Not Found

404 Not Found


nginx

【concat】連結と追加|Pandas データ結合の基礎

merge は「横方向の結合」(キーで列をマッチング)を行うのに対し、concat は「縦・横方向の連結」(行や列を積み重ねる)を行います。12ヶ月分の売上データを1つの年間テーブルにまとめたり、3つの支店のレポートをマスターレポートに統合したりするのが concat の役割です。本セクションでは、concat の axis 方向、インデックス処理、整合(アラインメント)、keys による多段階ラベル、そして concat と merge の使い分け戦略について解説します。

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

1. 学習内容



2. チャーリーの12ヶ月データ連結

(1) 課題:12個の CSV を1つずつ読み込む手間

チャーリーは月別の売上 CSV を12個持っており、手作業でつなぎ合わせるのは非常に面倒です:

PYTHON
import pandas as pd

# 12個の別々のデータフレームを想像してください
jan = pd.DataFrame({'date': ['2024-01-15'], 'sales': [5000]})
feb = pd.DataFrame({'date': ['2024-02-20'], 'sales': [4500]})
mar = pd.DataFrame({'date': ['2024-03-10'], 'sales': [5200]})
# ... 残り9ヶ月分
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値は pandas のバージョンにより若干異なる場合があります。

(2) 解決策:concat で一括連結

▶ サンプル:concat による縦方向の連結(難易度 ⭐)

PYTHON
import pandas as pd

jan = pd.DataFrame({'date': ['2024-01-15'], 'sales': [5000]})
feb = pd.DataFrame({'date': ['2024-02-20'], 'sales': [4500]})
mar = pd.DataFrame({'date': ['2024-03-10'], 'sales': [5200]})

# 縦方向に積み重ねる(axis=0 がデフォルト)
year = pd.concat([jan, feb, mar], ignore_index=True)
print(year)
#          date  sales
# 0  2024-01-15   5000
# 1  2024-02-20   4500
# 2  2024-03-10   5200
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値は pandas のバージョンにより若干異なる場合があります。


3. concat の基本パラメータ

(1) 縦方向と横方向

▶ サンプル

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

:axis=0 と axis=1 の違い(難易度 ⭐)

PYTHON
import pandas as pd

df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [5, 6], 'B': [7, 8]})

# axis=0:行を積み重ねる(縦方向)
print("axis=0(縦方向):")
print(pd.concat([df1, df2], axis=0))
#    A  B
# 0  1  3
# 1  2  4
# 0  5  7  ← インデックスが重複!
# 1  6  8

# axis=1:列を並べる(横方向)
print("\naxis=1(横方向):")
print(pd.concat([df1, df2], axis=1))
#    A  B  A  B
# 0  1  3  5  7
# 1  2  4  6  8
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値は pandas のバージョンにより若干異なる場合があります。

(2) ignore_index によるインデックスの再構築

▶ サンプル

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

:ignore_index によるインデックスの再構築(難易度 ⭐)

PYTHON
import pandas as pd

df1 = pd.DataFrame({'A': [1, 2]})
df2 = pd.DataFrame({'A': [3, 4]})
df3 = pd.DataFrame({'A': [5, 6]})

# ignore_index なし — 元のインデックスが保持される(重複の可能性あり)
result1 = pd.concat([df1, df2, df3])
print(result1.index.tolist())  # [0, 1, 0, 1, 0, 1] — 重複!

# ignore_index あり — きれいな連番インデックス
result2 = pd.concat([df1, df2, df3], ignore_index=True)
print(result2.index.tolist())  # [0, 1, 2, 3, 4, 5] — きれい!
print(result2)
#    A
# 0  1
# 1  2
# 2  3
# 3  4
# 4  5
# 5  6
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値は pandas のバージョンにより若干異なる場合があります。


4. keys による多段階ラベル

(1) データソースのタグ付け

▶ サンプル

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

:keys によるソースのタグ付け(難易度 ⭐⭐)

PYTHON
import pandas as pd

q1 = pd.DataFrame({'sales': [100, 200, 300]})
q2 = pd.DataFrame({'sales': [150, 250, 350]})
q3 = pd.DataFrame({'sales': [180, 280, 380]})

# keys でマルチインデックスを作成 — 各行がどのデータフレーム由来か追跡可能
result = pd.concat([q1, q2, q3], keys=['Q1', 'Q2', 'Q3'])
print(result)
#       sales
# Q1 0    100
#    1    200
#    2    300
# Q2 0    150
#    1    250
#    2    350
# Q3 0    180
#    1    280
#    2    380

# キーで選択
print(result.loc['Q2'])
#    sales
# 0    150
# 1    250
# 2    350

# マルチインデックスの代わりにソース列を追加
result2 = pd.concat([q1, q2, q3], keys=['Q1', 'Q2', 'Q3'], names=['quarter'])
result2 = result2.reset_index(level=0)
print(result2)
#   quarter  sales
# 0      Q1    100
# 1      Q1    200
# ...
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値は pandas のバージョンにより若干異なる場合があります。


5. join による整合(アラインメント)戦略

(1) 列名が完全に一致しない場合

▶ サンプル

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

:join='outer' と 'inner' の違い(難易度 ⭐⭐)

PYTHON
import pandas as pd

df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]})
df2 = pd.DataFrame({'B': [7, 8], 'C': [9, 10], 'D': [11, 12]})

# join='outer'(デフォルト)— すべての列を保持し、欠損は NaN で埋める
print("outer:")
print(pd.concat([df1, df2], axis=0, join='outer'))
#      A    B    C     D
# 0  1.0    3    5   NaN
# 1  2.0    4    6   NaN
# 0  NaN    7    9  11.0
# 1  NaN    8   10  12.0

# join='inner' — 共通の列のみ保持
print("\ninner:")
print(pd.concat([df1, df2], axis=0, join='inner'))
#    B   C
# 0  3   5
# 1  4   6
# 0  7   9
# 1  8  10
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値は pandas のバージョンにより若干異なる場合があります。


6. concat と merge の比較

特徴 concat merge
操作 積み重ね(縦・横方向) 結合(キーによるマッチング)
キー 不要 on/left_on が必要
行数 元データの行数の合計(axis=0) 元データの行数の合計以下
列数 元データの列数の合計(axis=1) 元データの列の和集合
用途 同一構造のデータの積み重ね 異なる構造のデータの結合
典型シナリオ 12ヶ月分を年間テーブルに統合 ユーザー + 注文をキーで結合

▶ サンプル

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

:concat と merge の使い分け(難易度 ⭐⭐)

PYTHON
import pandas as pd

# concat を使う場合:同一構造を縦方向に積み重ねる
jan_sales = pd.DataFrame({'product': ['A', 'B'], 'sales': [100, 200]})
feb_sales = pd.DataFrame({'product': ['A', 'B'], 'sales': [150, 250]})
annual = pd.concat([jan_sales, feb_sales], keys=['Jan', 'Feb'])

# merge を使う場合:異なる構造をキーで連結する
products = pd.DataFrame({'product': ['A', 'B'], 'price': [10, 20]})
categories = pd.DataFrame({'product': ['A', 'B'], 'category': ['Electronics', 'Home']})
enriched = pd.merge(products, categories, on='product')
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値は pandas のバージョンにより若干異なる場合があります。


7. 総合例:複数ソースのデータ連結と分析

(5) ▶ concat の連結タイプ

100%
graph TB
    A[複数のデータフレーム] --> B{連結方向は?}
    B -->|縦方向 axis=0| C[行を上から下へ積み重ねる]
    B -->|横方向 axis=1| D[列を横に並べる]
    C --> E{列名は一致する?}
    E -->|はい| F[完全な連結]
    E -->|いいえ| G[join='outer' は NaN で埋める / join='inner' は共通部分のみ保持]
    D --> H{行インデックスは一致する?}
    H -->|はい| I[整合された連結]
    H -->|いいえ| J[NaN で相互補完]
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値は pandas のバージョンにより若干異なる場合があります。

▶ サンプル

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

:複数ソース連結の完全なワークフロー(難易度 ⭐⭐⭐)

PYTHON
import pandas as pd
import numpy as np

# ============================================
# 総合例:複数ソースの concat
# 3つの地域レポート → 年間分析
# ============================================

# 1. 地域別の月次レポート
np.random.seed(42)
regions = {
    'North': pd.DataFrame({
        'month': pd.date_range('2024-01', periods=6, freq='MS'),
        'sales': np.random.randint(3000, 8000, 6),
        'orders': np.random.randint(50, 150, 6)
    }),
    'South': pd.DataFrame({
        'month': pd.date_range('2024-01', periods=6, freq='MS'),
        'sales': np.random.randint(2000, 6000, 6),
        'orders': np.random.randint(30, 120, 6)
    }),
    'East': pd.DataFrame({
        'month': pd.date_range('2024-01', periods=6, freq='MS'),
        'sales': np.random.randint(1500, 5000, 6),
        'orders': np.random.randint(20, 100, 6)
    })
}

# 2. keys で地域をタグ付けして連結
all_data = pd.concat(regions, names=['region', 'idx'])
all_data = all_data.reset_index(level=0).reset_index(drop=True)
print(f"総行数: {len(all_data)}")

# 3. 派生列の追加
all_data['avg_order_value'] = (all_data['sales'] / all_data['orders']).round(2)

# 4. 地域別の分析
region_summary = all_data.groupby('region').agg(
    total_sales=('sales', 'sum'),
    total_orders=('orders', 'sum'),
    avg_monthly_sales=('sales', 'mean')
).round(0)
print("\n=== 地域別サマリー ===")
print(region_summary)

# 5. 全地域の月次トレンド
monthly = all_data.groupby('month')['sales'].sum()
print(f"\nピーク月: {monthly.idxmax().strftime('%Y-%m')}")
TEXT
> 出力: ローカルの Python 環境(pandas 2.x)で実行してください。Piston サーバーには pandas がプリインストールされていないため、ローカルにインストール(`pip install pandas`)してから実行してください。実際の値は pandas のバージョンにより若干異なる場合があります。

❓ よくある質問

Q concat と merge の違いは何ですか?
A concat はデータを積み重ねます — 行を縦方向に、列を横方向に連結し、マッチング用のキーは不要です。merge はデータを結合します — SQL の JOIN のように、キーを使って2つのテーブルの行をマッチングします。同一構造の複数テーブルを1つにまとめる → concat。異なる構造のテーブルを列で連結する → merge。目安:「同一構造なら concat で積み重ね、異なる構造なら merge で結合する」です。
Q axis=0 と axis=1 は何をしますか?
A axis=0(デフォルト)は行を縦方向に連結します — 上から下へ積み重ね、行数が増加します。axis=1 は列を横方向に連結します — 横に並べ、列数が増加します。縦方向の連結では列が自動整合され(欠損は NaN で埋められる)、横方向の連結では行が自動整合されます(欠損は NaN で埋められる)。
Q ignore_index はいつ使うべきですか?
A 縦方向の連結では、ほぼ常に ignore_index=True を指定すべきです — 連番のインデックスを再構築し、インデックスの重複([0,1,0,1,0,1])を回避します。元のインデックスに意味がある場合(日付インデックスなど)のみ保持します。横方向の連結では ignore_index は不要です(行の整合はインデックスに依存するため)。
Q なぜ append は非推奨になったのですか?
A df.append() は Pandas 1.4 で非推奨(deprecated)となり、2.0 で完全に削除されました。理由:append は呼び出しのたびに新しいオブジェクトを作成するため、ループ内では O(n²) のパフォーマンスになります。pd.concat はすべてを一度に連結するため O(n) です。代替:pd.concat([df1, df2])。ループで追加する場合:まずリストに集め、最後に一度だけ concat してください。
Q 列名が異なる場合はどうなりますか?
A 縦方向の連結では、一致しない列名は NaN を生みます — 同じ名前の列のみデータが統合されます。解決策:① 連結前に列名を rename で統一する;② join='inner' で共通の列のみ保持する;③ 連結後に NaN 列を手動で処理する。ベストプラクティス:concat を呼び出す前に列名を統一することです。
Q concat のパフォーマンスを最適化するには?
A ループ内で concat を繰り返し呼び出すのは避けてください — 呼び出しのたびに新しいデータフレームが作成されます。正しい方法:すべてのデータフレームをリストに集め、一度だけ concat します。frames = [df1, df2, ..., df100]; result = pd.concat(frames)。これにより、ループベースの追加と比べて O(n) と O(n²) の差が生まれます。
Q verify_integrity は何をしますか?
A verify_integrity=True は連結後のインデックスに重複がないかチェックし、重複があれば ValueError を発生させます。データの整合性を保証するために使用します — 例えば、一意の ID が2回現れてはいけない場合などです。ただし、チェックにはパフォーマンスコストがあるため、大規模データではスキップしてください。日常的な用途では ignore_index=True の方がシンプルです。

📖 まとめ


📝 練習問題

  1. 基礎(難易度 ⭐):同一構造のデータフレームを3つ作成し(Q1/Q2/Q3 の売上データ)、concat で縦方向に連結(ignore_index=True)して、売上の合計を計算してください。
  2. 応用(難易度 ⭐⭐):列名が一部異なるデータフレームを2つ作成し、それぞれ join='outer' と join='inner' で連結して、列の違いを比較してください。
  3. 挑戦(難易度 ⭐⭐⭐):4つの地域について6ヶ月分のデータをシミュレートし、concat(keys=regions) で連結 → reset_index で整理 → 地域別の合計を計算 → 月次トレンドを確認してください。

← 前へ:Merge と Join · 次へ:リシェイプとピボット →

Web-Tutorial.com

Web-Tutorial 技術チーム

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

100%