Polars库shift()函数问题:无法填充同Invoice的Operation字段
问题解决:Polars中为相同Invoice批量生成唯一Operation值
问题场景
需要实现:当Invoice字段与上一行不同时,调用my_func()生成唯一的Operation值;同一Invoice的所有后续行复用该值。但原脚本使用shift()的方式未达到预期,同Invoice的后续Operation字段为空。
原代码问题分析
原代码的核心问题:
- 初始
Operation列全为空字符串,使用shift()后仍为空,导致otherwise分支无法获取有效值 - 用
map_elements逐行调用my_func()不仅效率低,也不符合“每个Invoice仅生成一次唯一值”的需求 - 依赖行偏移的逻辑无法处理分组内的批量赋值,Polars更适合用分组+广播的方式实现这类需求
解决方案
方法1:分组+Transform(推荐)
利用Polars的group_by+transform,在每个Invoice分组内仅生成一次唯一值,然后自动广播到组内所有行,代码简洁高效:
import polars as pl from faker import Faker from datetime import date # 原代码遗漏该导入,需补上 fake = Faker(locale='fr_FR') def my_func(): operation = fake.unique.pystr_format( string_format='??###', letters='abcdefghijklmnopqrstuvwxyz').upper() return operation my_df = pl.DataFrame({ "Date":[date(2023, 1, 2), date(2023, 1, 2), date(2023, 1, 2), date(2023, 3, 5), date(2023, 3, 17), date(2023, 3, 17), date(2023, 3, 17), date(2023, 3, 17), date(2023, 5, 1), date(2023, 5, 17), date(2023, 5, 17), date(2023, 5, 17)], "Invoice":['001', '001', '001', '002', '003', '003', '003', '003', '004', '005', '005', '005'], "Amount":[250, 250, 250, 300, 450, 450, 450, 450, 500, 650, 650, 650], }) # 直接生成Operation列,无需预先创建空列 result_df = my_df.with_columns( Operation=pl.col("Invoice").group_by("Invoice").transform( lambda group: pl.Series([my_func()] * len(group)) ) ) print(result_df)
方法2:创建映射表后Join
先为每个唯一的Invoice生成对应的Operation,再通过join将值映射回原表,适合需要单独保存映射关系的场景:
# 生成Invoice与Operation的映射表 invoice_map = my_df.select("Invoice").unique().with_columns( Operation=pl.col("Invoice").map_elements(lambda _: my_func()) ) # 关联回原表 result_df = my_df.join(invoice_map, on="Invoice", how="left")
效果说明
两种方法都能实现:每个唯一的Invoice对应一个唯一的Operation值,同一Invoice的所有行共享该值,解决了原脚本中空值的问题。
内容的提问来源于stack exchange,提问作者Laurent Reynaud
相关产品推荐
相关产品推荐

