Polars分组统计cut分桶后最高频桶次数报错排查与解决
Polars分组后计算cut桶最高频率的报错处理
问题背景
示例数据与初始实现:
import polars as pl df = pl.DataFrame({'a':[1,1,1,1,2,2,2,2],'b':[1,2,1,2,1,2,1,2],'c':[10,10,12,13,14,15,16,17]})
数据输出:
shape: (8, 3) ┌─────┬─────┬─────┐ │ a ┆ b ┆ c │ │ --- ┆ --- ┆ --- │ │ i64 ┆ i64 ┆ i64 │ ╞═════╪═════╪═════╡ │ 1 ┆ 1 ┆ 10 │ │ 1 ┆ 2 ┆ 10 │ │ 1 ┆ 1 ┆ 12 │ │ 1 ┆ 2 ┆ 13 │ │ 2 ┆ 1 ┆ 14 │ │ 2 ┆ 2 ┆ 15 │ │ 2 ┆ 1 ┆ 16 │ │ 2 ┆ 2 ┆ 17 │ └─────┴─────┴─────┘
需求为:找到pl.col("c").cut([11,14])生成的c_bucket列中最常见项的出现频率。全局计算时,以下代码可正常运行:
df.select(pl.col("c").cut([11,14]).value_counts().sort().struct.field("count").first())
输出:
shape: (1, 1) ┌───────┐ │ count │ │ --- │ │ u32 │ ╞═══════╡ │ 2 │ └───────┘
但分组计算时,执行以下代码报错:
df.group_by("a").agg(pl.col("c").cut([11,14]).value_counts().sort().struct.field("count").first())
错误信息:
PanicException: called `Option::unwrap()` on a `None` value
错误原因
在group_by.agg上下文里,pl.col("c").cut([11,14]).value_counts()返回的是每个分组对应的结构体数组(数组元素是包含c_bucket和count的结构体)。此时直接链式调用.sort().struct.field("count").first()会触发Polars内部的空值解包错误——因为Polars无法直接对数组类型的结果执行这类链式的结构体字段提取和排序操作,操作逻辑不匹配分组后的数组输出格式。
正确实现方式
方法1:用map_elements处理分组内的value_counts结果
通过map_elements对每个分组的value_counts数组单独处理,排序后取最大count:
df.group_by("a").agg( pl.col("c").cut([11,14]).value_counts() .map_elements(lambda x: x.sort("count", descending=True)[0]["count"], return_dtype=pl.UInt32) .alias("max_bucket_count") )
输出结果:
shape: (2, 2) ┌─────┬──────────────────┐ │ a ┆ max_bucket_count │ │ --- ┆ --- │ │ i64 ┆ u32 │ ╞═════╪══════════════════╡ │ 1 ┆ 2 │ │ 2 ┆ 2 │ └─────┴──────────────────┘
方法2:先展开分组统计,再取最大值
先按a和c_bucket双重分组统计次数,再按a分组取最大count:
( df.with_columns(c_bucket=pl.col("c").cut([11,14])) .group_by(["a", "c_bucket"]) .agg(count=pl.count()) .group_by("a") .agg(max_bucket_count=pl.max("count")) )
此方法逻辑更直观,避免了数组操作的潜在问题,输出结果与方法1一致。
内容的提问来源于stack exchange,提问作者figs_and_nuts
相关产品推荐
相关产品推荐

