使用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计算结果一致。

补充说明
- 实际数据集规模较大,优先希望使用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
相关产品推荐
相关产品推荐

