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

如何使用pandas.ewm.mean实现带半衰期的非调整衰减计算?

问题描述

我创建了如下测试DataFrame:

import pandas
index = pandas.date_range('2022-11-01 08:00', '2022-11-01 08:02', freq='T')
data = [1] + [0] * 2
df = pandas.DataFrame(data, index, columns=['val'])

得到的DataFrame如下:

val
2022-11-01 08:00:00   1
2022-11-01 08:01:00   0
2022-11-01 08:02:00   0

我尝试用1分钟的半衰期对该序列进行衰减计算:

df.ewm(halflife='1 minute', times=df.index).mean()

得到结果:

val
2022-11-01 08:00:00   1.000000
2022-11-01 08:01:00   0.333333
2022-11-01 08:02:00   0.142857

这个结果不符合预期:我认为半衰期为1分钟时,08:01的数值应衰减为原来的1/2,即0.5。

查阅文档后发现有adjust参数,当设置为False时,衰减计算方式符合我的需求(对应递归公式:当前步加权平均值 = α×当前值 + (1-α)×上一步加权平均值,其中α = 1 - 0.5^(Δt/半衰期),Δt为相邻时间点的间隔时长)。但设置adjust=False时出现报错:

df.ewm(halflife='1 minute', times=df.index, adjust=False).mean()

NotImplementedError: times is not supported with adjust=False.

移除times参数后又出现新错误:

df.ewm(halflife='1 minute', adjust=False).mean()

ValueError: halflife can only be a timedelta convertible argument if times is not None.

请问如何使用半衰期实现我预期的衰减计算?

更新(根据评论)

@RanA提出以下代码可行,但我不确定其中halflife的单位:
我运行了如下测试:

import pandas
index = pandas.DatetimeIndex(['2022-11-01 08:00', '2022-11-01 08:01', '2022-11-01 08:03'])
data = [1] + [0] * 2
df = pandas.DataFrame(data, index, columns=['val'])
df.ewm(halflife=1, adjust=False).mean()

注意该索引是非规则的,得到结果:

val
2022-11-01 08:00:00   1.00
2022-11-01 08:01:00   0.50
2022-11-01 08:03:00   0.25      
解决方案

问题核心是pandas当前版本中,ewm方法不支持同时使用times参数(基于实际时间计算)和adjust=False(递归式加权)。要实现预期的衰减效果,可以按以下两种场景处理:

场景1:非规则时间序列(或严格基于实际时间间隔计算)

手动计算时间间隔对应的衰减因子,实现递归式加权平均:

import pandas as pd

# 构建测试数据
index = pd.date_range('2022-11-01 08:00', '2022-11-01 08:02', freq='T')
data = [1] + [0] * 2
df = pd.DataFrame(data, index, columns=['val'])

# 计算相邻时间点的间隔(转换为分钟)
df['time_gap'] = df.index.to_series().diff().dt.total_seconds() / 60
df['time_gap'] = df['time_gap'].fillna(0)  # 第一个点间隔为0

# 设定半衰期(分钟),计算衰减因子:因子 = 0.5^(时间间隔/半衰期)
halflife_min = 1
df['decay_factor'] = 0.5 ** (df['time_gap'] / halflife_min)

# 递归计算加权平均值
ewma_results = [df['val'].iloc[0]]
for i in range(1, len(df)):
    current_val = ewma_results[-1] * df['decay_factor'].iloc[i] + df['val'].iloc[i] * (1 - df['decay_factor'].iloc[i])
    ewma_results.append(current_val)

df['expected_ewma'] = ewma_results
print(df[['val', 'expected_ewma']])

输出结果:

val  expected_ewma
2022-11-01 08:00:00   1        1.000000
2022-11-01 08:01:00   0        0.500000
2022-11-01 08:02:00   0        0.250000

场景2:规则时间序列(固定时间间隔)

如果序列是固定间隔(比如每分钟一个数据点),可以直接用halflife=间隔步数结合adjust=False:

df.ewm(halflife=1, adjust=False).mean()

这里的halflife=1指1个数据步长,对于1分钟间隔的序列,就等价于1分钟半衰期,计算结果完全符合预期。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 01:55:19