PandasとSQL:適切なツールの選択
Pandasのgroupby/mergeとSQLのGROUP BY/JOINを比較し、それぞれの変換処理をどの層で行うべきか判断します。
「PandasとSQL:適切なツールの選択」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。
2 つのツール、それぞれの強みを活かす
Pandas と SQL はどちらもデータ操作のためのツールであり、プロのデータアナリストに利用されています。重要なポイントは、両者が競合するのではなく、相互補完的だということです。SQL はリレーショナルデータベースに保存された大規模なテーブルに対する宣言型の集合演算を得意とし、Pandas はメモリに読み込まれたデータに対する命令型の行単位処理や複雑なアルゴリズム変換を得意とします。優れたパイプラインでは、それぞれのツールが最も得意とする処理を任せます。
SQL の強み:SQL が得意なこと
一般に、次のような場合は SQL のほうが優れています。データが大規模(ギガバイト~テラバイト)で、読み込み前にフィルタリングする必要がある場合、複数の大規模テーブルにまたがる結合でデータベースのインデックスによる桁違いの高速化が得られる場合、集計が単純(SUM、COUNT、GROUP BY)な場合、入力に対して結果セットが小さい場合、または同時読み取り/書き込みが必要な場合です(データベースがトランザクションとロックを処理します)。また、SQL の宣言型構文を使うと、クエリオプティマイザが最適な物理実行計画を自動的に選択できます。
-- SQL excels at:
-- 1. Filtering billions of rows using an index
SELECT * FROM orders WHERE customer_id = 12345;
-- 2. Joining large tables efficiently
SELECT o.order_id, c.name, SUM(o.amount)
FROM orders o
JOIN customers c ON o.customer_id = c.id
GROUP BY o.order_id, c.name;
-- 3. Window functions on ordered data
SELECT order_id, amount,
SUM(amount) OVER (PARTITION BY customer_id ORDER BY order_date)
FROM orders;Pandas の強み:Pandas が得意なこと
一般に、次のような場合は Pandas のほうが優れています。SQL では表現できないカスタム Python ロジック(機械学習の前処理、独自の文字列解析、複雑なアルゴリズム)が必要な場合、データ変換の連鎖が多段階に及ぶ場合、分析直後に可視化したい場合、データがすでにメモリ上にあるため SQL との追加の往復が遅延を生む場合、または対話的に試行したい探索的分析を行う場合です。Pandas は、行列計算や時系列の平滑化など、表形式ではない操作にも対応します。
import pandas as pd
# Pandas excels at:
# 1. Custom Python logic that SQL cannot express
df['clean_name'] = df['name'].str.strip().str.title().str.replace(r'[^a-zA-Z ]', '', regex=True)
# 2. Vectorised string parsing
df[['first', 'last']] = df['full_name'].str.split(' ', n=1, expand=True)
# 3. Rolling statistics and time series
df['7day_avg'] = df['daily_sales'].rolling(7).mean()
# 4. Direct visualisation
# df.groupby('category')['sales'].sum().plot(kind='bar')SQL の操作を Pandas に対応付ける
ほとんどの SQL 操作には、Pandas に直接対応する機能があります。両方の構文を知っていると応用力が高まり、ツールを切り替える際にも相互に変換しやすくなります。WHERE はブールインデックスまたは .query() に、GROUP BY + SUM は .groupby().sum() に、JOIN は pd.merge() に、ORDER BY は .sort_values() に、DISTINCT は .drop_duplicates() に相当します。意味は同じで、構文だけが異なります。
import pandas as pd
df = pd.DataFrame({'region': ['N','S','N','E'], 'amount': [100,200,150,300]})
# SQL: SELECT region, SUM(amount) FROM df WHERE amount>100 GROUP BY region ORDER BY region
# Pandas:
result = (
df[df['amount'] > 100]
.groupby('region')['amount']
.sum()
.reset_index()
.sort_values('region')
)
print(result)データ量で選択が決まる場合
データ量に基づく実用的な判断基準は次のとおりです。100 MB 未満:すべて Pandas を使用します。SQL のオーバーヘッドに見合いません。100 MB~10 GB:SQL でフィルタリングと集計を行い、概要の DataFrame を Pandas に読み込みます。10 GB~1 TB:SQL または Dask で処理し、Pandas は最終的な集計にのみ使用します。1 TB 超:分散 SQL(BigQuery、Spark SQL、Redshift)を使用します。16 GB のノートパソコンで 100 GB のテーブルを Pandas に読み込もうとしてはいけません。クラッシュするか、ディスクのスラッシングが発生します。
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///large.db')
# Right approach: SQL handles the heavy lifting
summary_df = pd.read_sql_query(
'''
SELECT region, product_category,
SUM(revenue) AS total_revenue,
COUNT(DISTINCT customer_id) AS unique_customers
FROM orders
WHERE order_date >= '2024-01-01'
GROUP BY region, product_category
''',
con=engine
)
# summary_df is small — now do Pandas things on it
print(summary_df.sort_values('total_revenue', ascending=False))SQL のウィンドウ関数と Pandas のローリング処理
SQLのウィンドウ関数(OVER (PARTITION BY ... ORDER BY ...))は強力ですが、制限もあります。累積順位、前後の値の取得、単純な移動集計は得意ですが、複雑な移動統計(例:移動ピアソン相関)はSQLでは表現できません。Pandasのrolling()とexpanding()は、.apply()によるカスタム関数も含め、はるかに幅広いウィンドウ計算に対応しています。大規模データで標準的なウィンドウ関数を使う場合はSQLを、複雑なウィンドウ処理にはPandasを優先してください。
import pandas as pd
df = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=30),
'sales': [100 + i*10 + (i%7)*20 for i in range(30)]
})
# Pandas rolling — easy with arbitrary window functions
df['7d_mean'] = df['sales'].rolling(7).mean()
df['7d_std'] = df['sales'].rolling(7).std()
df['7d_corr'] = df['sales'].rolling(7).corr(df['sales'].shift(1))
print(df.tail())複雑な結合:Pandasの柔軟性
SQLの結合は、基本的にキーの等価性に基づきます(一部例外があります)。Pandasのpd.merge_asof()は時間に基づくあいまい結合に対応しており、キーが完全に一致するのではなく最も近いキーを照合できます。これは時系列の整列に非常に便利です(例:直前の株価と取引イベントを結合する場合)。Pandasでは、mergeの後にフィルタリングすることで条件付き結合も実行できますが、SQLで同じ処理を表現するにはサブクエリまたはLATERAL結合が必要です。このような高度な結合パターンは、Pandasが明らかに優れている分野の一つです。
import pandas as pd
trades = pd.DataFrame({
'time': pd.to_datetime(['2024-01-01 10:00', '2024-01-01 10:05', '2024-01-01 10:12']),
'symbol': ['AAPL', 'AAPL', 'AAPL'],
'shares': [100, 200, 50]
})
prices = pd.DataFrame({
'time': pd.to_datetime(['2024-01-01 10:00', '2024-01-01 10:10']),
'price': [185.0, 186.5]
})
# Fuzzy join: match each trade to the nearest preceding price
result = pd.merge_asof(trades.sort_values('time'),
prices.sort_values('time'),
on='time', direction='backward')
print(result)データプロファイリングにはPandas、本番環境にはSQL
よくあるワークフローは、まず代表的なサンプル(例:先頭100万行)に対してEDAとデータプロファイリングをPandasで行い、変換ロジックを反復的に開発してから、主要な処理を本番規模向けのSQLに変換する方法です。Pandasでは、結果をすぐに視覚的に確認しながら迅速に反復できます。一方、SQLは最小限のインフラで大規模な処理を安定して実行できます。両者の処理内容は常に同期させてください。Pandasで新しい特徴量を追加したら、本番環境用に同等のSQLストアドプロシージャまたはビューを作成します。
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///data.db')
# Development: sample in Pandas for fast iteration
df_sample = pd.read_sql_query(
'SELECT * FROM orders ORDER BY RANDOM() LIMIT 10000',
con=engine
)
# Explore and prototype:
df_sample['revenue_tier'] = pd.cut(
df_sample['amount'],
bins=[0, 100, 500, float('inf')],
labels=['low', 'mid', 'high']
)
print(df_sample['revenue_tier'].value_counts())
# Production: translate cut logic to SQL CASE WHENpandasql:DataFrameに対するSQLの記述
pandasqlライブラリを使うと、内部でSQLiteを利用してPandasのDataFrameに対するSQLクエリを直接記述できます。sqldf('SELECT * FROM df WHERE amount > 100', locals())は、df DataFrameに対してクエリを実行します。SQLで考えるほうが得意でもデータがすでにPandasにある場合や、インメモリデータを使ってSQLの概念を教える場合に便利です。ただし、ほとんどの処理ではネイティブなPandasより遅いため、パフォーマンスではなく使い慣れたSQLを利用する目的で使ってください。
# pip install pandasql
import pandas as pd
# from pandasql import sqldf
df = pd.DataFrame({
'product': ['A', 'B', 'A', 'C', 'B'],
'sales': [100, 200, 150, 80, 220]
})
# With pandasql (commented out as it requires install):
# result = sqldf('SELECT product, SUM(sales) AS total FROM df GROUP BY product', locals())
# Equivalent native Pandas:
result = df.groupby('product')['sales'].sum().reset_index()
print(result)判断の指針:クイックリファレンス
SQLとPandasのどちらを使うか迷ったときは、次の指針を利用してください:
- データがデータベースにあり、しかも大規模ですか?まずSQLでフィルタリングと集計を行います。
- カスタムのPythonロジックが必要ですか?SQLで事前にフィルタリングしてからPandasを使います。
- サンプルに対して探索的分析を行いますか?Pandasならより速く反復できます。
- 複雑な移動統計を含む時系列ですか?Pandasのrolling/ewmを使います。
- 数百万行に対する単純なGROUP BYですか?インデックスを利用したSQLを使います。
- 複数の小さなDataFrameがすでにメモリ上にありますか?pd.merge()で問題ありません。
- ACIDトランザクションが必要ですか?PandasではなくSQLデータベースを使います。
両者の組み合わせ:ハイブリッドパイプライン
最も実用的な方法は、それぞれのツールの強みを生かすハイブリッドパイプラインです。SQLで、大規模な未加工テーブルに対する取り込み、大まかなフィルタリング、標準的な集計を処理します。その出力である扱いやすいDataFrameをPandasに渡し、特徴量エンジニアリング、カスタム指標、移動統計、可視化を行います。必要に応じて、結果をデータベースに書き戻して提供用に利用します。このパイプラインは読みやすく、拡張性と保守性に優れており、SQLとPythonの両方を知っている分析担当者なら誰でも扱えます。
import pandas as pd
import sqlalchemy as sa
engine = sa.create_engine('sqlite:///pipeline.db')
# Step 1: SQL coarse aggregation
df = pd.read_sql_query('''
SELECT DATE(order_date) AS date, region, SUM(amount) AS daily_revenue
FROM orders WHERE status = 'completed'
GROUP BY DATE(order_date), region
ORDER BY date
''', con=engine, parse_dates=['date'])
# Step 2: Pandas rolling and pivoting (hard in SQL)
df['7d_avg'] = df.groupby('region')['daily_revenue'].transform(
lambda x: x.rolling(7, min_periods=1).mean()
)
pivot = df.pivot(index='date', columns='region', values='7d_avg')
print(pivot.tail())クイックチェック
このレッスンで学んだデータ分析の概念について、理解度を確認しましょう。
レッスンのまとめ
このレッスンでは、SQLはインデックス付きデータの大規模なフィルタリング、結合、単純な集計に優れており、PandasはカスタムのPythonロジック、複雑な移動統計、探索的分析に優れていることを学びました。最適な戦略は、SQLでデータを大まかに絞り込み、扱いやすくなった結果に対してPandasで複雑な変換を行うハイブリッドパイプラインです。次はSciPyを使った推測統計として、正規性の検定と記述統計を始めます。
AI チューターと学ぶ Python — 無料
ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。
- コース
- 30
- レッスン
- 120
よくある質問
「PandasとSQL:適切なツールの選択」レッスンは無料ですか?
はい。「PandasとSQL:適切なツールの選択」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。
「PandasとSQL:適切なツールの選択」で何を学びますか?
Pandasのgroupby/mergeとSQLのGROUP BY/JOINを比較し、それぞれの変換処理をどの層で行うべきか判断します。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Pandas & NumPy Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「PandasとSQL:適切なツールの選択」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このPandas & NumPy Academyレッスンでコードを書いて実行できますか?
はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- SQLAlchemyによるデータベース接続
- PandasからのSQLクエリ実行
- DataFrameのデータベーステーブルへの書き込み
- PandasとSQL:適切なツールの選択