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

使用numpy计算日期时间加权平均时部分月份结果偏差问题

问题:日期时间加权平均计算异常

计算日期时间加权平均值时,6月日期计算结果符合预期,替换为7月同间隔日期后结果出现明显偏差,复现过程如下:

正常返回的6月测试用例

import pandas as pd
import numpy as np

foo = pd.DataFrame({'date': ['2022-06-01', '2022-06-16'],
                    'value': [1000, 10000]})
foo['date'] = pd.to_datetime(foo['date'])
bar = np.average(foo['date'].view(dtype='float64'), weights=foo['value'])
print(np.array(bar).view(dtype='datetime64[ns]'))

运行返回2022-06-14T15:16:21.818181818,结果符合预期。

结果异常的7月测试用例

foo = pd.DataFrame({'date': ['2022-07-01', '2022-07-16'],
                    'value': [1000, 10000]})
foo['date'] = pd.to_datetime(foo['date'])
bar = np.average(foo['date'].view(dtype='float64'), weights=foo['value'])
print(np.array(bar).view(dtype='datetime64[ns]'))

运行返回2022-07-14T23:59:53.766924660,但预期结果应为2022-07-14T15:16:21.818181818,与Excel计算结果一致。

Excel计算结果示意图

补充说明

  • 实际数据集规模较大,优先希望使用numpy实现计算
  • foo['date']均为无时间分量的纯日期数据,加权平均计算结果允许包含时间分量

问题根因

核心是float64精度不足引发的舍入误差:

  • pandas中datetime64[ns]类型底层存储为距离1970-01-01的纳秒整数值,2022年对应的纳秒值约为1.6e18
  • float64类型最多可精确表示2^53(约9e15)以内的整数,1.6e18远超出该范围,将纳秒级时间戳直接转为float64时会自动舍入丢失精度
  • 6月测试用例的两个时间戳转float64时舍入误差极小,结果看起来符合预期;7月测试用例的舍入误差在加权计算后被放大,出现了明显的时间偏差

解决方案

不要直接对原始纳秒时间戳做float转换,先减去固定基准时间将数值降到float64可精确表示的范围内,计算完成后再加回基准时间即可,完全适配numpy大数组高性能计算场景:

import pandas as pd
import numpy as np

foo = pd.DataFrame({'date': ['2022-07-01', '2022-07-16'],
                    'value': [1000, 10000]})
foo['date'] = pd.to_datetime(foo['date'])

# 选取基准时间,也可选用数据集内最早日期进一步缩小数值范围
base = pd.Timestamp("1970-01-01")
# 计算每个日期距基准时间的纳秒差,转float64无精度损失
delta = (foo['date'] - base).astype("int64").astype("float64")
weighted_delta = np.average(delta, weights=foo['value'])
# 加回基准时间得到最终结果
res = base + pd.Timedelta(weighted_delta, unit="ns")
print(res)
# 输出:2022-07-14 15:16:21.818181818

如果需要和Excel计算逻辑完全对齐,可直接按天为单位计算:

# Excel日期序列起点为1899-12-30,单位为天
excel_base = pd.Timestamp("1899-12-30")
days = (foo['date'] - excel_base).dt.total_seconds() / 86400
weighted_days = np.average(days, weights=foo['value'])
res = excel_base + pd.Timedelta(weighted_days, unit="D")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 16:57:23