Обработка неточностей с плавающей запятой при создании весов экспоненциального сглаживания
Я хочу создать массив весов экспоненциального сглаживания, как в формуле (7.2), отсюда. Я знаю рекурсивное определение, но мне нужны реальные веса. Я придумал следующую простую реализацию:
import numpy as np
def create_weights(n, alpha = 1.0):
wghts = alpha*(1-alpha)**np.arange(n)
return wghts
Веса должны составлять до 1,0, однако, как показывает этот тест, это не относится к более мелким альфа-версиям, я думаю, из-за впечатления с плавающей запятой:
np.set_printoptions(precision=3)
for alpha in np.arange(1.0, 0.0, -0.1):
print("%.3f, %s, %.3f" % (alpha, create_weights(5, alpha) , create_weights(5, alpha).sum()))
Out:
1.000, [1. 0. 0. 0. 0.], 1.000
0.900, [9.e-01 9.e-02 9.e-03 9.e-04 9.e-05], 1.000
0.800, [0.8 0.16 0.032 0.006 0.001], 1.000
0.700, [0.7 0.21 0.063 0.019 0.006], 0.998
0.600, [0.6 0.24 0.096 0.038 0.015], 0.990
0.500, [0.5 0.25 0.125 0.062 0.031], 0.969
0.400, [0.4 0.24 0.144 0.086 0.052], 0.922
0.300, [0.3 0.21 0.147 0.103 0.072], 0.832
0.200, [0.2 0.16 0.128 0.102 0.082], 0.672
0.100, [0.1 0.09 0.081 0.073 0.066], 0.410
Подобно решениям здесь, я мог бы просто "нормализовать" его, чтобы снова увеличить его:
def create_weights(n, alpha = 1.0):
wghts = alpha*(1-alpha)**np.arange(n)
wghts /= wghts.sum()
return wghts
Это приводит к:
1.000, [1. 0. 0. 0. 0.], 1.000
0.900, [9.e-01 9.e-02 9.e-03 9.e-04 9.e-05], 1.000
0.800, [0.8 0.16 0.032 0.006 0.001], 1.000
0.700, [0.702 0.211 0.063 0.019 0.006], 1.000
0.600, [0.606 0.242 0.097 0.039 0.016], 1.000
0.500, [0.516 0.258 0.129 0.065 0.032], 1.000
0.400, [0.434 0.26 0.156 0.094 0.056], 1.000
0.300, [0.361 0.252 0.177 0.124 0.087], 1.000
0.200, [0.297 0.238 0.19 0.152 0.122], 1.000
0.100, [0.244 0.22 0.198 0.178 0.16 ], 1.000
Хотя в настоящее время сумма составляет 1,0, для небольшой альфы первый вес слишком сильно отклоняется от ожидаемого значения (ожидается, что он равен альфе).
Есть ли другой способ реализовать это, чтобы выполнить оба свойства весов, добавив к 1,0 (+-маленькая ошибка) и первый вес, являющийся альфа (+ - небольшая ошибка)?
1 ответ
Это не имеет ничего общего с точностью с плавающей точкой. Массивы, которые вы генерируете, не будут равны 1 даже с арифметикой действительных чисел бесконечной точности. Бесконечный ряд, сгенерированный аналогичным образом, суммирует до 1, но ваши массивы останавливаются на 5 элементах, а не вечны.
Простое экспоненциальное сглаживание не останавливается произвольно на 5 элементах. Часто разумно применять отсечение для элементов, достаточно далеко в прошлом, чтобы их веса были крошечными, но остановка на 5 для каждой альфы без нормализации приведет к необоснованным результатам.