You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Polars按session_id分组统计fqid频次并转宽表的实现方法

Polars按session_id分组后实现fqid列的频次透视转换

原始数据与需求

原始DataFrame代码

import polars as pl

df = pl.from_repr("""
┌───────────────────┬──────────────┬────────┐
│ session_id        ┆ elapsed_time ┆ fqid   │
│ ---               ┆ ---          ┆ ---    │
│ i64               ┆ i32          ┆ cat    │
╞═══════════════════╪══════════════╪════════╡
│ 20090312431273200 ┆ 0            ┆ intro  │
│ 20090312431273200 ┆ 1323         ┆ gramps │
│ 20090312431273200 ┆ 831          ┆ gramps │
│ 20090312431273200 ┆ 1147         ┆ gramps │
│ 20090312431273200 ┆ 5197         ┆ teddy  │
│ 20090312431273200 ┆ 6180         ┆ teddy  │
│ 20090312431273200 ┆ 7014         ┆ teddy  │
│ 20090312431273200 ┆ 7946         ┆ teddy  │
└───────────────────┴──────────────┴────────┘
""")

目标格式

希望转换为按session_id分组,统计fqid各分类的频次,并将分类转为fqid_分类值格式的列:

┌───────────────────┬─────────────┬────────────┬────────────┐
│ session_id        ┆ fqid_gramps ┆ fqid_intro ┆ fqid_teddy │
│ ---               ┆ ---         ┆ ---        ┆ ---        │
│ i64               ┆ i32         ┆ i32        ┆ i32        │
╞═══════════════════╪═════════════╪════════════╪════════════╡
│ 20090312431273200 ┆ 3           ┆ 1          ┆ 4          │
└───────────────────┴─────────────┴────────────┴────────────┘

需求要点

  • 按session_id分组
  • 统计fqid各分类的出现频次
  • 将列名重命名为fqid_+分类值
  • 转换为宽表格式

问题场景

你可以通过非分组代码实现全局统计:

# 全局统计的非分组代码
column_values = df['fqid'].value_counts().with_columns(pl.concat_str(pl.lit('fqid_'), pl.col('fqid').cast(pl.String))).transpose()
column_values = column_values.rename(column_values.head(1).to_dicts().pop()).slice(1)

但尝试将逻辑改为分组聚合时,用pl.col('fqid')替代df['fqid']并执行group_by('session_id').aggregate(func('fqid')),会报错:AttributeError: 'Expr' object has no attribute 'with_columns'。

错误原因

pl.col('fqid')是Polars表达式对象,而非DataFrame,因此没有with_columns方法。聚合操作中需要使用符合Polars表达式规则的聚合逻辑,不能直接套用DataFrame的链式操作。

正确实现方式

方法1:使用pivot(推荐,简洁高效)

利用Polars的pivot方法直接实现分组后的宽表转换:

result = df.group_by(['session_id', 'fqid']).agg(
    pl.count().alias('count')
).pivot(
    index='session_id',
    columns='fqid',
    values='count'
).fill_null(0).rename(
    lambda col: f'fqid_{col}' if col != 'session_id' else col
)

print(result)

步骤说明:

  1. 先按session_id和fqid分组,统计每个组合的频次
  2. 使用pivot将fqid的分类转为列,值为对应的频次
  3. 用fill_null(0)填充未出现分类的缺失值为0
  4. 重命名列,给非session_id的列加上fqid_前缀

方法2:提前获取分类,逐个聚合计数

如果需要明确指定要统计的分类,可以先获取所有fqid的唯一值,再在聚合中逐个计数:

# 获取所有fqid的唯一分类
fqid_categories = df['fqid'].unique().to_list()

result = df.group_by('session_id').agg(
    [pl.count().filter(pl.col('fqid') == cat).alias(f'fqid_{cat}') for cat in fqid_categories]
)

print(result)

步骤说明:

  1. 提取fqid的所有唯一分类
  2. 按session_id分组,对每个分类用filter筛选后统计数量,并重命名列

两种方法都能得到你需要的结果,其中pivot方法更简洁,适合大多数场景。

内容的提问来源于stack exchange,提问作者yk4r2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:33:10