You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从时间序列Pandas DataFrame中识别事件并计算曲线下面积?

时间序列事件识别与面积计算解决方案

一、先明确事件定义(核心前提)

你得先把「高于零的上升段」的规则量化,不然代码没法落地,给你两种常用定义参考:

  1. 基础版:连续高于零的区间
    • 事件起始:数据点从≤0变为>0的时刻
    • 事件结束:数据点从>0变为≤0的时刻
    • 中间所有连续>0的点都归为同一个事件
  2. 进阶版:连续高于零且趋势上升的区间
    • 在基础版规则上,额外要求事件区间内整体趋势向上(比如用相邻点差值为正的占比、或线性拟合斜率为正来判断)

二、用Pandas识别事件区间

假设你的DataFrame是df,包含timestamp(已排序的时间戳列)和value(数值列)

步骤1:标记事件状态

给每个数据点标记是否处于事件中:

# 基础版:标记>0的点为事件内
df['in_event'] = (df['value'] > 0).astype(int)

# 进阶版:额外加入上升趋势判断(以相邻差值≥0为例)
# df['diff'] = df['value'].diff().fillna(0)
# df['in_event'] = ((df['value'] > 0) & (df['diff'] >= 0)).astype(int)

步骤2:给每个事件分配唯一ID

通过事件状态的变化,把连续的事件点归为同一个ID:

# 标记新事件的起始点:从非事件(0)转为事件(1)的位置
df['event_start'] = (df['in_event'] == 1) & (df['in_event'].shift(1) == 0)
# 生成事件ID:累计起始标记的次数
df['event_id'] = df['event_start'].cumsum()
# 非事件的ID设为0,方便后续过滤
df['event_id'] = df['event_id'].where(df['in_event'] == 1, 0)

步骤3:提取事件起止时间

按事件ID分组,提取每个事件的最早和最晚时间:

event_info = df[df['event_id'] != 0].groupby('event_id').agg(
    start_time=('timestamp', 'min'),
    end_time=('timestamp', 'max')
).reset_index()

三、计算每个事件的曲线下面积(AUC)

用梯形法计算最贴合时间序列的面积,借助scipy的trapezoid函数:

from scipy.integrate import trapezoid

# 定义单个事件的AUC计算函数
def calculate_auc(group):
    # 确保数据按时间排序
    group_sorted = group.sort_values('timestamp')
    # 把时间转为数值(比如秒)作为x轴,数值作为y轴
    x = (group_sorted['timestamp'] - group_sorted['timestamp'].iloc[0]).dt.total_seconds()
    y = group_sorted['value']
    return trapezoid(y, x)

# 分组计算每个事件的AUC
event_auc = df[df['event_id'] != 0].groupby('event_id').apply(calculate_auc).reset_index(name='auc')

# 合并事件起止时间和AUC结果
final_result = event_info.merge(event_auc, on='event_id')

四、结果存储

把最终结果导出成常用格式即可:

# 保存为CSV
final_result.to_csv('event_auc_results.csv', index=False)

# 或者保存为Excel
# final_result.to_excel('event_auc_results.xlsx', index=False)

补充提示

  • 如果你的时间戳不是datetime类型,先转换:df['timestamp'] = pd.to_datetime(df['timestamp'])
  • 进阶版的趋势判断可以灵活调整,比如用滑动窗口或线性回归:
    from scipy.stats import linregress
    
    def is_rising(group):
        x = range(len(group))
        y = group['value'].values
        slope, _, _, _, _ = linregress(x, y)
        return slope > 0
    
    # 过滤出真正上升的事件
    rising_events = df[df['event_id'] != 0].groupby('event_id').filter(is_rising)
    # 再对过滤后的事件重新计算信息和AUC即可
    

内容的提问来源于stack exchange,提问作者abhi_kr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 07:25:23