0

0

Pandas时间窗口内事件检测:按团队分组查找特定事件

花韻仙語

花韻仙語

发布时间:2025-11-12 12:34:26

|

232人浏览过

|

来源于php中文网

原创

Pandas时间窗口内事件检测:按团队分组查找特定事件

本教程详细阐述了如何使用pandas的`groupby`和`rolling`功能,在指定时间窗口内按组(例如团队)检测特定事件的发生。文章通过示例代码演示了两种场景:排除当前行和包含当前行进行时间窗口内事件查找,并提供了关键操作如时间戳转换、dataframe反转与`shift`的详细解释,旨在帮助用户高效处理时序数据中的复杂条件查询。

在数据分析中,我们经常需要处理包含时间序列信息的DataFrame,并根据时间窗口内的条件来标记或聚合数据。一个常见的需求是,针对某个分组(如“团队”),判断在当前事件发生后的特定时间范围内是否发生了另一个特定事件。本教程将深入探讨如何利用Pandas的强大功能,特别是groupby、rolling以及时间序列操作,高效地解决这类问题。

1. 数据准备

首先,我们需要一个包含事件、分组标识和时间戳的DataFrame。为了确保时间相关的操作能够正确执行,时间戳列必须被转换为Pandas的datetime类型。

import pandas as pd

# 示例数据
data = {
    'event': [1, 1, 3, 2, 3, 1, 2, 3, 4, 5],
    'team': ['A', 'A', 'B', 'A', 'B', 'C', 'C', 'C', 'D', 'D'],
    'timeStamp': ['2023-07-23 14:57:13.357', '2023-07-23 14:57:14.357',
                  '2023-07-23 14:57:15.357', '2023-07-23 14:57:16.357',
                  '2023-07-23 14:57:20.357', '2023-07-23 14:57:13.357',
                  '2023-07-23 14:57:18.357', '2023-07-23 14:57:23.357',
                  '2023-07-23 14:57:23.357', '2023-07-23 14:57:25.357']
}
df = pd.DataFrame(data)

# 将 'timeStamp' 列转换为 datetime 类型
df['timeStamp'] = pd.to_datetime(df['timeStamp'])

print("原始DataFrame:")
print(df)

2. 核心概念:groupby与rolling

要解决按团队分组并在时间窗口内查找事件的问题,我们需要结合使用groupby和rolling。

  • groupby('team'): 确保我们只在同一个团队内部进行时间窗口的检测,避免跨团队的错误判断。
  • rolling('7s', on='timeStamp'): 这是实现时间窗口检测的关键。'7s' 定义了一个7秒的时间窗口。on='timeStamp' 指定了基于哪个时间列来创建滚动窗口。需要注意的是,rolling窗口默认是“前向”的,即包含当前时间点及其之前指定时间范围内的所有数据。然而,我们的目标是查找当前行 之后 的事件。为了实现“后向”查找(即查找未来事件),我们需要一些技巧。

3. 场景一:排除当前行,检测未来7秒内是否存在特定事件

我们的目标是,对于DataFrame中的每一行,判断在当前行发生后7秒内(不包括当前行本身)同一团队中是否存在事件类型为“2”的记录。

为了实现向前看(查找未来事件)并排除当前行,我们将采用以下策略:

简篇AI排版
简篇AI排版

AI排版工具,上传图文素材,秒出专业效果!

下载
  1. 创建一个布尔列,标记 event == 2 的行。
  2. 将DataFrame进行反转 ([::-1])。这样,原本的“未来”就变成了反转后DataFrame的“过去”,rolling窗口就可以正常工作了。
  3. 在反转后的数据上,按团队进行groupby,并应用rolling('7s', on='timeStamp')。
  4. 在每个滚动窗口内,使用 shift(1) 将布尔值向下移动一位,从而排除当前行(在原始DataFrame中对应的行)。
  5. 对shift(1)后的结果取max(),判断窗口内是否存在 True。
  6. 将计算出的结果合并回原始DataFrame。
# 步骤1: 创建布尔列
df_temp = df.assign(is_2_in_7_sec_raw=df['event'].eq(2))

# 步骤2 & 3: 反转DataFrame,按团队分组,并应用rolling窗口
# 注意:这里对 df_temp 进行 df['team'] 的 groupby 是为了在原始索引上进行分组,
# 但 rolling 操作是在 df_temp 的时间戳上进行的。
# 更直接的方式是先进行 assign 和反转,再 groupby
rolled_results = (df_temp[::-1] # 反转DataFrame以实现“向前看”
                  .groupby('team')
                  .rolling('7s', on='timeStamp')
                  ['is_2_in_7_sec_raw']
                  .apply(lambda x: x.shift(1).max()) # shift(1) 排除当前行,max() 检查是否有 True
                  .eq(1) # 转换为布尔值
                  .reset_index())

# 步骤4: 合并结果
# 需要将原始DataFrame的索引重置,以便与 rolled_results 的 level_1 索引(原索引)进行合并
df_output_exclude_self = (df.reset_index()
                          .merge(rolled_results, how='left', left_on=['team', 'index'], right_on=['team', 'level_1'])
                          .set_index('index')
                          .reindex(df.index) # 确保原始顺序
                         )

# 清理合并后的多余列并重命名
df_output_exclude_self = df_output_exclude_self[['event', 'team', 'timeStamp', 'is_2_in_7_sec_raw']]
df_output_exclude_self = df_output_exclude_self.rename(columns={'is_2_in_7_sec_raw': 'is_2_in_7_sec'})

print("\n场景一:排除当前行,检测未来7秒内是否存在事件'2':")
print(df_output_exclude_self)

代码解释:

  • df.assign(is_2_in_7_sec_raw=df['event'].eq(2)): 创建一个临时列 is_2_in_7_sec_raw,如果 event 等于 2,则为 True,否则为 False。
  • [::-1]: 这是Python切片操作,用于反转DataFrame的行顺序。这一步至关重要,它使得rolling窗口在逻辑上从“未来”向“过去”滑动,从而实现了我们“向前看”的需求。
  • groupby('team'): 确保每个团队独立进行计算。
  • rolling('7s', on='timeStamp'): 定义了一个基于时间戳的7秒滚动窗口。由于DataFrame已反转,这个窗口现在会捕获当前行在原始时间序列中的“未来”7秒内的事件。
  • ['is_2_in_7_sec_raw'].apply(lambda x: x.shift(1).max()):
    • x 代表滚动窗口内的数据(一个Series)。
    • x.shift(1) 将窗口内的值向下移动一位。在反转的DataFrame中,这实际上排除了当前行(在原始DataFrame中对应的行),只考虑了“未来”的事件。
    • .max():如果窗口内(排除当前行后)有任何 True 值,则返回 True。
  • .eq(1):将 max() 返回的布尔值(True/False 或 1/0)确保转换为标准的布尔类型。
  • .reset_index():将groupby和rolling产生的多层索引展平,方便后续合并。
  • merge(...):将计算出的布尔结果合并回原始DataFrame,通过 team 和原始索引进行匹配。
  • set_index('index').reindex(df.index):恢复原始DataFrame的索引和行顺序。

4. 场景二:包含当前行,检测未来7秒内是否存在特定事件

如果需要包含当前行本身进行检测,逻辑会稍微简化,无需使用 shift(1)。

# 步骤1: 创建布尔列
df_temp_include_self = df.assign(is_2_in_7_sec_raw=df['event'].eq(2))

# 步骤2 & 3: 反转DataFrame,按团队分组,并应用rolling窗口
rolled_results_include_self = (df_temp_include_self[::-1] # 反转DataFrame
                               .groupby('team')
                               .rolling('7s', on='timeStamp')
                               ['is_2_in_7_sec_raw']
                               .max() # 直接取max(),包含当前行
                               .astype(bool) # 确保为布尔类型
                               .reset_index())

# 步骤4: 合并结果
df_output_include_self = (df.reset_index()
                          .merge(rolled_results_include_self, how='left', left_on=['team', 'index'], right_on=['team', 'level_1'])
                          .set_index('index')
                          .reindex(df.index)
                         )

# 清理合并后的多余列并重命名
df_output_include_self = df_output_include_self[['event', 'team', 'timeStamp', 'is_2_in_7_sec_raw']]
df_output_include_self = df_output_include_self.rename(columns={'is_2_in_7_sec_raw': 'is_2_in_7_sec'})

print("\n场景二:包含当前行,检测未来7秒内是否存在事件'2':")
print(df_output_include_self)

5. 注意事项与性能考量

  • 时间戳类型: 确保用于rolling的时间戳列是Pandas的datetime类型,否则时间窗口(如'7s')将无法正常工作。
  • 窗口方向: Pandas的rolling默认是前向窗口(包含当前点和之前的点)。为了实现“向前看”(即查看未来事件),我们巧妙地使用了DataFrame反转 ([::-1])。理解这一机制对于正确应用至关重要。
  • shift() 的作用: shift(1) 在这里用于在滚动窗口内排除当前行。它将 Series 中的值向下移动一位,使得当前位置的值变为前一个位置的值,从而将当前行的值从考虑范围中移除。
  • 性能: 对于非常大的数据集,apply函数可能会比优化的Pandas/NumPy操作慢。虽然对于大多数情况足够高效,但在处理亿级数据时,可能需要考虑更底层的优化或使用Dask等工具
  • 索引管理: 在合并结果时,由于groupby和rolling可能会改变索引结构,使用reset_index()、merge()和set_index().reindex()组合是确保结果正确对齐和恢复原始顺序的常用且健壮的方法。

6. 总结

本教程详细介绍了如何利用Pandas的groupby和rolling功能,结合时间序列处理技巧,在复杂的时间窗口内按分组检测特定事件。通过理解DataFrame反转和shift操作的精妙应用,我们能够灵活地实现“向前看”的事件检测,无论是排除当前行还是包含当前行。掌握这些技术将极大地提升您在处理时序数据时的分析能力。

相关专题

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

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

751

2023.06.15

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

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

636

2023.07.20

python能做什么
python能做什么

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

758

2023.07.25

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

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

618

2023.07.31

python教程
python教程

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

1262

2023.08.03

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

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

547

2023.08.04

python eval
python eval

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

577

2023.08.04

scratch和python区别
scratch和python区别

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

706

2023.08.11

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

34

2026.01.14

热门下载

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

精品课程

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

共4课时 | 0.6万人学习

Django 教程
Django 教程

共28课时 | 3万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.1万人学习

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

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