0

0

Polars UDF 行级映射与多行结果 DataFrame 的高效拼接

聖光之護

聖光之護

发布时间:2026-02-22 10:23:00

|

439人浏览过

|

来源于php中文网

原创

Polars UDF 行级映射与多行结果 DataFrame 的高效拼接

本文详解如何在 Polars 中正确实现「每行输入生成一个同结构但行数可变的 DataFrame」的 UDF 模式,对比 map_rows、iter_rows + concat 与表达式向量化三种方案,强调性能陷阱与最佳实践。

本文详解如何在 polars 中正确实现「每行输入生成一个同结构但行数可变的 dataframe」的 udf 模式,对比 `map_rows`、`iter_rows + concat` 与表达式向量化三种方案,强调性能陷阱与最佳实践。

在 Polars 中,当需要对每一行输入执行复杂逻辑(如基于参数切片参考数据、生成变长结果集)并最终合并为单个 DataFrame 时,开发者常误用 map_rows 返回嵌套 DataFrame,导致性能劣化与类型混乱。核心原则是:map_rows 本质是逐行标量映射,不适用于返回多行结构;真正支持“1→N”行扩展的操作应使用 iter_rows + pl.concat() 或(更优)完全向量化表达式重构。

✅ 推荐方案一:避免 map_rows,改用 iter_rows + pl.concat()

这是最直接、语义清晰且可控性高的方式,尤其适合逻辑无法轻易向量化(如需调用外部库、动态切片大表等)的场景:

import polars as pl

df = pl.DataFrame({
    "foo": [1, 2, 3],
    "bar": [6.0, 7.0, 8.0],
    "ham": ["a", "b", "c"],
})

reference_data = pl.DataFrame({
    "x": list(range(10)),
    "y": [chr(ord("a") + i % 26) for i in range(10)],
})

def myUDF(row_tuple):
    foo, bar, ham = row_tuple
    # 动态切片:从 foo 开始取 floor(bar/2) 行
    n_rows = int(bar / 2)
    return (
        reference_data
        .slice(foo, n_rows)
        .with_columns(name=pl.lit(ham))
    )

# ✅ 正确做法:逐行调用 UDF 并拼接
result = pl.concat([myUDF(row) for row in df.iter_rows()], how="vertical")
print(result)

输出:

shape: (10, 3)
┌─────┬─────┬──────┐
│ x   ┆ y   ┆ name │
│ --- ┆ --- ┆ ---  │
│ i64 ┆ str ┆ str  │
╞═════╪═════╪══════╡
│ 1   ┆ b   ┆ a    │
│ 2   ┆ c   ┆ a    │
│ 3   ┆ d   ┆ a    │
│ 2   ┆ c   ┆ b    │
│ 3   ┆ d   ┆ b    │
│ 4   ┆ e   ┆ b    │
│ 3   ┆ d   ┆ c    │
│ 4   ┆ e   ┆ c    │
│ 5   ┆ f   ┆ c    │
│ 6   ┆ g   ┆ c    │
└─────┴─────┴──────┘

⚠️ 注意事项:

Calliper 文档对比神器
Calliper 文档对比神器

文档内容对比神器

下载
  • pl.concat(..., how="vertical") 要求所有子 DataFrame 具有完全一致的 schema(列名、类型、顺序),否则会报错;
  • iter_rows() 返回 Python tuple,默认按列顺序解包,确保 UDF 内部解构顺序与 DataFrame 列序严格一致;
  • 若 reference_data 极大(如千万级),建议预先 .lazy() 化并在 UDF 中构建 LazyFrame,最后统一 .collect(),避免重复 eager 计算。

✅ 推荐方案二:彻底向量化 —— 用 Polars 表达式替代 UDF(最高性能)

若逻辑可表达为列运算(如本例中“切片范围由 foo 和 bar 决定”),应优先放弃行级循环,转为纯表达式操作:

# ✅ 向量化实现(无 Python 循环,充分利用 Polars 引擎)
result_vec = (
    df
    .with_row_index("row_idx")  # 添加索引用于后续 join 或 expand
    .with_columns(
        start = pl.col("foo"),
        stop = (pl.col("bar") / 2).cast(pl.Int64),
        name = pl.col("ham")
    )
    # 生成每个 row 对应的 range(start, stop),再 explode 展开
    .with_columns(
        range_list = pl.arange(pl.col("start"), pl.col("stop"), eager=False)
    )
    .explode("range_list")
    .join(
        reference_data.rename({"x": "range_list"}),
        on="range_list",
        how="left"
    )
    .select("x", "y", "name")
)

该方式零 Python 解释器开销,支持多线程并行,是 Polars 的设计哲学首选。

❌ 不推荐方案:滥用 map_rows 返回 DataFrame

map_rows 的设计目标是返回标量元组(如 (a, b)),其输出会被自动构造成新 DataFrame 的一行。若在函数内创建 DataFrame 并返回(如 return (result,)),Polars 仅将其作为 object 类型存储,后续需 .unnest().explode() 等昂贵操作,丧失 Polars 的内存与计算优势:

# ❌ 反模式:低效、类型丢失、难以调试
df.map_rows(lambda r: (pl.DataFrame({"a": [r[0]+r[1]], "b": [r[2]]}),))

总结:选择路径的决策树

场景 推荐方式 理由
逻辑完全可用 Polars 表达式描述(如算术、条件、窗口、join) 纯表达式链 最高性能、可并行、惰性优化、类型安全
需动态访问外部资源 / 调用非 Polars 函数 / 复杂控制流 iter_rows() + pl.concat() 语义明确、易于调试、可控性强;注意 schema 一致性
临时调试或极小数据集 map_rows + 标量元组(非 DataFrame) 仅限简单 1→1 映射,避免嵌套结构

记住:Polars 的强大源于列式计算与查询优化器,而非模拟 Pandas 的 .apply(axis=1)。拥抱向量化,谨慎使用行级迭代——这才是“正确的 Polars 方式”。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 时间序列分析与预测
Python 时间序列分析与预测

本专题专注讲解 Python 在时间序列数据处理与预测建模中的实战技巧,涵盖时间索引处理、周期性与趋势分解、平稳性检测、ARIMA/SARIMA 模型构建、预测误差评估,以及基于实际业务场景的时间序列项目实操,帮助学习者掌握从数据预处理到模型预测的完整时序分析能力。

76

2025.12.04

Python 数据清洗与预处理实战
Python 数据清洗与预处理实战

本专题系统讲解 Python 在数据清洗与预处理中的核心技术,包括使用 Pandas 进行缺失值处理、异常值检测、数据格式化、特征工程与数据转换,结合 NumPy 高效处理大规模数据。通过实战案例,帮助学习者掌握 如何处理混乱、不完整数据,为后续数据分析与机器学习模型训练打下坚实基础。

7

2026.01.31

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

695

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

370

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

26

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

25

2026.01.21

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

99

2026.02.06

go语言 数组和切片
go语言 数组和切片

本专题整合了go语言数组和切片的区别与含义,阅读专题下面的文章了解更多详细内容。

49

2025.09.03

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

928

2026.02.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号