为什么每个分组的累计和都是全为1?

后端开发 2026-07-12

在Pandas中,我使用 .groupby().cumsum() 来生成一个计数列:

import pandas as pd

df = pd.DataFrame({'ID':['A','B','A','A','B','B','C','D','D','C']})

df['count'] = df['ID'].ne(df['ID'].shift()).groupby(df['ID']).cumsum()
  ID  count
0  A      1
1  B      1
2  A      2
3  A      2
4  B      2
5  B      2
6  C      1
7  D      1
8  D      1
9  C      2

在Polars中尝试同样的方法时,结果却全是1。这是为什么?

import polars as pl

df = pl.DataFrame({'ID':['A','B','A','A','B','B','C','D','D','C']})

df.with_columns(
    count = (pl.col('ID').ne(pl.col('ID').shift()).fill_null(True).cum_sum()).over('ID')
)
┌─────┬───────┐
│ ID  ┆ count │
│ --- ┆ ---   │
│ str ┆ u32   │
╞═════╪═══════╡
│ A   ┆ 1     │
│ B   ┆ 1     │
│ A   ┆ 1     │
│ A   ┆ 1     │
│ B   ┆ 1     │
│ B   ┆ 1     │
│ C   ┆ 1     │
│ D   ┆ 1     │
│ D   ┆ 1     │
│ C   ┆ 1     │
└─────┴───────┘

如何生成与Pandas方案相同的计数列?

解决方案

你用来生成“连续ID”的Pandas shift做法,也被称为游程编码(run-length encoding)。

Polars确实提供了一个专门的 .rle_id() 表达式来实现这个。

df.with_columns(count=pl.col.ID.rle_id()) 

# shape: (10, 2)
# ┌─────┬───────┐
# │ ID  ┆ count │
# │ --- ┆ ---   │
# │ str ┆ u32   │
# ╞═════╪═══════╡
# │ A   ┆ 0     │
# │ B   ┆ 1     │
# │ A   ┆ 2     │
# │ A   ┆ 2     │
# │ B   ┆ 3     │
# │ B   ┆ 3     │
# │ C   ┆ 4     │
# │ D   ┆ 5     │
# │ D   ┆ 5     │
# │ C   ┆ 6     │
# └─────┴───────┘

你接着可以对每个分组执行一个密集 .rank() 作为一个窗口函数来得到1..N的序列。

(df.with_columns(count=pl.col.ID.rle_id())
   .with_columns(pl.col("count").rank(method="dense").over("ID"))
)
shape: (10, 2)
┌─────┬───────┐
│ ID  ┆ count │
│ --- ┆ ---   │
│ str ┆ u32   │
╞═════╪═══════╡
│ A   ┆ 1     │
│ B   ┆ 1     │
│ A   ┆ 2     │
│ A   ┆ 2     │
│ B   ┆ 2     │
│ B   ┆ 2     │
│ C   ┆ 1     │
│ D   ┆ 1     │
│ D   ┆ 1     │
│ C   ┆ 2     │
└─────┴───────┘
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章