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()

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

阿里云AI平台
阿里云AI平台

阿里云AI平台

下载
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中连续行块计数的问题,这在时间序列分析、日志处理等领域具有广泛的应用价值。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python 时间序列分析与预测
Python 时间序列分析与预测

本专题专注讲解 Python 在时间序列数据处理与预测建模中的实战技巧,涵盖时间索引处理、周期性与趋势分解、平稳性检测、ARIMA/SARIMA 模型构建、预测误差评估,以及基于实际业务场景的时间序列项目实操,帮助学习者掌握从数据预处理到模型预测的完整时序分析能力。

80

2025.12.04

Python 数据清洗与预处理实战
Python 数据清洗与预处理实战

本专题系统讲解 Python 在数据清洗与预处理中的核心技术,包括使用 Pandas 进行缺失值处理、异常值检测、数据格式化、特征工程与数据转换,结合 NumPy 高效处理大规模数据。通过实战案例,帮助学习者掌握 如何处理混乱、不完整数据,为后续数据分析与机器学习模型训练打下坚实基础。

33

2026.01.31

数据类型有哪几种
数据类型有哪几种

数据类型有整型、浮点型、字符型、字符串型、布尔型、数组、结构体和枚举等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

338

2023.10.31

php数据类型
php数据类型

本专题整合了php数据类型相关内容,阅读专题下面的文章了解更多详细内容。

225

2025.10.31

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

138

2026.02.12

counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

203

2023.11.20

mysql标识符无效错误怎么解决
mysql标识符无效错误怎么解决

mysql标识符无效错误的解决办法:1、检查标识符是否被其他表或数据库使用;2、检查标识符是否包含特殊字符;3、使用引号包裹标识符;4、使用反引号包裹标识符;5、检查MySQL的配置文件等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

210

2023.12.04

Python标识符有哪些
Python标识符有哪些

Python标识符有变量标识符、函数标识符、类标识符、模块标识符、下划线开头的标识符、双下划线开头、双下划线结尾的标识符、整型标识符、浮点型标识符等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

324

2024.02.23

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

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

精品课程

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

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

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

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