cumsum直接累加忽略时间间隔,本质错误;正确做法是按梯形法计算各点时间权重(前后时间差中点),乘以对应值后再cumsum,并须用.dt.total_seconds()转为浮点秒数。

用 cumsum 做不规则时间累加,本质是错的
直接对原始序列调用 cumsum 无法体现时间权重——它只按行序累加,完全忽略相邻点之间的时间差。比如传感器每 5 秒、30 秒、2 秒采一次,cumsum 会把它们全当“等间隔”处理,结果严重失真。
真正需要的是:每个值乘以它“覆盖的时间长度”,再做前缀和。这个“覆盖长度”通常取前后时间戳中点差(梯形法),首尾特殊处理。
实操建议:
- 先确保时间列是
pd.Timestamp或datetime64[ns]类型,否则.diff()返回NaT - 用
df['time'].diff().shift(-1)+df['time'].diff()算出每个点对应的时间跨度,再除以 2 得梯形权重 - 首行权重用
df.loc[1, 'time'] - df.loc[0, 'time'],末行用df.loc[-1, 'time'] - df.loc[-2, 'time'],更稳妥
手动构造时间权重列比依赖 resample 更可控
resample 强制等频重采样(如 '5S'),会插值或丢点,破坏原始时序特征;而积分计算必须忠于原始采样点及其间隔。所以应绕过 resample,自己算权重。
立即学习“Python免费学习笔记(深入)”;
示例关键步骤:
df['dt'] = df['time'].diff().fillna(pd.Timedelta(0)) df['dt_next'] = df['time'].diff().shift(-1).fillna(pd.Timedelta(0)) df['weight'] = (df['dt'] + df['dt_next']) / 2 df['weighted'] = df['value'] * df['weight'].dt.total_seconds() # 转为秒,便于数值计算 df['integral'] = df['weighted'].cumsum()
注意:.dt.total_seconds() 必须显式调用,Timedelta 直接参与数值运算会报 TypeError。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
遇到 TypeError: unsupported operand type(s) for *: 'float' and 'Timedelta' 怎么办
这是最常卡住的地方:Pandas 不允许 float 和 Timedelta 直接相乘。不是类型写错了,而是没转换单位。
必须把时间差统一转成浮点秒数(或其他标量单位):
-
df['dt'].dt.total_seconds()—— 正确,返回float64Series -
df['dt'].astype('timedelta64[s]')—— 错误,仍是timedelta64类型,不能直接乘 -
df['dt'] / pd.Timedelta('1s')—— 可行,但不如.dt.total_seconds()直观稳定
如果数据含 NaT,.dt.total_seconds() 会自动转成 NaN,后续用 .fillna(0) 补零即可,不影响 cumsum。
梯形法 vs 矩形法:选哪个取决于物理意义
矩形法(用前向或后向差分作权重)简单快,适合变化平缓、采样密集的场景;梯形法更准,尤其在突变点附近,但首尾需单独处理。
若你明确知道信号在区间内近似恒定(如电表脉冲计数),用矩形法更合理:
df['weight_rect'] = df['time'].diff().shift(-1).dt.total_seconds().fillna(
(df['time'].iloc[-1] - df['time'].iloc[-2]).total_seconds()
)梯形法隐含“线性变化”假设,若原始数据本身是离散事件(如点击日志),反而可能引入虚假连续性。实际选哪种,得看你的 value 是瞬时值还是平均速率。
时间权重计算本身不难,难的是想清楚“这个数字到底代表什么物理量”。一旦定义模糊,后面所有 cumsum 都只是数字游戏。

















