mirror of
https://github.com/fjosw/pyerrors.git
synced 2025-03-16 23:30:24 +01:00
Merge branch 'develop' into documentation
This commit is contained in:
commit
abd0b29305
3 changed files with 121 additions and 105 deletions
105
pyerrors/fits.py
105
pyerrors/fits.py
|
@ -646,10 +646,10 @@ def fit_lin(x, y, **kwargs):
|
||||||
return y
|
return y
|
||||||
|
|
||||||
if all(isinstance(n, Obs) for n in x):
|
if all(isinstance(n, Obs) for n in x):
|
||||||
out = odr_fit(x, y, f, **kwargs)
|
out = total_least_squares(x, y, f, **kwargs)
|
||||||
return out.fit_parameters
|
return out.fit_parameters
|
||||||
elif all(isinstance(n, float) or isinstance(n, int) for n in x) or isinstance(x, np.ndarray):
|
elif all(isinstance(n, float) or isinstance(n, int) for n in x) or isinstance(x, np.ndarray):
|
||||||
out = standard_fit(x, y, f, **kwargs)
|
out = least_squares(x, y, f, **kwargs)
|
||||||
return out.fit_parameters
|
return out.fit_parameters
|
||||||
else:
|
else:
|
||||||
raise Exception('Unsupported types for x')
|
raise Exception('Unsupported types for x')
|
||||||
|
@ -785,104 +785,3 @@ def ks_test(obs=None):
|
||||||
plt.draw()
|
plt.draw()
|
||||||
|
|
||||||
print(scipy.stats.kstest(Qs, 'uniform'))
|
print(scipy.stats.kstest(Qs, 'uniform'))
|
||||||
|
|
||||||
|
|
||||||
def fit_general(x, y, func, silent=False, **kwargs):
|
|
||||||
"""Performs a non-linear fit to y = func(x) and returns a list of Obs corresponding to the fit parameters.
|
|
||||||
|
|
||||||
Plausibility of the results should be checked. To control the numerical differentiation
|
|
||||||
the kwargs of numdifftools.step_generators.MaxStepGenerator can be used.
|
|
||||||
|
|
||||||
func has to be of the form
|
|
||||||
|
|
||||||
def func(a, x):
|
|
||||||
y = a[0] + a[1] * x + a[2] * np.sinh(x)
|
|
||||||
return y
|
|
||||||
|
|
||||||
y has to be a list of Obs, the dvalues of the Obs are used as yerror for the fit.
|
|
||||||
x can either be a list of floats in which case no xerror is assumed, or
|
|
||||||
a list of Obs, where the dvalues of the Obs are used as xerror for the fit.
|
|
||||||
|
|
||||||
Keyword arguments
|
|
||||||
-----------------
|
|
||||||
silent -- If true all output to the console is omitted (default False).
|
|
||||||
initial_guess -- can provide an initial guess for the input parameters. Relevant for non-linear fits
|
|
||||||
with many parameters.
|
|
||||||
"""
|
|
||||||
|
|
||||||
warnings.warn("New fit functions with exact error propagation are now available as alternative.", DeprecationWarning)
|
|
||||||
|
|
||||||
if not callable(func):
|
|
||||||
raise TypeError('func has to be a function.')
|
|
||||||
|
|
||||||
for i in range(10):
|
|
||||||
try:
|
|
||||||
func(np.arange(i), 0)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
n_parms = i
|
|
||||||
if not silent:
|
|
||||||
print('Fit with', n_parms, 'parameters')
|
|
||||||
|
|
||||||
global print_output, beta0
|
|
||||||
print_output = 1
|
|
||||||
if 'initial_guess' in kwargs:
|
|
||||||
beta0 = kwargs.get('initial_guess')
|
|
||||||
if len(beta0) != n_parms:
|
|
||||||
raise Exception('Initial guess does not have the correct length.')
|
|
||||||
else:
|
|
||||||
beta0 = np.arange(n_parms)
|
|
||||||
|
|
||||||
if len(x) != len(y):
|
|
||||||
raise Exception('x and y have to have the same length')
|
|
||||||
|
|
||||||
if all(isinstance(n, Obs) for n in x):
|
|
||||||
obs = x + y
|
|
||||||
x_constants = None
|
|
||||||
xerr = [o.dvalue for o in x]
|
|
||||||
yerr = [o.dvalue for o in y]
|
|
||||||
elif all(isinstance(n, float) or isinstance(n, int) for n in x) or isinstance(x, np.ndarray):
|
|
||||||
obs = y
|
|
||||||
x_constants = x
|
|
||||||
xerr = None
|
|
||||||
yerr = [o.dvalue for o in y]
|
|
||||||
else:
|
|
||||||
raise Exception('Unsupported types for x')
|
|
||||||
|
|
||||||
def do_the_fit(obs, **kwargs):
|
|
||||||
|
|
||||||
global print_output, beta0
|
|
||||||
|
|
||||||
func = kwargs.get('function')
|
|
||||||
yerr = kwargs.get('yerr')
|
|
||||||
length = len(yerr)
|
|
||||||
|
|
||||||
xerr = kwargs.get('xerr')
|
|
||||||
|
|
||||||
if length == len(obs):
|
|
||||||
assert 'x_constants' in kwargs
|
|
||||||
data = RealData(kwargs.get('x_constants'), obs, sy=yerr)
|
|
||||||
fit_type = 2
|
|
||||||
elif length == len(obs) // 2:
|
|
||||||
data = RealData(obs[:length], obs[length:], sx=xerr, sy=yerr)
|
|
||||||
fit_type = 0
|
|
||||||
else:
|
|
||||||
raise Exception('x and y do not fit together.')
|
|
||||||
|
|
||||||
model = Model(func)
|
|
||||||
|
|
||||||
odr = ODR(data, model, beta0, partol=np.finfo(np.float64).eps)
|
|
||||||
odr.set_job(fit_type=fit_type, deriv=1)
|
|
||||||
output = odr.run()
|
|
||||||
if print_output and not silent:
|
|
||||||
print(*output.stopreason)
|
|
||||||
print('chisquare/d.o.f.:', output.res_var)
|
|
||||||
print_output = 0
|
|
||||||
beta0 = output.beta
|
|
||||||
return output.beta[kwargs.get('n')]
|
|
||||||
res = []
|
|
||||||
for n in range(n_parms):
|
|
||||||
res.append(derived_observable(do_the_fit, obs, function=func, xerr=xerr, yerr=yerr, x_constants=x_constants, num_grad=True, n=n, **kwargs))
|
|
||||||
return res
|
|
||||||
|
|
|
@ -70,3 +70,23 @@ def test_covobs_name_collision():
|
||||||
def test_covobs_replica_separator():
|
def test_covobs_replica_separator():
|
||||||
with pytest.raises(Exception):
|
with pytest.raises(Exception):
|
||||||
covobs = pe.cov_Obs(0.5, 0.002, 'test|r2')
|
covobs = pe.cov_Obs(0.5, 0.002, 'test|r2')
|
||||||
|
|
||||||
|
|
||||||
|
def test_covobs_init():
|
||||||
|
covobs = pe.cov_Obs(0.5, 0.002, 'test')
|
||||||
|
covobs = pe.cov_Obs([1, 2], [0.1, 0.2], 'test')
|
||||||
|
covobs = pe.cov_Obs([1, 2], np.array([0.1, 0.2]), 'test')
|
||||||
|
covobs = pe.cov_Obs([1, 2], [[0.1, 0.2], [0.1, 0.2]], 'test')
|
||||||
|
covobs = pe.cov_Obs([1, 2], np.array([[0.1, 0.2], [0.1, 0.2]]), 'test')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def test_covobs_exceptions():
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
covobs = pe.cov_Obs(0.1, [[0.1, 0.2], [0.1, 0.2]], 'test')
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
covobs = pe.cov_Obs(0.1, np.array([[0.1, 0.2], [0.1, 0.2]]), 'test')
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
covobs = pe.cov_Obs([0.5, 0.1], np.array([[2, 1, 3], [1, 2, 3]]), 'test')
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
covobs = pe.cov_Obs([0.5, 0.1], np.random.random((2, 2, 2)), 'test')
|
||||||
|
|
|
@ -232,8 +232,7 @@ def test_odr_derivatives():
|
||||||
out = pe.total_least_squares(x, y, func)
|
out = pe.total_least_squares(x, y, func)
|
||||||
fit1 = out.fit_parameters
|
fit1 = out.fit_parameters
|
||||||
|
|
||||||
with pytest.warns(DeprecationWarning):
|
tfit = fit_general(x, y, func, base_step=0.1, step_ratio=1.1, num_steps=20)
|
||||||
tfit = pe.fits.fit_general(x, y, func, base_step=0.1, step_ratio=1.1, num_steps=20)
|
|
||||||
assert np.abs(np.max(np.array(list(fit1[1].deltas.values()))
|
assert np.abs(np.max(np.array(list(fit1[1].deltas.values()))
|
||||||
- np.array(list(tfit[1].deltas.values())))) < 10e-8
|
- np.array(list(tfit[1].deltas.values())))) < 10e-8
|
||||||
|
|
||||||
|
@ -274,3 +273,101 @@ def test_r_value_persistence():
|
||||||
assert np.isclose(fitp[1].value, fitp[1].r_values['a'])
|
assert np.isclose(fitp[1].value, fitp[1].r_values['a'])
|
||||||
assert np.isclose(fitp[1].value, fitp[1].r_values['b'])
|
assert np.isclose(fitp[1].value, fitp[1].r_values['b'])
|
||||||
|
|
||||||
|
|
||||||
|
def fit_general(x, y, func, silent=False, **kwargs):
|
||||||
|
"""Performs a non-linear fit to y = func(x) and returns a list of Obs corresponding to the fit parameters.
|
||||||
|
|
||||||
|
Plausibility of the results should be checked. To control the numerical differentiation
|
||||||
|
the kwargs of numdifftools.step_generators.MaxStepGenerator can be used.
|
||||||
|
|
||||||
|
func has to be of the form
|
||||||
|
|
||||||
|
def func(a, x):
|
||||||
|
y = a[0] + a[1] * x + a[2] * np.sinh(x)
|
||||||
|
return y
|
||||||
|
|
||||||
|
y has to be a list of Obs, the dvalues of the Obs are used as yerror for the fit.
|
||||||
|
x can either be a list of floats in which case no xerror is assumed, or
|
||||||
|
a list of Obs, where the dvalues of the Obs are used as xerror for the fit.
|
||||||
|
|
||||||
|
Keyword arguments
|
||||||
|
-----------------
|
||||||
|
silent -- If true all output to the console is omitted (default False).
|
||||||
|
initial_guess -- can provide an initial guess for the input parameters. Relevant for non-linear fits
|
||||||
|
with many parameters.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not callable(func):
|
||||||
|
raise TypeError('func has to be a function.')
|
||||||
|
|
||||||
|
for i in range(10):
|
||||||
|
try:
|
||||||
|
func(np.arange(i), 0)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
n_parms = i
|
||||||
|
if not silent:
|
||||||
|
print('Fit with', n_parms, 'parameters')
|
||||||
|
|
||||||
|
global print_output, beta0
|
||||||
|
print_output = 1
|
||||||
|
if 'initial_guess' in kwargs:
|
||||||
|
beta0 = kwargs.get('initial_guess')
|
||||||
|
if len(beta0) != n_parms:
|
||||||
|
raise Exception('Initial guess does not have the correct length.')
|
||||||
|
else:
|
||||||
|
beta0 = np.arange(n_parms)
|
||||||
|
|
||||||
|
if len(x) != len(y):
|
||||||
|
raise Exception('x and y have to have the same length')
|
||||||
|
|
||||||
|
if all(isinstance(n, pe.Obs) for n in x):
|
||||||
|
obs = x + y
|
||||||
|
x_constants = None
|
||||||
|
xerr = [o.dvalue for o in x]
|
||||||
|
yerr = [o.dvalue for o in y]
|
||||||
|
elif all(isinstance(n, float) or isinstance(n, int) for n in x) or isinstance(x, np.ndarray):
|
||||||
|
obs = y
|
||||||
|
x_constants = x
|
||||||
|
xerr = None
|
||||||
|
yerr = [o.dvalue for o in y]
|
||||||
|
else:
|
||||||
|
raise Exception('Unsupported types for x')
|
||||||
|
|
||||||
|
def do_the_fit(obs, **kwargs):
|
||||||
|
|
||||||
|
global print_output, beta0
|
||||||
|
|
||||||
|
func = kwargs.get('function')
|
||||||
|
yerr = kwargs.get('yerr')
|
||||||
|
length = len(yerr)
|
||||||
|
|
||||||
|
xerr = kwargs.get('xerr')
|
||||||
|
|
||||||
|
if length == len(obs):
|
||||||
|
assert 'x_constants' in kwargs
|
||||||
|
data = RealData(kwargs.get('x_constants'), obs, sy=yerr)
|
||||||
|
fit_type = 2
|
||||||
|
elif length == len(obs) // 2:
|
||||||
|
data = RealData(obs[:length], obs[length:], sx=xerr, sy=yerr)
|
||||||
|
fit_type = 0
|
||||||
|
else:
|
||||||
|
raise Exception('x and y do not fit together.')
|
||||||
|
|
||||||
|
model = Model(func)
|
||||||
|
|
||||||
|
odr = ODR(data, model, beta0, partol=np.finfo(np.float64).eps)
|
||||||
|
odr.set_job(fit_type=fit_type, deriv=1)
|
||||||
|
output = odr.run()
|
||||||
|
if print_output and not silent:
|
||||||
|
print(*output.stopreason)
|
||||||
|
print('chisquare/d.o.f.:', output.res_var)
|
||||||
|
print_output = 0
|
||||||
|
beta0 = output.beta
|
||||||
|
return output.beta[kwargs.get('n')]
|
||||||
|
res = []
|
||||||
|
for n in range(n_parms):
|
||||||
|
res.append(pe.derived_observable(do_the_fit, obs, function=func, xerr=xerr, yerr=yerr, x_constants=x_constants, num_grad=True, n=n, **kwargs))
|
||||||
|
return res
|
||||||
|
|
Loading…
Add table
Reference in a new issue