0

0

Pandas矢量化操作:实现带阈值重置的序列计数功能

心靈之曲

心靈之曲

发布时间:2025-09-24 10:06:40

|

574人浏览过

|

来源于php中文网

原创

Pandas矢量化操作:实现带阈值重置的序列计数功能

本文详细介绍了如何利用Pandas的矢量化操作,高效地对DataFrame中连续相同的数值序列进行计数,并实现当计数达到预设阈值时自动重置的功能。通过巧妙结合groupby、cumcount以及模运算,该方法能够避免低效的循环,显著提升数据处理性能,适用于股票信号、事件序列分析等场景。

问题背景与需求

在数据分析中,我们经常需要识别并统计数据序列中连续重复的模式。例如,在一个股票交易数据集中,我们可能需要计算连续上涨(信号为1)或连续下跌(信号为-1)的天数。更进一步,如果要求当连续计数达到某个特定阈值(比如5)时,计数器需要自动重置并重新开始计数,这就对传统的循环计数方法提出了挑战,尤其是在处理大规模数据时,循环操作效率低下。

考虑以下示例DataFrame,其中包含股票价格(price)和涨跌信号(sign):

import pandas as pd

data = {
    'price': [13, 12, 11, 12, 13, 14, 14, 14, 14, 14, 14],
    'sign': [1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1]
}
df = pd.DataFrame(data)
print("原始DataFrame:")
print(df)

期望的结果是在新列count中,对sign列的连续相同值进行计数,并在计数达到5时重置:

   price  sign  count
0     13     1      1
1     12     1      2
2     11    -1      1
3     12    -1      2
4     13     1      1
5     14     1      2
6     14     1      3
7     14     1      4
8     14     1      5
9     14     1      1  # 达到5后重置
10    14     1      2

Pandas 矢量化解决方案

为了高效地实现这一功能,我们可以利用Pandas的矢量化操作,特别是groupby、cumcount和模运算。核心思路是首先识别出sign列中所有连续相同的块,然后对每个块内部进行累积计数,最后通过模运算实现阈值重置。

1. 识别连续块

识别连续相同值的块是解决问题的关键第一步。我们可以通过比较当前值与其前一个值是否相等来判断连续性。当值发生变化时,就标志着一个新的连续块的开始。

  • df['sign'].shift(): 获取sign列的上一行值。
  • df['sign'].ne(df['sign'].shift()): 比较当前sign值是否不等于上一个sign值。这将生成一个布尔序列,True表示值发生了变化(即新块的开始),False表示值未变。
  • .cumsum(): 对布尔序列进行累积求和。由于True被视为1,False被视为0,cumsum()会在每次遇到True时加1,从而为每个连续块生成一个唯一的组标识符。
# 识别连续块
df['consecutive_group'] = df['sign'].ne(df['sign'].shift()).cumsum()
print("\n带有连续块标识的DataFrame:")
print(df)

输出如下:

   price  sign  consecutive_group
0     13     1                  1  # 第一个块 (sign=1)
1     12     1                  1
2     11    -1                  2  # 第二个块 (sign=-1)
3     12    -1                  2
4     13     1                  3  # 第三个块 (sign=1)
5     14     1                  3
6     14     1                  3
7     14     1                  3
8     14     1                  3
9     14     1                  3
10    14     1                  3

可以看到,consecutive_group列成功地为每个连续的sign值序列分配了一个唯一的整数ID。

2. 块内累积计数

有了连续块的标识后,我们就可以对每个块内部进行累积计数。Pandas的groupby()方法结合cumcount()可以非常方便地实现这一点。

  • df.groupby(df['consecutive_group']): 按照consecutive_group列进行分组。
  • .cumcount(): 对每个分组内部的行进行累积计数,从0开始。
# 对每个连续块进行累积计数(从0开始)
df['raw_count'] = df.groupby(df['consecutive_group']).cumcount()
print("\n带有原始累积计数的DataFrame:")
print(df)

输出如下:

   price  sign  consecutive_group  raw_count
0     13     1                  1          0
1     12     1                  1          1
2     11    -1                  2          0
3     12    -1                  2          1
4     13     1                  3          0
5     14     1                  3          1
6     14     1                  3          2
7     14     1                  3          3
8     14     1                  3          4
9     14     1                  3          5
10    14     1                  3          6

此时,raw_count列已经正确地显示了每个连续块内部从0开始的计数。

燕雀Logo
燕雀Logo

为用户提供LOGO免费设计在线生成服务

下载

3. 应用重置阈值并调整为1开始计数

现在我们需要实现计数达到阈值(例如5)时重置,并且最终的计数是从1开始而不是从0开始。这可以通过模运算(%)和加1操作来实现。

  • raw_count % 5: 对raw_count进行模5运算。当raw_count达到0, 1, 2, 3, 4时,结果分别为0, 1, 2, 3, 4。当raw_count达到5时,结果变为0,实现了重置。
  • + 1: 由于我们希望计数从1开始,所以对模运算的结果加1。这样,0, 1, 2, 3, 4就变成了1, 2, 3, 4, 5。

将以上所有步骤整合到一行代码中:

# 完整的矢量化解决方案
threshold = 5
df['count'] = df.groupby(df['sign'].ne(df['sign'].shift()).cumsum()).cumcount() % threshold + 1

print("\n最终结果DataFrame:")
print(df[['price', 'sign', 'count']])

最终输出:

最终结果DataFrame:
   price  sign  count
0     13     1      1
1     12     1      2
2     11    -1      1
3     12    -1      2
4     13     1      1
5     14     1      2
6     14     1      3
7     14     1      4
8     14     1      5
9     14     1      1
10    14     1      2

可以看到,count列完美地实现了连续计数并在达到5时重置为1的功能。

详细步骤解析(中间列展示)

为了更清晰地理解整个过程,我们可以将中间步骤的列也添加到DataFrame中进行观察:

import pandas as pd

data = {
    'price': [13, 12, 11, 12, 13, 14, 14, 14, 14, 14, 14],
    'sign': [1, 1, -1, -1, 1, 1, 1, 1, 1, 1, 1]
}
df = pd.DataFrame(data)
threshold = 5

df_detailed = df.assign(
    # 步骤1: 识别连续块的起始点 (True表示变化)
    is_new_block=df['sign'].ne(df['sign'].shift()),
    # 步骤2: 为每个连续块生成唯一ID
    consecutive_group=df['sign'].ne(df['sign'].shift()).cumsum(),
    # 步骤3: 在每个块内进行0-based累积计数
    cum_counter_0based=df.groupby(df['sign'].ne(df['sign'].shift()).cumsum()).cumcount(),
    # 步骤4: 应用模运算实现重置
    cum_counter_mod_threshold=df.groupby(df['sign'].ne(df['sign'].shift()).cumsum()).cumcount() % threshold,
    # 步骤5: 最终的1-based计数
    count=df.groupby(df['sign'].ne(df['sign'].shift()).cumsum()).cumcount() % threshold + 1
)

print("\n详细步骤解析DataFrame:")
print(df_detailed)

输出:

详细步骤解析DataFrame:
    price  sign  is_new_block  consecutive_group  cum_counter_0based  cum_counter_mod_threshold  count
0      13     1          True                  1                   0                          0      1
1      12     1         False                  1                   1                          1      2
2      11    -1          True                  2                   0                          0      1
3      12    -1         False                  2                   1                          1      2
4      13     1          True                  3                   0                          0      1
5      14     1         False                  3                   1                          1      2
6      14     1         False                  3                   2                          2      3
7      14     1         False                  3                   3                          3      4
8      14     1         False                  3                   4                          4      5
9      14     1         False                  3                   5                          0      1
10     14     1         False                  3                   6                          1      2

通过观察is_new_block、consecutive_group、cum_counter_0based、cum_counter_mod_threshold和count列,可以清晰地看到每一步的逻辑如何协同工作,最终生成期望的计数结果。

注意事项与总结

  • 性能优势: 这种矢量化方法比使用Python循环(如for循环或apply结合自定义函数)在处理大型数据集时效率更高,因为Pandas底层是C语言实现,优化了这类操作。
  • 通用性: 这里的threshold值可以根据具体需求进行调整。例如,如果希望每3次重置,则将% 5改为% 3即可。
  • 适用场景: 这种技术不仅适用于股票信号分析,还可以应用于任何需要对连续事件或状态进行计数并在达到特定条件时重置的场景,例如日志分析、传感器数据处理等。
  • 初始值: df['sign'].shift()在第一行会产生NaN。ne()操作会自动处理NaN,将其与任何非NaN值比较都视为不相等,因此is_new_block在第一行通常是True,这符合我们对新序列开始的预期。

通过上述方法,我们能够利用Pandas强大的矢量化能力,简洁而高效地解决复杂的序列计数与重置问题,极大地提升了数据处理的效率和代码的可读性。

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
C语言变量命名
C语言变量命名

c语言变量名规则是:1、变量名以英文字母开头;2、变量名中的字母是区分大小写的;3、变量名不能是关键字;4、变量名中不能包含空格、标点符号和类型说明符。php中文网还提供c语言变量的相关下载、相关课程等内容,供大家免费下载使用。

401

2023.06.20

c语言入门自学零基础
c语言入门自学零基础

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,本专题为大家c语言入门自学零基础的相关文章,以及相关课程,感兴趣的朋友千万不要错过了。

619

2023.07.25

c语言运算符的优先级顺序
c语言运算符的优先级顺序

c语言运算符的优先级顺序是括号运算符 > 一元运算符 > 算术运算符 > 移位运算符 > 关系运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符。本专题为大家提供c语言运算符相关的各种文章、以及下载和课程。

354

2023.08.02

c语言数据结构
c语言数据结构

数据结构是指将数据按照一定的方式组织和存储的方法。它是计算机科学中的重要概念,用来描述和解决实际问题中的数据组织和处理问题。数据结构可以分为线性结构和非线性结构。线性结构包括数组、链表、堆栈和队列等,而非线性结构包括树和图等。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

259

2023.08.09

c语言random函数用法
c语言random函数用法

c语言random函数用法:1、random.random,随机生成(0,1)之间的浮点数;2、random.randint,随机生成在范围之内的整数,两个参数分别表示上限和下限;3、random.randrange,在指定范围内,按指定基数递增的集合中获得一个随机数;4、random.choice,从序列中随机抽选一个数;5、random.shuffle,随机排序。

606

2023.09.05

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

530

2023.09.20

c语言get函数的用法
c语言get函数的用法

get函数是一个用于从输入流中获取字符的函数。可以从键盘、文件或其他输入设备中读取字符,并将其存储在指定的变量中。本文介绍了get函数的用法以及一些相关的注意事项。希望这篇文章能够帮助你更好地理解和使用get函数 。

646

2023.09.20

c数组初始化的方法
c数组初始化的方法

c语言数组初始化的方法有直接赋值法、不完全初始化法、省略数组长度法和二维数组初始化法。详细介绍:1、直接赋值法,这种方法可以直接将数组的值进行初始化;2、不完全初始化法,。这种方法可以在一定程度上节省内存空间;3、省略数组长度法,这种方法可以让编译器自动计算数组的长度;4、二维数组初始化法等等。

604

2023.09.22

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

158

2026.01.28

热门下载

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

精品课程

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

共4课时 | 22.3万人学习

Django 教程
Django 教程

共28课时 | 3.6万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.3万人学习

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

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