Я пытаюсь получить дискретную близость к гауссовскому распределению при n> = 2.
Итак, пусть n = 2, чем дискретная близость [0,5, 0,5].
при n = 3, чем это было бы [0,25, 0,5, 0,25]
при n = 4, чем это было [0,125, 0,375, 0,375, 0,125]
на мой взгляд, я надеюсь.
Возвращенная дискретная сумма массива близости всегда должна быть равна 1 как все распределения.
Вот мой код:
import numpy as np
import matplotlib.pyplot as plt
import math
import scipy
from random import randint
def discrete_gauss(n):
g = [0.5, 0.5]
f = g
for x in range(1, n - 1):
f = np.convolve(f,g)
if(sum(f) != 1):
print("The distribution sum is not 1.")
else:
return f
Теперь "discrete_gauss" отлично работает, когда я использую (1 <n <68), но когда я вхожу (n> 67), сумма f отличается от 1 (иногда иногда меньше), и я не знаю почему. У кого-нибудь есть ключ?
Извините за беспорядочный вопрос, я попытался удержать его. Я буду рад прояснить ситуацию, если они не ясны. Благодарю.
Прочтите этот документ о проблемах использования математики с плавающей запятой, а затем пересмотреть свой подход.
Здесь приведена альтернативная процедура для генерирования желаемого "распределения", которая позволяет избежать ошибок округления с плавающей запятой в суммировании, выполняемом np.convolve
:
import numpy as np
import scipy.special as sps
def discrete_gauss(n):
f = np.array([sps.comb(n - 1, i, exact=True) for i in range(n)], dtype='O')
f = np.float64(f)/np.float64(f).sum()
if not np.allclose(f.sum(), 1.0):
raise ValueError("The distribution sum is not close to 1.\n"
"f.sum(): %s" % f.sum())
return f
Последовательность, которую вы хотите, эквивалентна n
му уровню треугольника Паскаля (см. Рисунок в верхней части Wiki по теореме о биномиальности), нормированная так, чтобы она могла представлять вероятность. В приведенном выше решении используются стандартные значения Python int
(которые по умолчанию произвольны в Python 3), чтобы найти значения на n
м уровне, а затем переключается на математику с плавающей запятой только в самом конце для этапа нормализации (например, np.float64(f)/np.float64(f).sum()
).
Обратите внимание на использование not np.allclose(f.sum(), 1.0)
в вышеприведенной проверке вместо f.sum() != 1.0
. Как обсуждается ниже в разделе Deeper dive, f.sum()
будет равно 1.0
для ~ 90% от значений n
от 1 до 1000. Однако в целом вы не можете предположить, что результат вычисления с плавающей точкой будет точно соответствовать результату, который вы получите от эквивалентного вычисления с использованием реальных чисел (см. Эту статью для всех деталей gory). Когда вы имеете дело с поплавками, вы обычно (под которым я подразумеваю почти всегда) проверяем, что результат близок (т.е. равный в пределах данного допуска/ошибки) к вашему ожидаемому значению, а не к нему.
Это решение не идеально. Большинство значений n
дают результаты, которые точно суммируются до 1.0
, но некоторые из них этого не делают. Следующий код проверяет результаты discrete_gauss(n)
для значений n
от 1 до 1000:
nnot1 = []
for n in range(1,1001):
if discrete_gauss(n).sum() != 1.0:
nnot1.append(n)
print('discrete_gauss(n).sum() was not equal to 1.0 for %d values of n.' % len(nnot1))
print(nnot1)
Выход:
discrete_gauss(n).sum() was not equal to 1.0 for 75 values of n.
[78, 89, 110, 114, 125, 127, 180, 182, 201, 206, 235, 248, 273, 342, 346, 348, 365, 373, 383, 390, 402, 403, 421, 427, 429, 451, 454, 471, 502, 531, 540, 556, 558, 574, 579, 584, 587, 595, 600, 609, 617, 631, 633, 647, 648, 651, 657, 669, 674, 703, 705, 728, 731, 763, 765, 772, 778, 783, 798, 816, 837, 852, 858, 860, 861, 867, 874, 877, 906, 912, 941, 947, 959, 964, 972]
Таким образом, для ~ 8% этих значений dicrete_gauss(n).sum()
не была точно равна 1.0
. Однако, поскольку ошибка не была повышена, np.allclose(dicrete_gauss(n).sum(), 1.0)
всегда была True
.
scipy.speical.comb(n, k, exact=True)
дает (n, k)
-ый биномиальный коэффициент как стандартный Python int
, который эквивалентен k
му значению на n
м уровне треугольника Паскаля.
0.9999999999999999
что говорит о том, что ваши проблемы - просто проблема точности с плавающей запятой.