【发布时间】:2015-03-28 05:05:49
【问题描述】:
我正在测试日期范围的模拟,以这样一种方式,我期望给定日期的计算返回相同的数字,而不管我计算给定批次的日期范围。
也就是说,如果我在 1990-2000 的范围内调用系统,那么 1995.07.01 的结果应该与在 1995-1996 调用系统时的结果相同。应该很基础吧,我想...
问题在于快速滚动窗口实现会累积舍入误差,这确实取决于滚动窗口之外的历史长度。因此,当我对 1995.07.01 进行 20 天移动求和时,如果对 1990 年以来的时间序列运行滚动求和运算,结果会产生更多的累积舍入误差。
这是一个示例,我希望非 nan 结果完全匹配:
df = pd.DataFrame([xrange(7)]).astype('float64').T
df = np.sqrt(df)
roll1_df = pd.rolling_sum(df, window=3)
roll2_df = pd.rolling_sum(df.iloc[3:, :], window=3)
但我得到了舍入错误:
roll1_df - roll2_df
0
0 NaN
1 NaN
2 NaN
3 NaN
4 NaN
5 8.881784e-16
6 1.776357e-15
该示例使用 Python/pandas,但在任何数字运算软件中问题都是一样的,因此我很高兴在 pandas、numpy、Matlab、R ... 或基于纯理论的想法。
保持快速滚动操作的性能优势很重要,即避免简单地将所有日期的最后 N 个值相加(这将比快速滚动窗口实现慢 O(N) 倍)。
编辑:解决方案
我毕竟选择了以下解决方案,将 pandas 拆开并在 rolling_sum 中进行一些舍入后重新组合:
rolling_sum_stable_df = _rolling_func(
lambda *arg_l: np.round(roll_sum(*arg_l), decimals=11),
'Stable rolling_sum'
)
可以在 rolling_sum() 之前先转换为 float32,然后再转换回 float64,但会丢失更多位数。该方法的缺点是我必须为 rolling_cov 和其他滚动函数执行此操作,这涉及到更多。
【问题讨论】:
-
我不太确定我明白你到底在总结什么。但是,如果您想要两个结果之间完全相等 - 浮点数永远不会让您满意。您要么必须使用整数类型,要么必须使用“几乎相等”而不是“相等”的实现。
-
您可以使用
np.isclose:np.isclose(roll1_df[3:], roll2_df )这表明最后两个值足够接近,可以认为是相等的 -
几年前尝试过。不幸的是,系统中的数值误差是非线性的,即 1e-16 的差异可能会导致以后的数字发生较大变化。
标签: matlab numpy pandas numerical-methods moving-average