mcpField
D
duckdb

duckdb

github.com/tondevrelデータ・データベース2467 回インストール39 週間前に更新
リポジトリ

duckdb について

DuckDB は、Python のデータサイエンス向けインプロセス分析 SQL エンジンです。大規模なローカルデータを扱う分析者や研究者に適し、CSV、Parquet、Python のデータフレームを直接処理し、メモリまたはファイルに保存できます。

主な機能

  1. 01インプロセス SQL 分析実行
  2. 02CSV と Parquet の直接クエリ
  3. 03Pandas と Polars データのクエリ
  4. 04複数データソースの結合
  5. 05ウィンドウ関数と集計
  6. 06メモリまたはファイルでの保存

活用シーン

  1. 01大規模な CSV や Parquet ファイルの分析
  2. 02ファイルデータと Pandas DataFrame の結合
  3. 03SQL によるデータ整形と集計の構築
  4. 04機械学習向け特徴量の生成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/tondevrel/scientific-agent-skills --skill duckdb

インストール後、Claude Code で/duckdbを入力して読み込まれたか確認します。

詳細

DuckDB — 科学データのための SQL エンジン

DuckDB は、Python のデータサイエンススタックにプロフェッショナルな SQL の力をもたらします。「オンライン分析処理」(OLAP)向けに最適化されており、メモリよりも大きなデータセットに対する大規模な集計、結合、複雑なクエリを得意とします。

使用する場面

  • Pandas または Polars のデータに対して、複雑な SQL クエリ(JOIN、ウィンドウ関数)を実行する場合。
  • 大きな Parquet ファイルや CSV ファイルをメモリに読み込まずに直接クエリする場合。
  • 異なるソース(例:CSV ファイルと Pandas DataFrame)のデータを効率的に結合する場合。
  • SQL のほうが DataFrame のコードより簡潔または高速な分析パイプラインを構築する場合。
  • Excel では扱いきれないものの、PostgreSQL サーバーを丸ごと用意する必要はないローカルデータセットを管理する場合。
  • 機械学習のための中間データ保存や特徴量エンジニアリングを行う場合。

リファレンスドキュメント

公式ドキュメント: https://duckdb.org/docs/
Python API: https://duckdb.org/docs/api/python/overview
検索パターン: duckdb.sql、duckdb.query、duckdb.read_parquet、duckdb.from_df

基本原則

プロセス内実行

DuckDB は Python プロセス内で動作します。起動や管理が必要なサーバーはありません。データはファイル(.db)に保存することも、すべてメモリ内に保持することもできます。

列指向エンジン

Polars と同様に、DuckDB は列指向ストレージとベクトル化実行エンジンを使用しており、分析タスクでは行ベースのデータベース(SQLite など)より桁違いに高速です。

シームレスな相互運用性

DuckDB は Python の変数を「認識」できます。データベース内のテーブルであるかのように、Pandas DataFrame の変数に対して SQL クエリを直接実行できます。

クイックリファレンス

インストール
pip install duckdb
標準インポート
import duckdb
import pandas as pd
import numpy as np
基本パターン — Python データのクエリ
import duckdb
import pandas as pd

# 1. Create a sample DataFrame
df = pd.DataFrame({"id": [1, 2, 3], "val": [10.5, 20.0, 15.2]})

# 2. Query the DataFrame directly via SQL
# DuckDB automatically finds the 'df' variable in the local scope
result_df = duckdb.sql("SELECT id, val * 2 AS doubled FROM df WHERE val > 12").df()

print(result_df)

重要なルール

✅ 推奨事項
  • ファイルを直接クエリする — ファイルを先に読み込むのではなく、SELECT * FROM 'data.parquet' を使用します。DuckDB は必要な列と行だけを読み込みます。
  • .df()、.pl()、.arrow() メソッドを使用する — クエリ結果を好みの形式(Pandas、Polars、Arrow)に効率よく変換できます。
  • 大きなデータには永続ストレージを使用する — スクリプトの実行間でデータを保持したい場合は、duckdb.connect('my_data.db') を使用します。
  • Parquet を活用する — DuckDB は Parquet ファイルに最適なエンジンです。最大限の速度を得るために活用しましょう。
  • ワイルドカードを使用する — FROM 'data/*.parquet' を使って、何千ものファイルを一度にクエリできます。
  • EXPLAIN を使用する — クエリの前に EXPLAIN ANALYZE を付けると、DuckDB によるクエリの実行方法を確認し、ボトルネックを特定できます。
❌ 避けるべきこと
  • 高頻度の書き込み(OLTP)に使用する — DuckDB は分析向けです。1 秒間に何千回も行を 1 つずつ挿入する必要がある場合は、SQLite または PostgreSQL を使用してください。
  • 接続を放置する — ファイルベースのデータベースを使用する場合は、ファイルロックを避けるため、接続を閉じるかコンテキストマネージャーを使用してください。
  • 不要な CSV の手動読み込み — pd.read_csv() で読み込んでからクエリするのは避けてください。パフォーマンスを高めるには、ファイルパスを直接クエリします。

アンチパターン(絶対に避けること)

import duckdb
import pandas as pd

# ❌ BAD: Loading everything into Pandas just to do a simple filter
# df = pd.read_csv("massive.csv") 
# result = df[df['val'] > 100]

# ✅ GOOD: Let DuckDB filter while reading (saves RAM)
result = duckdb.sql("SELECT * FROM 'massive.csv' WHERE val > 100").df()

# ❌ BAD: Manual string formatting for SQL queries (SQL Injection risk)
# duckdb.sql(f"SELECT * FROM data WHERE name = '{user_input}'")

# ✅ GOOD: Use prepared statements or parameters
duckdb.execute("SELECT * FROM data WHERE name = ?", [user_input]).df()

# ❌ BAD: Re-reading the same file in a loop
# for i in range(10): 
#    res = duckdb.sql("SELECT mean(val) FROM 'large.parquet'").df()

# ✅ GOOD: Create a VIEW or TABLE first
duckdb.sql("CREATE VIEW data_view AS SELECT * FROM 'large.parquet'")
for i in range(10):
    res = duckdb.sql("SELECT mean(val) FROM data_view").df()

SQL の機能と操作

異なるソースへのクエリ
# Query a CSV
res_csv = duckdb.sql("SELECT * FROM read_csv_auto('data.csv')").df()

# Query a Parquet file
res_pq = duckdb.sql("SELECT * FROM 'data.parquet' WHERE price > 50").df()

# Query multiple Parquet files and join with a Pandas DF
df_metadata = pd.DataFrame(...)
query = """
    SELECT p.*, m.category 
    FROM 'raw_data/*.parquet' p
    JOIN df_metadata m ON p.id = m.id
    LIMIT 10
"""
res = duckdb.sql(query).df()
リレーショナル API(プログラムによる SQL)

生の SQL より Python らしいメソッドチェーン形式を使いたい場合:

rel = duckdb.from_df(df)
res = rel.filter("val > 15").project("id, val * 2").order("val").limit(5)
print(res.df())
高度な SQL:ウィンドウ関数と集計

DuckDB は最新の SQL を完全にサポートしており、複雑な統計処理では Pandas より簡単な場合がよくあります。

query = """
    SELECT 
        date,
        station_id,
        temp,
        AVG(temp) OVER (PARTITION BY station_id ORDER BY date ROWS BETWEEN 7 PRECEDING AND CURRENT ROW) as rolling_7d_avg,
        temp - LAG(temp) OVER (PARTITION BY station_id ORDER BY date) as daily_change
    FROM 'weather_data.parquet'
"""
df_stats = duckdb.sql(query).df()
永続データベースの操作
# Create or open a database file
con = duckdb.connect('scientific_project.db')

# Create a table from a dataframe
con.execute("CREATE TABLE experiment_results AS SELECT * FROM df")

# Check tables
print(con.execute("SHOW TABLES").df())

# Close connection
con.close()

パフォーマンスの最適化

1. 外部集計(ディスクへのスピル)

クエリが RAM に収まらない場合、DuckDB は計算を完了するためにデータを「ディスクにスピル」できます。

# Enable temp directory for large queries
duckdb.sql("SET temp_directory='/tmp/duckdb_temp/'")
duckdb.sql("SET max_memory='4GB'") # Limit RAM usage
2. 並列処理

DuckDB はデフォルトで並列処理を行います。スレッド数は調整できます。

duckdb.sql("SET threads TO 8")
3. 探索的分析のためのサンプリング

巨大なファイルのサンプルをクエリすれば、瞬時に結果を得られます。

# Random 10% sample
df_sample = duckdb.sql("SELECT * FROM 'huge.parquet' USING SAMPLE 10%").df()

実践的なワークフロー

1. 「ビッグデータ」のクリーニングパイプライン
def process_experiment_logs(glob_pattern):
    """Clean and aggregate TBs of log data across many files."""
    query = f"""
    WITH clean_data AS (
        SELECT 
            timestamp::TIMESTAMP as ts,
            sensor_id,
            value
        FROM read_csv_auto('{glob_pattern}')
        WHERE value IS NOT NULL AND value != -999
    )
    SELECT 
        time_bucket(INTERVAL '1 hour', ts) as hour,
        sensor_id,
        AVG(value) as avg_val
    FROM clean_data
    GROUP BY 1, 2
    ORDER BY 1, 2
    """
    return duckdb.sql(query).df()
2. ML 向けの高速な特徴量エンジニアリング
def create_features(df_train):
    # Use SQL to create complex lag and moving average features
    return duckdb.sql("""
        SELECT *,
               AVG(price) OVER (PARTITION BY item ORDER BY date ROWS 3 PRECEDING) as ma3,
               COUNT(*) OVER (PARTITION BY user) as user_activity_count
        FROM df_train
    """).df()
3. 相互運用:DuckDB から PyTorch/TensorFlow へ
# Query data and convert to Arrow for zero-copy transfer to Deep Learning
arrow_table = duckdb.sql("SELECT * FROM 'data.parquet'").arrow()

# Then in PyTorch (requires torch.utils.dlpack or similar)
# Or just use the fast arrow-to-numpy/tensor path

よくある問題と解決策

「変数が見つかりません」エラー

DuckDB は、duckdb.sql() が呼び出されたスコープ内で変数を探します。

# ✅ Solution: If calling inside a function, ensure the variable is local or passed
def my_query(my_df):
    return duckdb.sql("SELECT * FROM my_df").df()
データベースファイルがロックされる

2 つのプロセスが同じ .db ファイルを「書き込み」モードで開こうとすると、失敗します。

# ✅ Solution: Open as read-only for secondary processes
con = duckdb.connect('data.db', read_only=True)
日付/時刻の解析

CSV では、形式が不規則な日付がよく使われています。

# ✅ Solution: Use strptime or let DuckDB auto-detect
# SELECT strptime(date_col, '%d/%m/%Y') FROM 'data.csv'

ベストプラクティス

  1. ファイルを直接クエリする - まずメモリに読み込むのではなく、SELECT * FROM 'file.parquet' を使用します。
  2. 適切な出力形式を使用する - Pandas には .df()、Polars には .pl()、Arrow には .arrow() を使用します。
  3. 繰り返し実行するクエリにはビューを作成する - 同じファイルを何度も読み込まないようにします。
  4. プリペアドステートメントを使用する - SQL インジェクションを防ぎ、繰り返し実行するクエリのパフォーマンスを向上させます。
  5. Parquet 形式を活用する - DuckDB は Parquet に優れているため、最高のパフォーマンスを得るには Parquet を使用します。
  6. 複数のファイルにはワイルドカードを使用する - FROM 'data/*.parquet' を使って、一度に多数のファイルをクエリします。
  7. 大規模なクエリではディスクへのスピルを有効にする - メモリ不足時の処理に備えて、temp_directory と max_memory を設定します。
  8. EXPLAIN ANALYZE を使用する - クエリの実行状況を把握し、ボトルネックを特定します。
  9. 接続を適切に閉じる - コンテキストマネージャーを使用するか、ファイルベースの接続を明示的に閉じます。
  10. 複雑な集計には SQL を優先する - ウィンドウ関数や複雑な結合は、DataFrame コードよりも SQL のほうが分かりやすいことがよくあります。

DuckDB は、SQL の分析能力と Python の柔軟性をつなぐ架け橋です。「データ読み込みのコスト」をなくし、科学者がデータに対する複雑な問いに超高速で取り組めるようにします。

コメント