DuckDBをR・Pythonで使う【duckplyrも】

軽量・高速な組み込み型データベースDuckDBの使い方を、RとPythonの両方で解説します。

R
Python
SQL
データ処理
公開

2025年9月19日

最終更新

2026年2月1日

はじめに

大量のデータを扱う際、メモリ制限やパフォーマンスの問題に直面することがあります。そんなとき便利なのが、軽量で高速な組み込み型データベース DuckDB です。本記事では、RとPythonの両方でDuckDBを使う方法を体系的に解説します。

DuckDBとは

DuckDBは、組み込み型のSQLデータベースであり、特に分析ワークロードに最適化されています。SQLiteのように軽量でありながら、大規模なデータセットを効率的に処理できる点が特徴です。

組み込み型データベースとは、アプリケーションに組み込まれて動作するデータベースのことです。PostgreSQLなどのサーバー型とは異なり、外部のデータベースサーバーを必要とせず、R/Python上で完結します。

また、DuckDBは列指向ストレージを採用しています。データを行ではなく列ごとに格納するため、特定の列に対するクエリが高速に処理されます。列指向については、以下の記事でも触れています。

Parquetファイルについて調べてみる
ファイルサイズを小さくできるということだけは知っているが…
yo5uke.com

インストール

duckdbパッケージをインストールします。

# install.packages("pak")
pak::pak("duckdb")

もしくは

install.packages("duckdb")

duckdbパッケージをインストールします。

# pipを使用する場合
pip install duckdb

# uvを使用する場合
uv add duckdb

uvについては以下の記事をご参照ください。

Preview image for 【renv】仮想環境を設定する【venv】
【renv】仮想環境を設定する【venv】
Rは[renv]{.fira-code}、Pythonは[venv]{.fira-code}を使います。注目のuvも紹介!
yo5uke.com

基本的な使い方

データベースへの接続

DuckDBにはメモリ内データベース永続データベースの2種類があります。

  • メモリ内データベース: セッション終了時にデータが消去される。一時的な分析に便利。
  • 永続データベース: .duckdbファイルにデータが保存され、セッションを跨いで再利用できる。
library(duckdb)
# メモリ内データベースに接続
con <- dbConnect(duckdb())
# 永続データベースに接続
con <- dbConnect(duckdb(), dbdir = here::here("data/iris.duckdb"))

永続データベースの場合、指定したパスに.duckdbファイルが作成されます。

import duckdb

# メモリ内データベースに接続
con = duckdb.connect()

# 永続データベースに接続する場合
con = duckdb.connect('data/iris.duckdb')

データの読み込み

DuckDBはCSVやParquetなど、様々なデータ形式を直接読み込めます。ここではCSVファイルの読み込みを例に紹介します。

SQLで読み込む

dbExecute(con, "CREATE TABLE iris AS SELECT * FROM read_csv('data/iris.csv')")
con.sql("CREATE TABLE iris AS SELECT * FROM read_csv('data/iris.csv')")

このSQL文は、read_csv('data/iris.csv')から全列(*)を選択し、irisという名前のテーブルを作成しています。

この方法のメリットは、R/Pythonに一度もデータを読み込まずに、DuckDBが直接ファイルを処理できる点です。R/Pythonに読み込まれるのはクエリの結果だけなので、メモリ消費を抑えられます。また、CREATE TABLE ... AS SELECT ...構文で、列の選択やフィルタリングなどの前処理を行いながらテーブルを作成できます。

dplyrで読み込む(R限定)

SQLになじみがない方向けに、Rではdplyrを使ったデータベース操作も可能です。dplyrで書いたコードが裏でSQLに変換・実行されます。

library(tidyverse)
# Rでデータを読み込み、DuckDBに登録
iris_data <- read_csv(here::here("data/iris.csv"))
duckdb_register(con, iris, "iris_data")

duckdb_register()は、RのデータフレームをDuckDB上のテーブルとして登録します。これをすると、dbGetQuery()tbl()irisテーブルを参照できるようになります。

永続データベースに書き込みたい場合は、代わりにdbWriteTable()を使います。

dbWriteTable(con, "iris", iris_data)

永続データベースに書き込めば、1つの.duckdbファイルに複数のテーブルを保存でき、後で再利用できます。

Note

SQLで直接ファイルを読む方法とは異なり、dplyr経由では一度Rにデータを読み込んでからデータベースに登録するため、大きなデータではメモリ消費が増える点に注意してください。

なお、データベースにはテーブルを複数作成できるので、iris以外のデータも好きな名前で追加できます1

遅延評価について

データベースを使うメリットのひとつに、遅延評価(lazy evaluation)があります。通常のデータ処理では書いた順に即座に実行されますが、DuckDBでは処理を記録しておき、最後にまとめて実行します。

通常:データ読み込み → 処理を即実行 → 結果を返す
遅延評価:データ読み込み → 処理を記録 → まとめて実行(SQL発行)→ 結果を返す

このおかげで不要な計算が省かれ、大規模データでも効率的に処理できます。

データの操作

SQLで操作する

result <- dbGetQuery(con, "SELECT * FROM iris WHERE Species = 'setosa'")
result = con.sql("SELECT * FROM iris WHERE Species = 'setosa'")

この例では、irisテーブルからSpeciessetosaの行を取得しています。

dplyrで操作する(R限定)

result <- tbl(con, "iris") |>
  filter(Species == "setosa") |>
  collect()

tbl(con, "iris")でデータベース上のテーブルを参照し、filter()などおなじみのdplyr関数で操作できます。

ここで重要なのは、collect()を呼び出すまではSQLが実行されないという点です。filter()などの処理を重ねるたびに裏でSQLクエリが組み立てられ、collect()で初めて実行されます。つまり、collect()の前まではデータはRに読み込まれず、「SQLを組み立てているだけ」の状態です。

データベースになじみがない方にとっては少し不思議かもしれませんが、conはデータそのものではなく、データベースへの接続(窓口)を表すオブジェクトです。この窓口を通してテーブルを参照し、最終的にcollect()で結果を手元に取り込む、という流れになります。

テーブルの削除

# テーブルを削除
dbExecute(con, "DROP TABLE iris")

# テーブルが存在しない場合でもエラーにならない書き方
dbExecute(con, "DROP TABLE IF EXISTS iris")
# テーブルを削除
con.sql("DROP TABLE iris")

# テーブルが存在しない場合でもエラーにならない書き方
con.sql("DROP TABLE IF EXISTS iris")

データベースからの切断

操作が終わったら、接続を切断します。

dbDisconnect(con, shutdown = TRUE)

shutdown = TRUEを指定すると、メモリ内データベースの場合はデータが消去され、ファイルベースの場合は接続が閉じられます。

con.close()

{duckplyr}を使う(R限定)

ここまではDuckDBをデータベースとして使う方法を紹介してきましたが、Rにはduckplyrというもうひとつのアプローチがあります。

duckplyrとは

duckplyrは、dplyrのドロップイン置き換えとして機能するパッケージです。library(duckplyr)するだけで、既存のdplyrコードがそのまま動きながら、裏側でDuckDBの高速な分析エンジンが使われます。

duckdbパッケージとの違い

duckdb + dbplyr duckplyr
データベース接続 必要 不要
データの場所 DB上(collect()でRへ) Rのメモリ上
仕組み dplyr → SQL翻訳 → DuckDB実行 Rのデータを直接DuckDBエンジンで処理
用途 大規模データのDB管理・分析 メモリ内データの高速化

duckdb + dbplyr は、データベースに接続してSQLベースで処理する方法(前のセクションで紹介)、duckplyr は、データベースを意識せずに、普段のdplyrコードをそのまま高速化する方法です。

duckplyrの特徴

  1. ドロップイン置き換え: library(duckplyr)するだけで、多くのdplyr動詞が高速化される
  2. 自動フォールバック: 対応できない操作は自動的に通常のdplyrにフォールバックするため、エラーで止まらない
  3. 大規模データに最適: DuckDBの並列処理エンジンとメモリ効率の良い処理を活用
  4. 互換性: tidyverseエコシステムとシームレスに連携

使用例

library(tidyverse)
library(duckplyr)
#> Loading required package: dplyr
#> ✔ Overwriting dplyr methods with duckplyr methods.
#> ℹ Turn off with `duckplyr::methods_restore()`.

# 通常のdplyr構文がそのまま使えます
mtcars |>
  group_by(cyl) |>
  summarise(
    mean_mpg = mean(mpg),
    mean_hp = mean(hp),
    .groups = "drop"
  )
# A tibble: 3 × 3
    cyl mean_mpg mean_hp
  <dbl>    <dbl>   <dbl>
1     4     26.7    82.6
2     6     19.7   122. 
3     8     15.1   209. 
Important

読み込み順序が重要です。 library(tidyverse)の後にlibrary(duckplyr)を読み込んでください。逆の順序だと、通常のdplyrが優先されてしまいます。

小さいデータだと速さを実感しにくいかもしれませんが、大きいデータを扱うときに効果を発揮します。

まとめ

DuckDBは軽量で高速な組み込み型データベースであり、R/Python上で手軽に大規模データを扱えます。

  • SQLで直接ファイルを読み込み・操作する方法が、最もメモリ効率が良い
  • Rではdplyrを使ったデータベース操作も可能で、SQLに不慣れでも扱いやすい
  • さらにRではduckplyrを使えば、既存のdplyrコードをほぼそのまま高速化できる

ぜひお試しあれ。

参考

Preview image for Documentation
Documentation
Connecting to DuckDB DuckDB connection overview Client APIs C C++ CLI (command line interface) Go Java (JDBC) Node.js ODBC Python R Rust WebAssembly All client APIs SQL Introduction Statements Other Guides Installation Building DuckDB Browsing offline
duckdb.org

  1. とはいえ、プロジェクトごとなどで.duckdbは分けた方が良いとは思います。↩︎