DEBUG.WIKI
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
腾讯云;让你的想法跑起来;轻量服务器 · 建站 / Docker / API;查看产品 →
晚安云;香港 CN2 ¥15/月

Polars 的 Array 是 null,arr.first 却取出了 0

固定长度 Array 经 gather 或外连接产生空行后,部分 arr 操作可能读取空行底层值。区分整行 null 与数组内 null,保留缺失掩码,必要时转换为 List 后使用对应操作。

固定长度 Array 列里明明有一行 null,执行 arr.first() 却得到 0;换一种方式创建相同数据,结果又是 null。这时要检查整行数组的有效性掩码有没有在操作中生效,而不是认为 Polars 自动把缺失值填成了零。

Polars 2.0.0 经 gather([0, None, 1]) 产生空数组行时已出现这项问题;外连接补出的空行也有历史同类表现。arr.first()、arr.get() 或 arr.max() 可能读到空行下方的存储值。那个值可以是零,也可以是别的已有值,不能根据一次结果推断固定填充值。

区分三种数据含义

整行 null、[null, null] 和 [0, 0] 是不同数据。固定长度数组可以有外层有效性掩码,也可以有内部元素掩码;只看底层数值缓冲区无法判断整行是否有效。

先保留原列,用 is_null() 对照异常结果的位置,再比较不同操作。某个 arr.sum() 或 explode() 返回正确,不代表所有 arr 操作共用相同的掩码处理;反过来也不能因为一项出错就把整列有效数值全部丢弃。

用 List 路径保留空行含义

需要取首个元素或求最大值时,可以先把固定长度 Array 转成 List,再使用对应的 List 操作:

import polars as pl

checked = frame.with_columns(
    pl.col("values").arr.to_list().list.first().alias("first_value"),
    pl.col("values").arr.to_list().list.max().alias("max_value"),
)

values 应是原来的固定长度 Array 列。这个方案保留原列并新建结果列,便于按行核对;转换后的 List 不再把长度约束作为 dtype 的同一部分,下游若要求 Array,需明确只转换计算表达式,不悄悄改变接口列类型。

用原来经 gather 或 join 产生空行的输入核对,而不只是手工构造一份 [None]。检查空行仍得到 null,有效的 [0, 0] 仍得到 0,含内部 null 的数组按该操作原有规则处理。对空 List 的语义也要独立确认,不能拿固定长度非空数组的规则套到它上面。

不从已经算出的零恢复缺失值

将结果列中所有 0 改成 null,会把真实零也删除;把所有 null 填零则会反向抹掉缺失。应从保存的原数组有效性掩码或原输入重新计算。若错误结果已经用于汇总、导出或训练,修正库版本不会重算这些产物,需要确认影响范围。

无论继续使用 2.0 还是更换版本,都要分别检查 gather 空索引、连接补空、原生空行与真实零值。每种实际使用的 arr 方法都应核对,不能从一项聚合正确就推断其他取值操作也保留了空行。