Narwhals — 统一 pandas/Polars/Arrow 的轻量 DataFrame API
一句话说明
Narwhals 让你写一套代码,自动适配 pandas、Polars、PyArrow、cuDF 等多种 DataFrame 后端,库作者用它发布同时支持所有后端的数据库工具。
安装与配置
# pip 安装(极轻量,无强制依赖)
pip install narwhals # 当前版本 1.x
# 工作需要对应的后端
pip install pandas polars pyarrow # 安装你要用的后端
# 验证
python -c "import narwhals as nw; print(nw.__version__)"
核心用法
核心思路:类型无关函数
import narwhals as nw
import pandas as pd
import polars as pl
# 定义一个后端无关的函数
def get_top_scorers(df_native, n: int = 5):
"""不管传 pandas 还是 polars 都能工作"""
df = nw.from_native(df_native) # 包装为 narwhals DataFrame
result = (
df
.filter(nw.col("score") > 80) # 过滤
.sort("score", descending=True) # 降序排列
.head(n) # 取前 n 行
.select(["name", "score"]) # 选列
)
return nw.to_native(result) # 解包,返回原始类型
# 传 pandas
pd_df = pd.DataFrame({"name": ["Alice","Bob","Carol"], "score":[95,78,88]})
print(get_top_scorers(pd_df)) # 返回 pandas DataFrame
# 传 polars(同一函数!)
pl_df = pl.DataFrame({"name": ["Alice","Bob","Carol"], "score":[95,78,88]})
print(get_top_scorers(pl_df)) # 返回 polars DataFrame
常用表达式
import narwhals as nw
def transform(df_native):
df = nw.from_native(df_native)
return (
df
# 选列
.select(["id", "value", "group"])
# 添加新列
.with_columns(
(nw.col("value") * 2).alias("value_doubled"), # 计算列
nw.col("group").str.to_uppercase().alias("group_up"), # 字符串操作
)
# 分组聚合
.group_by("group")
.agg(
nw.col("value").mean().alias("mean_value"),
nw.col("value").max().alias("max_value"),
)
# 过滤
.filter(nw.col("mean_value") > 10)
# 排序
.sort("mean_value", descending=True)
)
实战案例
写兼容多后端的数据分析库
import narwhals as nw
from narwhals.typing import IntoDataFrame
def analyze_otu_table(df: IntoDataFrame, group_col: str = "group"):
"""
分析 OTU 多样性表——兼容 pandas 和 polars
Args:
df: pandas/polars DataFrame,包含 shannon、group 列
group_col: 分组列名
Returns:
每组的 Shannon 均值,保持原始类型
"""
ndf = nw.from_native(df)
result = (
ndf
.filter(nw.col("shannon").is_not_null()) # 去除空值
.group_by(group_col)
.agg(
nw.col("shannon").mean().alias("mean_shannon"),
nw.col("shannon").std().alias("std_shannon"),
nw.len().alias("n_samples"),
)
.sort("mean_shannon", descending=True)
)
return nw.to_native(result) # 返回原始类型
# 两种调用方式
import pandas as pd
pd_result = analyze_otu_table(pd.read_csv("otu.csv")) # pandas 版
import polars as pl
pl_result = analyze_otu_table(pl.read_csv("otu.csv")) # polars 版
常见报错与解决
| 报错 | 原因 | 解决 |
|---|
InvalidOperationError | 操作不被当前后端支持 | 查文档确认 narwhals API 覆盖范围 |
TypeError: cannot convert | 忘记 nw.from_native() | 确保先包装再操作 |
ColumnNotFoundError | 列名不存在 | 检查列名拼写 |
速查表
| 操作 | 代码 |
|---|
| 包装 | nw.from_native(df) |
| 解包 | nw.to_native(ndf) |
| 选列 | .select(["a","b"]) |
| 过滤 | .filter(nw.col("x") > 0) |
| 添加列 | .with_columns(nw.col("x")*2).alias("y") |
| 分组聚合 | .group_by("g").agg(nw.col("x").mean()) |
| 排序 | .sort("col", descending=True) |
| 取前N | .head(n) |