Skip to content

与 pandas 进行交互

DuckDB 与 Python 生态的pandas 提供了交互,即运行直接在 DataFrame 上进行 SQL 查询

Python
import duckdb
import pandas

# Create a Pandas dataframe
my_df = pandas.DataFrame.from_dict({"a": [42]})

# query the Pandas DataFrame "my_df"
# Note: duckdb.sql connects to the default in-memory database connection
duckdb.sql("SELECT * FROM my_df").df()

    a
------
0   42

从 DataFrame 导入

DataFrame 可以直接作为虚拟视图在 SQL 语句中使用:

Python
import duckdb
import pandas

# Create a Pandas dataframe
my_df = pandas.DataFrame.from_dict({"a": [42]})

# 创建表的同时插入数据
duckdb.sql("CREATE TABLE my_table AS SELECT * FROM my_df")

# 已存在表可以直接插入
duckdb.sql("INSERT INTO my_table SELECT * FROM my_df")

# 如果列的顺序不同或并非所有列都存在于 DataFrame 可以使用
duckdb.sql("INSERT INTO my_table BY NAME SELECT * FROM my_df")

导出数据到 DataFrame 中

有两个方法来将结果转换为 DataFrame:

  • df()/fetchdf()/fetch_df(): 将结果表转换为 DataFrame 对象
  • fetch_df_chunk(vector_multiple=1): 将部分结果提取到 DataFrame 中,每个块中返回2048 * vector_multiple行,返回的结果行并不一定是 2048*vector_multiple
Python
# 没有实现迭代器接口必须手动循环
result = duckdb.cursor().execute("SELECT * FROM range(10) as rel(id)")
while True:
    temp_df = result.fetch_df_chunk(10)
    if len(temp_df) == 0:
        break

fetch_df_chunk 的使用逻辑和迭代器完全不一样,默认情况下使用的内存并不会被回收,因此一个非常大的数据库执行 fetch_df_chunk 操作会占用大量的内存。此时就必须指定 set memory_limit ='20G' 这样的来限制内存使用量。

用于 Relational API

DataFrame 在 DuckDB 中直接被认为是一个虚拟表,但是我们只能将它作为右表使用,而无法直接作为左表使用。此时我们就需要通过方法来将它封装为 DuckDBPyRelation 对象:

Python
import duckdb
import pandas

input_df = pandas.DataFrame.from_dict(
    {"i": [1, 2, 3, 4], "j": ["one", "two", "three", "four"]}
)

# 是直接可以作为右表使用的
duckdb.sql("SELECT * FROM input_df")

# 从 DataFrame 来构造 DuckDBPyRelation 对象来作为左表
rel = duckdb.from_df(input_df)

# 此时就可以作为左表使用了
rel.filter("i >= 2").project("i, j, i*2 as two_i").order("i desc").limit(2).show()

    ┌───────┬─────────┬───────┐
       i       j     two_i 
     int64  varchar  int64 
    ├───────┼─────────┼───────┤
         4  four         8 
         3  three        6 
    └───────┴─────────┴───────┘