0

0

Pandas高效计算基于类别变化的滚动时间差

心靈之曲

心靈之曲

发布时间:2025-10-14 13:36:12

|

658人浏览过

|

来源于php中文网

原创

Pandas高效计算基于类别变化的滚动时间差

本文详细介绍了如何在pandas dataframe中高效计算一个时间列相对于另一个类别列值发生变化时的滚动时间差。通过利用`shift()`、`ne()`、`cumsum()`组合创建连续组,并结合`groupby().transform('first')`获取组内起始时间,最终实现矢量化操作,避免了低效的循环,从而显著提升数据处理性能。

引言:问题背景与挑战

在数据分析场景中,我们经常需要根据某个特定条件的变化来计算时间或其他数值的累积或差值。一个常见需求是,给定一个包含时间戳(t)和类别标识符(A)的DataFrame,我们希望计算从类别A的当前值首次出现(即A值发生变化)到当前行所经过的时间。传统上,许多开发者可能会倾向于使用Python的for循环来遍历DataFrame并进行判断,但这在处理大型数据集时效率极低,计算成本高昂。

例如,考虑以下数据结构:

A t X (期望输出)
1 0.0 0
1 3.2 3.2
1 3.9 3.9
1 18.0 18
1 27.4 27.4
3 47.4 0
3 50.2 2.8
3 57.2 9.8
3 64.8 17.4
3 76.4 29.0
2 80.5 0
1 85.3 0
1 87.4 2.1

我们的目标是生成X列,其中每个值表示当前行t距离其所属的连续A值块开始时的t值的差。当A的值发生变化时,新的A块的第一个X值应为0。

解决方案:Pandas矢量化操作

Pandas库提供了强大的矢量化操作,能够以远超for循环的效率处理此类问题。核心思路是:

  1. 识别连续的类别组:将DataFrame根据A列中连续相同值的块进行分组。
  2. 获取组内起始时间:对于每个识别出的组,获取其第一个t值。
  3. 计算时间差:用当前行的t值减去其所属组的起始t值。

下面是具体的实现步骤和代码示例。

步骤一:创建示例DataFrame

首先,我们创建一个与问题描述相符的Pandas DataFrame:

import pandas as pd

data = {
    'A': [1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 2, 1, 1],
    't': [0.0, 3.2, 3.9, 18.0, 27.4, 47.4, 50.2, 57.2, 64.8, 76.4, 80.5, 85.3, 87.4]
}
df = pd.DataFrame(data)
print("原始DataFrame:")
print(df)

输出:

Toolify.ai
Toolify.ai

Toolify.ai是一个专门收集、评测AI工具和服务的网址导航站

下载
原始DataFrame:
    A      t
0   1    0.0
1   1    3.2
2   1    3.9
3   1   18.0
4   1   27.4
5   3   47.4
6   3   50.2
7   3   57.2
8   3   64.8
9   3   76.4
10  2   80.5
11  1   85.3
12  1   87.4

步骤二:识别连续的类别组

这是解决问题的关键一步。我们需要为A列中每个连续的相同值块生成一个唯一的标识符。这可以通过结合使用shift()、ne()和cumsum()方法来实现:

  • df['A'].shift():将A列向下移动一行,这样每一行都可以与上一行的A值进行比较。
  • df['A'].ne(df['A'].shift()):比较当前行的A值是否不等于上一行的A值。如果不同,则返回True,表示类别发生了变化;否则返回False。
  • .cumsum():对布尔序列进行累积求和。每当遇到True(即类别变化)时,累加值增加1。这样,每个连续的类别块都会得到一个唯一的整数作为组标识符。
group = df['A'].ne(df['A'].shift()).cumsum()
print("\n生成的连续组标识符:")
print(group)

输出:

生成的连续组标识符:
0     1
1     1
2     1
3     1
4     1
5     2
6     2
7     2
8     2
9     2
10    3
11    4
12    4
Name: A, dtype: int64

可以看到,A值为1的第一个连续块被标记为组1,A值为3的块被标记为组2,依此类推。

步骤三:获取每个组的起始时间

有了组标识符后,我们可以使用groupby()结合transform('first')来获取每个组的第一个t值。transform('first')的优点在于它会返回一个与原始DataFrame长度相同的Series,其中每个值都是其所属组的第一个元素。

first_t_per_group = df.groupby(group)['t'].transform('first')
print("\n每个组的起始时间 (广播到每行):")
print(first_t_per_group)

输出:

每个组的起始时间 (广播到每行):
0      0.0
1      0.0
2      0.0
3      0.0
4      0.0
5     47.4
6     47.4
7     47.4
8     47.4
9     47.4
10    80.5
11    85.3
12    85.3
Name: t, dtype: float64

步骤四:计算时间差

最后,我们将原始的t列减去每个组的起始t值,即可得到所需的滚动时间差X:

df['X'] = df['t'].sub(first_t_per_group)
print("\n最终结果DataFrame:")
print(df)

输出:

最终结果DataFrame:
    A      t      X
0   1    0.0    0.0
1   1    3.2    3.2
2   1    3.9    3.9
3   1   18.0   18.0
4   1   27.4   27.4
5   3   47.4    0.0
6   3   50.2    2.8
7   3   57.2    9.8
8   3   64.8   17.4
9   3   76.4   29.0
10  2   80.5    0.0
11  1   85.3    0.0
12  1   87.4    2.1

这个结果与我们期望的输出完全一致。

完整代码示例

将上述步骤整合,完整的解决方案代码如下:

import pandas as pd

# 1. 创建示例DataFrame
data = {
    'A': [1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 2, 1, 1],
    't': [0.0, 3.2, 3.9, 18.0, 27.4, 47.4, 50.2, 57.2, 64.8, 76.4, 80.5, 85.3, 87.4]
}
df = pd.DataFrame(data)

# 2. 识别连续的类别组
# df['A'].shift() 获取上一行的A值
# df['A'].ne(df['A'].shift()) 比较当前A值是否不等于上一行A值,生成布尔序列
# .cumsum() 对布尔序列进行累积求和,为每个连续的A值块生成唯一组ID
group = df['A'].ne(df['A'].shift()).cumsum()

# 3. 计算每个组的起始时间并广播
# df.groupby(group)['t'] 按生成的组ID对t列进行分组
# .transform('first') 获取每个组的第一个t值,并将其广播到组内的所有行
first_t_per_group = df.groupby(group)['t'].transform('first')

# 4. 计算时间差
# df['t'].sub(...) 用当前t值减去其所属组的起始t值
df['X'] = df['t'].sub(first_t_per_group)

print("最终计算结果:")
print(df)

注意事项与总结

  • 效率优势:这种方法完全依赖于Pandas的矢量化操作和C语言实现,相比Python原生的for循环,在处理大规模数据集时能提供显著的性能提升。
  • 通用性:此模式不仅适用于时间差计算,也可以推广到其他需要基于连续类别变化的组内统计(如组内计数、组内求和等)的场景,只需将transform('first')替换为相应的聚合函数即可。
  • shift()的第一个值:df['A'].shift()在第一行会产生NaN。当ne()与NaN比较时,结果通常是True,因此cumsum()会从1开始,这对于生成第一个组的标识符是正确的行为。
  • 数据类型:确保时间列t是数值类型(如float或int),以便进行数学运算。如果它是日期时间对象,则需要先转换为时间差(timedelta)或Unix时间戳进行计算。

通过掌握shift()、ne()、cumsum()以及groupby().transform()的组合使用,我们可以高效且优雅地解决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语言变量的相关下载、相关课程等内容,供大家免费下载使用。

407

2023.06.20

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

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

627

2023.07.25

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

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

361

2023.08.02

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

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

263

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,随机排序。

617

2023.09.05

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

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

547

2023.09.20

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

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

661

2023.09.20

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

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

611

2023.09.22

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

283

2026.02.13

热门下载

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

精品课程

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

共4课时 | 22.4万人学习

Django 教程
Django 教程

共28课时 | 4.3万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.6万人学习

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

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