Хорошо, вот быстрый способ решения (если вы хотите использовать усеченный гауссов). Установите границы и желаемый stddev. Я предполагаю, что среднее значение равно 0. Затем быстрый и сырой код для бинарного поиска для распределения sigma
, решение для нелинейного корня (brentq()
должен использоваться в производственном коде). Все формулы взяты со страницы вики на Усеченный нормальный . Это (сигма) должно быть больше, чем желаемый stddev из-за того, что усечение удаляет случайные значения, которые способствуют большому stddev. Затем мы делаем быструю выборочную проверку - и mean и stddev близки к желаемым значениям, но никогда точно не равны им. Код (Python-3.7, Анаконда, Win10 x64)
import numpy as np
from scipy.special import erf
from scipy.stats import truncnorm
def alpha(a, sigma):
return a/sigma
def beta(b, sigma):
return b/sigma
def xi(x, sigma):
return x/sigma
def fi(xi):
return 1.0/np.sqrt(2.0*np.pi) * np.exp(-0.5*xi*xi)
def Fi(x):
return 0.5*(1.0 + erf(x/np.sqrt(2.0)))
def Z(al, be):
return Fi(be) - Fi(al)
def Variance(sigma, a, b):
al = alpha(a, sigma)
be = beta(b, sigma)
ZZ = Z(al, be)
return sigma*sigma*(1.0 + (al*fi(al) - be*fi(be))/ZZ - ((fi(al)-fi(be))/ZZ)**2)
def stddev(sigma, a, b):
return np.sqrt(Variance(sigma, a, b))
m = 0.0 # mean
s = 1.0 # this is what we want
a = -3.0 # left boundary
b = 3.0 # right boundary
#print(stddev(s , a, b))
#print(stddev(s + 0.1, a, b))
slo = 1.0
shi = 1.1
stdlo = stddev(slo, a, b)
stdhi = stddev(shi, a, b)
sigma = -1.0
while True: # binary search for sigma
sme = (slo + shi) / 2.0
stdme = stddev(sme, a, b)
if stdme - s == 0.0:
sigma = stdme
break
elif stdme - s < 0.0:
slo = sme
else:
shi = sme
if shi - slo < 0.0000001:
sigma = (shi + slo) / 2.0
break
print(sigma) # we got it, shall be slightly bigger than s, desired stddev
np.random.seed(73123457)
rvs = truncnorm.rvs(a, b, loc=m, scale=sigma, size=1000000) # quick sampling test
print(np.mean(rvs))
print(np.std(rvs))
Для меня это напечатано
sigma = 1.0153870105743408
mean = -0.000400729471992301
stddev = 1.0024267696681475
с другой длиной семени или последовательности, вы можете получить вывод, например
1.0153870105743408
-0.00015923177289006116
0.9999974266369461