Как распространить неопределенность на пользовательскую функцию, используя python
Я хотел бы распространять неопределенность с помощью Python. Это относительно просто для простых функций через пакет неопределенностей. Тем не менее, это не так очевидно, чтобы достичь того же с пользовательской функцией. Далее следует пример того, что я пытаюсь сделать.
import mcerp as err
import numpy as np
def mult_func(x,xm ,a):
x[x==0.] = 1e-20
v = (1.-(xm/x)**a) * (x > xm)
v[np.isnan(v)] = 0.
return v
def intg(e,f,cut,s):
t = mult_func(e,cut,s)
res = np.trapz(t*f,e)
return res
x=np.linspace(0,1,10000)
y=np.exp(x)
m=0.
mm=0.
N=100000
for i in range(0,N):
cut=np.random.normal(0.21,0.02)
stg=np.random.normal(1.1,0.1)
v=intg(x,y,cut,stg)
m=m+v
mm=mm+v*v
print("avg. %10.5E +/- %10.5E fixed %10.5E"%(m/N,np.sqrt((mm/N-(m/N)**2)),intg(x,y,0.21,1.1)))
То, что сделано выше, это просто случайная выборка двух параметров и вычисление среднего значения и дисперсии. Однако я не уверен, насколько этот метод грубой силы является адекватным. Я мог бы использовать закон больших чисел и попытаться оценить, сколько испытаний N
необходимы, чтобы получить определенное значение (P=1-1/(N*k**2))
быть рядом k
раз стандартные отклонения вокруг истинного среднего.
В принципе то, что я написал, могло сработать. Тем не менее, я предполагаю, что, будучи настолько гибким языком со многими мощными пакетами, python мог бы выполнять эту задачу гораздо более эффективно. Я думал о uncertainties
, mcerp
а также pymc
, Из-за моего ограниченного опыта использования этих пакетов, я не уверен, что делать дальше.
РЕДАКТИРОВАТЬ: Мой оригинальный пример не был настолько информативным, поэтому я решил сделать новый пример, который на самом деле работает, чтобы проиллюстрировать мою идею.
1 ответ
Numpy поддерживает массивы произвольных числовых типов. Однако не все функции поддерживают произвольные числовые типы.
В этом случае оба numpy.exp
а также trapz
не поддерживаются
Обратите внимание, что модуль uncertanties содержит unumpy
пакет. numpy.exp
здесь есть замена: uncertainties.unumpy.exp
Мы определяем trapz как ufunc.
Проверьте это здесь!
a=un.ufloat(0.3,0.01)
b=un.ufloat(1.2,0.071)
def sample_func(a: un.UFloat, b: un.UFloat) -> np.ndarray:
x=np.linspace(0,a,100)
y = un.unumpy.exp(x)
return utrapz(y, x)
def utrapz(y: np.ndarray, x: np.ndarray) -> np.ndarray:
Δx = x[1:]-x[:-1]
avg_y = (y[1:]+y[:-1])/2
return (Δx*avg_y)
print(sample_func(a, b))
ИЗ:
[0.00026601240063021264+/-nan 0.0005935120815465686+/-6.429403852670308e-06
0.0006973604419223405+/-3.888235103342809e-06 ...,
0.002095505706899622+/-6.503985178118233e-05
0.0021019968633076134+/-6.545802781649068e-05
0.0021084415802710295+/-6.587387316821736e-05]