如何在Python的Polars中为多列应用value_counts()?
如何在Polars中对多列应用value_counts并合并结果?
问题场景
现有如下Polars DataFrame:
import polars as pl df = pl.from_repr(""" ┌──────────────┬─────────────┐ │ sub-category ┆ category │ │ --- ┆ --- │ │ str ┆ str │ ╞══════════════╪═════════════╡ │ tv ┆ electronics │ │ mobile ┆ mobile │ │ tv ┆ electronics │ │ wm ┆ electronics │ │ micro ┆ kitchen │ │ wm ┆ electronics │ └──────────────┴─────────────┘ """)
通过转Pandas后使用apply可以得到预期结果:
pl.from_pandas( df.to_pandas().apply(lambda x: x.value_counts()).reset_index() )
结果如下:
shape: (6, 3) ┌─────────────┬──────────────┬──────────┐ │ index ┆ sub-category ┆ category │ │ --- ┆ --- ┆ --- │ │ str ┆ f64 ┆ f64 │ ╞═════════════╪══════════════╪══════════╡ │ electronics ┆ null ┆ 4.0 │ │ kitchen ┆ null ┆ 1.0 │ │ micro ┆ 1.0 ┆ null │ │ mobile ┆ 1.0 ┆ 1.0 │ │ tv ┆ 2.0 ┆ null │ │ wm ┆ 2.0 ┆ null │ └─────────────┴──────────────┴──────────┘
需要直接在Polars中实现相同效果,无需转换为Pandas。
Polars实现方案
可以通过对每一列分别计算value_counts,再以唯一值为键进行外连接合并,代码如下:
# 计算每一列的value_counts subcat_counts = df.select(pl.col("sub-category").value_counts().alias("subcat")) cat_counts = df.select(pl.col("category").value_counts().alias("cat")) # 展开结构、重命名并外连接合并 result = ( subcat_counts.explode("subcat") .unnest("subcat") .rename({"sub-category": "index", "count": "sub-category"}) .join( cat_counts.explode("cat") .unnest("cat") .rename({"category": "index", "count": "category"}), on="index", how="outer" ) .sort("index") ) print(result)
步骤说明
- 单列统计:对
sub-category和category分别调用value_counts(),得到包含结构体的单列结果; - 结构展开:用
explode拆分结构体列表,unnest将结构体字段转为独立列,同时重命名列以匹配目标格式; - 外连接合并:以
index(原列的唯一值)为键执行外连接,保留所有唯一值,缺失的计数自动填充null; - 排序:按
index排序,保证结果顺序与Pandas实现一致。
执行后输出结果:
shape: (6, 3) ┌─────────────┬──────────────┬──────────┐ │ index ┆ sub-category ┆ category │ │ --- ┆ --- ┆ --- │ │ str ┆ u32 ┆ u32 │ ╞═════════════╪══════════════╪══════════╡ │ electronics ┆ null ┆ 4 │ │ kitchen ┆ null ┆ 1 │ │ micro ┆ 1 ┆ null │ │ mobile ┆ 1 ┆ 1 │ │ tv ┆ 2 ┆ null │ │ wm ┆ 2 ┆ null │ └─────────────┴──────────────┴──────────┘
若需要将计数列类型转为与Pandas一致的f64,可添加类型转换:
result = result.with_columns(pl.col(["sub-category", "category"]).cast(pl.Float64))
内容的提问来源于stack exchange,提问作者ViSa
相关产品推荐
相关产品推荐

