Arrow + DuckDB,完爆 Pandas!
Python 长期以来一直主导着数据分析。相关数据显示,Python 是数据分析的首选,近 90% 的专业人士经常使用它,超过 70% 的人更喜欢它。
Pandas 成为了默认工具,每个人都在用,而且它运行良好。但它的规模一旦扩大,就会出现问题。内存紧张,性能也会下降。
现在有一个强有力的替代方案。
DuckDB + PyArrow提供了一种全新的模型。它们共同将传统的 DataFrame 替换为更快、更强大、更灵活的模型。该堆栈专为扩展而构建,支持列操作,支持 SQL,并且无需转换即可跨格式运行。
Pandas 的问题
Pandas 非常适合快速分析。但本质上,它并未针对规模进行优化。它逐行存储数据。这对于小数据来说还行,但对于更大的数据,这会导致内存膨胀和 CPU 浪费。
你不能分块传输数据。你需要加载所有内容,并将其保存在内存中,这限制了你的操作能力。
像 Parquet 这样的多文件格式很笨拙。你需要把所有内容都转换成 DataFrame。每个操作都会复制内存。没有下推过滤,没有分区,没有矢量化扫描。只有 Python 中的逐行循环。
现在文件越来越大,数据集也存储在云存储中。工具也需要改进。
PyArrow 是什么
Apache Arrow 是一种列式内存格式。它以块的形式保存数据。每列在内存中都是连续的。这使得过滤、排序和向量操作的速度更快。
它与语言无关。你可以在 Python、Rust、Go 和 C++ 之间共享 Arrow 表,而无需复制。
许多工具已经在内部使用 Arrow。Spark、Snowflake 和 Polars 就是例子。但 Arrow 不是数据库或引擎。它只是一种格式。你仍然需要某种东西来查询它。
这就是 DuckDB 发挥作用的地方。
什么是DuckDB
DuckDB 是一个进程内 OLAP 引擎。它类似于 SQLite,但专为分析而设计。它支持 SQL,速度很快,并且无需服务器即可运行。
DuckDB 将数据存储在列中,而不是行中。它直接从 Parquet 和 Arrow 读取数据。它可以执行连接、过滤和聚合,而无需将所有数据加载到 RAM 中。
它也在 Python 内部运行。
这意味着你可以将 DuckDB 用作 DataFrames 或 Arrow 表上的快速 SQL 层。你无需移动数据,只需在数据所在位置进行查询即可。
DuckDB 和 Arrow 结合
PyArrow 提供现代的表格格式。DuckDB 提供现代的 SQL 引擎。它们共同取代了传统的 DataFrame。
以下是一个例子:
import pyarrow as pa
import duckdb
# 创建 Arrow 表
table = pa.table({
"user_id": pa.array([1, 2, 3, 4]),
"amount": pa.array([100, 150, 80, 300])
})
# 使用 DuckDB 查询
result = duckdb.query("""
SELECT user_id, amount
FROM arrow_table
WHERE amount > 100
""", {"arrow_table": table}).to_df()
print(result)
无需 Pandas,无需转换。只需创建一个 Arrow 表,并在其上运行 SQL,即可获得 DuckDB 视图或 Pandas DataFrame 形式的结果。
这很高效,避免了复制,并且还能让你扩展。
优于 Pandas 的优势
1.速度
DuckDB 以矢量化批次扫描数据。它会下推过滤器,并使用并行线程。在执行连接、过滤和聚合操作时,它通常比 Pandas 更快,尤其是在数据量较大或来自磁盘的情况下。
2. 内存使用
Arrow 表非常紧凑。它们使用原生类型,无需 Python 对象。DuckDB 可以就地查询它们。这样可以避免 Pandas 转换和中间数组带来的内存峰值。
3. SQL Power
使用 DuckDB,你可以使用 SQL。这样可以避免 Pandas 中复杂的链式调用.groupby().apply().merge()。SQL 更清晰,更易于测试,更易于调试。它还支持窗口函数等高级操作。
4. 格式灵活性
DuckDB 可以直接读取 Parquet、CSV、Arrow 甚至 JSON。你可以跳过转换步骤,直接对原始文件进行查询。
duckdb.query("SELECT COUNT(*) FROM 'data/*.parquet'").fetchall()
该命令无需将文件读入 Pandas 即可运行,只需在磁盘上操作,并流式传输列。最重要的是,它可扩展。
生产管道中的 DuckDB
DuckDB 不仅适用于笔记本。它还适用于 FastAPI 路由、Airflow 任务、CLI 脚本和可测试的数据管道。
这是一个简单的 API 模式:
from fastapi import FastAPI
import duckdb
app = FastAPI()
@app.get("/summary")
defget_summary():
result = duckdb.query("""
SELECT category, COUNT(*) as total
FROM 'data/sales.parquet'
GROUP BY category
""").to_df()
return result.to_dict(orient="records")
这为你提供了一个实时分析端点。无需 ETL,无需数据仓库,只需 DuckDB 和文件。
简化的机器学习工作流程
特征工程通常需要连接、过滤和滞后函数。Pandas 可以做到,但速度很慢,而且很繁琐。
DuckDB 可以清晰地处理这个问题:
import pandas as pd
df = pd.read_csv("transactions.csv")
result = duckdb.query("""
SELECT user_id,
amount,
LEAD(amount) OVER (PARTITION BY user_id ORDER BY date) as next_amount
FROM df
""").to_df()
这展示了如何在不脱离 Python 的情况下将 SQL 窗口应用于 Pandas 输入。它节省时间并保持低内存占用。
从远程读取Arrow
使用 DuckDB 扩展,你甚至可以查询 S3 和 HTTP 源。
INSTALL httpfs;
LOAD httpfs;
SELECT COUNT(*) FROM 'https://example.com/data/sales.parquet';
你无需下载文件。DuckDB 会流式传输数据,只读取所需内容。对于数据科学家和工程师来说,这改变了笔记本电脑的运作方式。
注意:INSTALL httpfs是 DuckDB SQL 命令,它增加了通过HTTP、HTTPS、Amazon S3和其他云存储协议读取远程文件的支持。
写在最后
DuckDB 和 PyArrow 为 Python 用户提供了一条新途径。它突破了 Pandas 的内存限制,将 SQL 的强大功能引入本地工作流。它还能将 Arrow、Parquet、CSV 等现代数据格式作为原生输入。
🏴☠️宝藏级🏴☠️ 原创公众号『数据STUDIO』内容超级硬核。公众号以Python为核心语言,垂直于数据科学领域,包括可戳👉Python|MySQL|数据分析|数据可视化|机器学习与数据挖掘|爬虫等,从入门到进阶!
长按👇关注- 数据STUDIO -设为星标,干货速递