跳转至

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)