0

0

Pandas DataFrame中连续行块计数的高效方法

聖光之護

聖光之護

发布时间:2025-11-24 11:41:47

|

394人浏览过

|

来源于php中文网

原创

Pandas DataFrame中连续行块计数的高效方法

本文将深入探讨如何在pandas dataframe中高效地计算某一列连续相同值的行数,并将其作为新列添加。通过结合`shift()`、`cumsum()`和`groupby().transform('size')`等pandas核心函数,我们将展示一种优雅且强大的解决方案,精确识别并统计数据集中所有连续值块的长度,避免了传统`groupby`的局限性,适用于需要精细化连续数据分析的场景。

在数据处理和分析中,我们经常会遇到需要统计DataFrame中某一列连续相同值出现的次数。例如,给定一个序列 ['a', 'a', 'a', 'b', 'b', 'c', 'd', 'e', 'e', 'e'],我们希望得到的结果是 [3, 3, 3, 2, 2, 1, 1, 3, 3, 3],即每个连续块的长度。这与简单地按值分组并计数不同,因为同一个值在DataFrame中可能非连续地出现多次,而我们只关心连续出现的块。

问题场景与常见误区

假设我们有以下DataFrame:

import pandas as pd

data = {
    'class': ['a', 'a', 'a', 'b', 'b', 'c', 'd', 'e', 'e', 'e', 'f', 'a', 'c', 'd', 'd']
}
df = pd.DataFrame(data)
print("原始DataFrame:")
print(df)

输出:

原始DataFrame:
   class
0      a
1      a
2      a
3      b
4      b
5      c
6      d
7      e
8      e
9      e
10     f
11     a
12     c
13     d
14     d

我们期望的结果是为每行添加一个 consecutive_count 列,其值表示该行所属的连续块的长度:

   class  consecutive_count
0      a                  3
1      a                  3
2      a                  3
3      b                  2
4      b                  2
5      c                  1
6      d                  1
7      e                  3
8      e                  3
9      e                  3
10     f                  1
11     a                  1
12     c                  1
13     d                  2
14     d                  2

误区一:使用 groupby().transform('count')

直接按 class 列进行分组并使用 transform('count') 会统计每个 class 值在整个DataFrame中出现的总次数,而不是连续块的次数。

df['total_count'] = df.groupby('class')['class'].transform('count')
print("\n使用 transform('count') 的结果:")
print(df)

输出:

使用 transform('count') 的结果:
   class  total_count
0      a            4
1      a            4
2      a            4
3      b            2
4      b            2
5      c            2
6      d            3
7      e            3
8      e            3
9      e            3
10     f            1
11     a            4
12     c            2
13     d            3
14     d            3

显然,这不符合我们的需求,例如,第一个 'a' 块有3个,但结果显示为4,因为后面还有一个单独的 'a'。

误区二:使用 (df['class'] != df['class'].shift()).cumsum()

这个表达式可以为每个连续块生成一个唯一的标识符,但它本身不提供块的长度。

启科网络PHP商城系统
启科网络PHP商城系统

启科网络商城系统由启科网络技术开发团队完全自主开发,使用国内最流行高效的PHP程序语言,并用小巧的MySql作为数据库服务器,并且使用Smarty引擎来分离网站程序与前端设计代码,让建立的网站可以自由制作个性化的页面。 系统使用标签作为数据调用格式,网站前台开发人员只要简单学习系统标签功能和使用方法,将标签设置在制作的HTML模板中进行对网站数据、内容、信息等的调用,即可建设出美观、个性的网站。

下载
df['consecutive_group_id'] = (df['class'] != df['class'].shift()).cumsum()
print("\n使用 cumsum() 生成组ID的结果:")
print(df)

输出:

使用 cumsum() 生成组ID的结果:
   class  consecutive_group_id
0      a                     1
1      a                     1
2      a                     1
3      b                     2
4      b                     2
5      c                     3
6      d                     4
7      e                     5
8      e                     5
9      e                     5
10     f                     6
11     a                     7
12     c                     8
13     d                     9
14     d                     9

这里 consecutive_group_id 成功地将不同的连续块区分开来(例如,第一个 'a' 块的ID是1,而第11行的 'a' 块的ID是7)。这是解决问题的关键一步,但还需要进一步处理才能得到块的长度。

解决方案:组合动态分组与 transform('size')

解决此问题的核心在于创建一个能够同时识别值和其连续性的分组键。我们可以利用 (df['class'] != df['class'].shift()).cumsum() 生成的连续组ID,并将其与原始的 class 值结合起来作为 groupby 的键。

步骤详解:

  1. 识别连续块的起始点:df['class'].shift() 将 class 列向下移动一行,使得当前行的值可以与上一行的值进行比较。 df['class'] != df['class'].shift() 会生成一个布尔序列,True 表示当前行的值与上一行的值不同(即一个新的连续块开始),False 表示相同。对于第一行,shift() 会产生 NaN,与任何值比较都会是 True,这恰好符合其作为第一个块起始点的逻辑。

  2. 生成唯一的连续块ID: 对上述布尔序列应用 .cumsum()。由于 True 在求和时被视为1,False 被视为0,cumsum() 会为每个新的连续块分配一个递增的唯一整数ID。这样,即使同一个值(如 'a')在DataFrame中多次非连续地出现,它们也会被赋予不同的连续块ID。

  3. 构建复合分组键: 现在我们有了两个关键信息:原始的 class 值,以及它所属的连续块的唯一ID。我们将这两者结合起来作为 groupby 的键: df.groupby(['class', (df['class'] != df['class'].shift()).cumsum()]) 这个 groupby 操作会创建一个组,其中每个组都由一个唯一的 (class值, 连续块ID) 对定义。例如,第一个 'a' 块会形成一个组 ('a', 1),而第11行的 'a' 块会形成另一个组 ('a', 7)。

  4. 计算并广播组大小: 在分组之后,我们使用 .transform('size')。transform('size') 的作用是计算每个组的元素数量(即连续块的长度),然后将这个计算结果广播回原始DataFrame中属于该组的所有行。这样,每个属于同一个连续块的行都会得到该块的正确长度。

完整代码示例:

import pandas as pd

# 原始数据
data = {
    'class': ['a', 'a', 'a', 'b', 'b', 'c', 'd', 'e', 'e', 'e', 'f', 'a', 'c', 'd', 'd']
}
df = pd.DataFrame(data)

# 核心解决方案
df['consecutive_count'] = df.groupby(['class', (df['class'] != df['class'].shift()).cumsum()]).transform('size')

print("\n最终结果DataFrame:")
print(df)

输出:

最终结果DataFrame:
   class  consecutive_count
0      a                  3
1      a                  3
2      a                  3
3      b                  2
4      b                  2
5      c                  1
6      d                  1
7      e                  3
8      e                  3
9      e                  3
10     f                  1
11     a                  1
12     c                  1
13     d                  2
14     d                  2

这个结果与我们最初期望的完全一致。

注意事项与总结

  • shift() 处理 NaN: df['class'].shift() 在DataFrame的第一行会产生 NaN。当与 df['class'] 的第一个元素比较时,'a' != NaN 会被评估为 True(在Pandas和Python中,'a' == NaN 是 False),因此 cumsum() 从1开始计数是正确的。
  • 性能: 这种方法利用了Pandas底层的优化,对于大型DataFrame来说效率很高。
  • 通用性: 这种方法不仅适用于字符串类型,也适用于数值型或其他可比较的数据类型。
  • transform() 的强大: transform() 函数是Pandas中一个非常强大的工具,它允许在 groupby 操作后,将聚合结果(如 size, sum, mean 等)广播回原始DataFrame,保持DataFrame的原始形状,这在许多数据转换场景中都非常有用。

通过理解并运用 shift()、cumsum() 和 groupby().transform('size') 的组合,我们能够优雅且高效地解决Pandas DataFrame中连续行块计数的问题,这在时间序列分析、日志处理等领域具有广泛的应用价值。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

755

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

636

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

760

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

618

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1264

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

547

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

578

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

708

2023.08.11

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

9

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 0.9万人学习

Django 教程
Django 教程

共28课时 | 3.1万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号