TL; DR
Отсутствие точности с плавающей запятой при внутренних расчетах. Хотя scipy - это библиотека Python, ее ядро написано на C и использует числовые типы C.
Позвольте мне показать вам пример:
import scipy.stats
for i in range (13):
trials = 10 ** i
print(f"i: {i}\tprobability: {scipy.stats.binom(trials, 0.5).cdf(trials - 1)}")
И вывод:
i: 0 probability: 0.5
i: 1 probability: 0.9990234375
i: 2 probability: 0.9999999999999999
i: 3 probability: 0.9999999999999999
i: 4 probability: 0.9999999999999999
i: 5 probability: 0.9999999999999999
i: 6 probability: 0.9999999999999999
i: 7 probability: 0.9999999999999999
i: 8 probability: 0.9999999999999999
i: 9 probability: 0.9999999999999999
i: 10 probability: nan
i: 11 probability: nan
i: 12 probability: nan
Причина заключается в формуле CDF для биномиального распределения (я не могу встраивать изображения, поэтому вот ссылка на вики: https://en.wikipedia.org/wiki/Binomial_distribution
Внутри scipy источников мы увидим ссылку на эту реализацию: http://www.netlib.org/cephes/doubldoc.html#bdtr
Глубоко внутри это включает деление на trials
(incbet.c, line 375: ai = 1.0 / a;
здесь это называется a
, но nwm). И если ваш trials
слишком велик, результат этого деления настолько мал, что когда мы добавляем это маленькое число к другому, а не к такому маленькому, оно на самом деле не меняется, потому что здесь нам не хватает точности с плавающей запятой (только 64 бита). до сих пор). Затем, после некоторой арифметики, мы пытаемся получить логарифм от числа, но оно равно нулю, поскольку оно не меняется, когда должно. И log(0)
не определено, что равно np.nan
.