Merge branch 'develop' of ariadne.geophysik.ruhr-uni-bochum.de:/data/git/pylot into develop
This commit is contained in:
commit
546dfad722
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import warnings
|
import warnings
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import scipy.optimize
|
||||||
from obspy import UTCDateTime
|
from obspy import UTCDateTime
|
||||||
from pylot.core.util.utils import find_nearest, clims
|
from pylot.core.util.utils import find_nearest, clims
|
||||||
from pylot.core.util.version import get_git_version as _getVersionString
|
from pylot.core.util.version import get_git_version as _getVersionString
|
||||||
@ -34,7 +35,7 @@ def gauss_parameter(te, tm, tl, eta):
|
|||||||
a1 = 2 / (1 + sig2 / sig1)
|
a1 = 2 / (1 + sig2 / sig1)
|
||||||
a2 = 2 / (1 + sig1 / sig2)
|
a2 = 2 / (1 + sig1 / sig2)
|
||||||
|
|
||||||
return sig1, sig2, a1, a2
|
return tm, sig1, sig2, a1, a2
|
||||||
|
|
||||||
|
|
||||||
def exp_parameter(te, tm, tl, eta):
|
def exp_parameter(te, tm, tl, eta):
|
||||||
@ -53,10 +54,10 @@ def exp_parameter(te, tm, tl, eta):
|
|||||||
sig2 = np.log(eta) / (tm - tl)
|
sig2 = np.log(eta) / (tm - tl)
|
||||||
a = 1 / (1 / sig1 + 1 / sig2)
|
a = 1 / (1 / sig1 + 1 / sig2)
|
||||||
|
|
||||||
return sig1, sig2, a
|
return tm, sig1, sig2, a
|
||||||
|
|
||||||
|
|
||||||
def gauss_branches(x, mu, sig1, sig2, a1, a2):
|
def gauss_branches(k, mu, sig1, sig2, a1, a2):
|
||||||
'''
|
'''
|
||||||
function gauss_branches takes an axes x, a center value mu, two sigma
|
function gauss_branches takes an axes x, a center value mu, two sigma
|
||||||
values sig1 and sig2 and two scaling factors a1 and a2 and return a
|
values sig1 and sig2 and two scaling factors a1 and a2 and return a
|
||||||
@ -75,16 +76,22 @@ def gauss_branches(x, mu, sig1, sig2, a1, a2):
|
|||||||
:param a2:
|
:param a2:
|
||||||
:returns fun_vals: list with function values along axes x
|
:returns fun_vals: list with function values along axes x
|
||||||
'''
|
'''
|
||||||
fun_vals = []
|
|
||||||
for k in x:
|
def _func(k, mu, sig1, sig2, a1, a2):
|
||||||
if k < mu:
|
if k < mu:
|
||||||
fun_vals.append(a1 * 1 / (np.sqrt(2 * np.pi) * sig1) * np.exp(-((k - mu) / sig1) ** 2 / 2))
|
rval = a1 * 1 / (np.sqrt(2 * np.pi) * sig1) * np.exp(-((k - mu) / sig1) ** 2 / 2)
|
||||||
else:
|
else:
|
||||||
fun_vals.append(a2 * 1 / (np.sqrt(2 * np.pi) * sig2) * np.exp(-((k - mu) / sig2) ** 2 / 2))
|
rval = a2 * 1 / (np.sqrt(2 * np.pi) * sig2) * np.exp(-((k - mu) /
|
||||||
return np.array(fun_vals)
|
sig2) ** 2 / 2)
|
||||||
|
return rval
|
||||||
|
|
||||||
|
try:
|
||||||
|
return [_func(x, mu, sig1, sig2, a1, a2) for x in iter(k)]
|
||||||
|
except TypeError:
|
||||||
|
return _func(k, mu, sig1, sig2, a1, a2)
|
||||||
|
|
||||||
|
|
||||||
def exp_branches(x, mu, sig1, sig2, a):
|
def exp_branches(k, mu, sig1, sig2, a):
|
||||||
'''
|
'''
|
||||||
function exp_branches takes an axes x, a center value mu, two sigma
|
function exp_branches takes an axes x, a center value mu, two sigma
|
||||||
values sig1 and sig2 and a scaling factor a and return a
|
values sig1 and sig2 and a scaling factor a and return a
|
||||||
@ -97,13 +104,19 @@ def exp_branches(x, mu, sig1, sig2, a):
|
|||||||
:param a:
|
:param a:
|
||||||
:returns fun_vals: list with function values along axes x:
|
:returns fun_vals: list with function values along axes x:
|
||||||
'''
|
'''
|
||||||
fun_vals = []
|
|
||||||
for k in x:
|
def _func(k, mu, sig1, sig2, a):
|
||||||
if k < mu:
|
if k < mu:
|
||||||
fun_vals.append(a * np.exp(sig1 * (k - mu)))
|
rval = a * np.exp(sig1 * (k - mu))
|
||||||
else:
|
else:
|
||||||
fun_vals.append(a * np.exp(-sig2 * (k - mu)))
|
rval = a * np.exp(-sig2 * (k - mu))
|
||||||
return np.array(fun_vals)
|
return rval
|
||||||
|
|
||||||
|
try:
|
||||||
|
return [_func(x, mu, sig1, sig2, a) for x in iter(k)]
|
||||||
|
except TypeError:
|
||||||
|
return _func(k, mu, sig1, sig2, a)
|
||||||
|
|
||||||
|
|
||||||
# define container dictionaries for different types of pdfs
|
# define container dictionaries for different types of pdfs
|
||||||
parameter = dict(gauss=gauss_parameter, exp=exp_parameter)
|
parameter = dict(gauss=gauss_parameter, exp=exp_parameter)
|
||||||
@ -117,62 +130,89 @@ class ProbabilityDensityFunction(object):
|
|||||||
|
|
||||||
version = __version__
|
version = __version__
|
||||||
|
|
||||||
def __init__(self, x0, incr, npts, pdf):
|
def __init__(self, x0, incr, npts, pdf, mu, params):
|
||||||
self.x0 = x0
|
self.x0 = x0
|
||||||
self.incr = incr
|
self.incr = incr
|
||||||
self.npts = npts
|
self.npts = npts
|
||||||
self.axis = create_axis(x0, incr, npts)
|
self.axis = create_axis(x0, incr, npts)
|
||||||
self.data = pdf
|
self.mu = mu
|
||||||
|
self._pdf = pdf
|
||||||
|
self.params = params
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
assert isinstance(other, ProbabilityDensityFunction), \
|
|
||||||
'both operands must be of type ProbabilityDensityFunction'
|
|
||||||
|
|
||||||
x0, incr, npts, pdf_self, pdf_other = self.rearrange(other)
|
x0, incr, npts = self.commonparameter(other)
|
||||||
|
|
||||||
|
axis = create_axis(x0, incr, npts)
|
||||||
|
pdf_self = np.array([self.data(x) for x in axis])
|
||||||
|
pdf_other = np.array([other.data(x) for x in axis])
|
||||||
|
|
||||||
pdf = np.convolve(pdf_self, pdf_other, 'full') * incr
|
pdf = np.convolve(pdf_self, pdf_other, 'full') * incr
|
||||||
|
|
||||||
# shift axis values for correct plotting
|
# shift axis values for correct plotting
|
||||||
npts = pdf.size
|
npts = pdf.size
|
||||||
x0 *= 2
|
x0 *= 2
|
||||||
return ProbabilityDensityFunction(x0, incr, npts, pdf)
|
axis = create_axis(x0, incr, npts)
|
||||||
|
|
||||||
|
params, pcov = scipy.optimize.curve_fit(branches['gauss'], axis, pdf)
|
||||||
|
|
||||||
|
mu = axis[np.where(pdf == max(pdf))]
|
||||||
|
|
||||||
|
return ProbabilityDensityFunction(x0, incr, npts, branches['gauss'], mu,
|
||||||
|
params)
|
||||||
|
|
||||||
def __sub__(self, other):
|
def __sub__(self, other):
|
||||||
assert isinstance(other, ProbabilityDensityFunction), \
|
|
||||||
'both operands must be of type ProbabilityDensityFunction'
|
|
||||||
|
|
||||||
x0, incr, npts, pdf_self, pdf_other = self.rearrange(other)
|
x0, incr, npts = self.commonparameter(other)
|
||||||
|
|
||||||
|
axis = create_axis(x0, incr, npts)
|
||||||
|
pdf_self = np.array([self.data(x) for x in axis])
|
||||||
|
pdf_other = np.array([other.data(x) for x in axis])
|
||||||
|
|
||||||
pdf = np.correlate(pdf_self, pdf_other, 'full') * incr
|
pdf = np.correlate(pdf_self, pdf_other, 'full') * incr
|
||||||
|
|
||||||
npts = len(pdf)
|
|
||||||
|
|
||||||
# shift axis values for correct plotting
|
# shift axis values for correct plotting
|
||||||
|
npts = len(pdf)
|
||||||
midpoint = npts / 2
|
midpoint = npts / 2
|
||||||
x0 = -incr * midpoint
|
x0 = -incr * midpoint
|
||||||
|
axis = create_axis(x0, incr, npts)
|
||||||
|
|
||||||
return ProbabilityDensityFunction(x0, incr, npts, pdf)
|
mu = axis[np.where(pdf == max(pdf))][0]
|
||||||
|
|
||||||
|
bounds = ([mu, 0., 0., 0., 0.],[mu, np.inf, np.inf, np.inf, np.inf])
|
||||||
|
|
||||||
|
params, pcov = scipy.optimize.curve_fit(branches['gauss'], axis, pdf,
|
||||||
|
bounds=bounds)
|
||||||
|
|
||||||
|
return ProbabilityDensityFunction(x0, incr, npts, branches['gauss'], mu,
|
||||||
|
params)
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __nonzero__(self):
|
||||||
prec = self.precision(self.incr)
|
prec = self.precision(self.incr)
|
||||||
gtzero = np.all(self.data >= 0)
|
data = np.array([self.data(t) for t in self.axis])
|
||||||
|
gtzero = np.all(data >= 0)
|
||||||
probone = bool(np.round(self.prob_gt_val(self.axis[0]), prec) == 1.)
|
probone = bool(np.round(self.prob_gt_val(self.axis[0]), prec) == 1.)
|
||||||
return bool(gtzero and probone)
|
return bool(gtzero and probone)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.data)
|
return str([self.data(val) for val in create_axis(self.x0, self.incr,
|
||||||
|
self.npts)])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def precision(incr):
|
def precision(incr):
|
||||||
prec = int(np.ceil(np.abs(np.log10(incr)))) - 2
|
prec = int(np.ceil(np.abs(np.log10(incr)))) - 2
|
||||||
return prec if prec >= 0 else 0
|
return prec if prec >= 0 else 0
|
||||||
|
|
||||||
@property
|
def data(self, value):
|
||||||
def data(self):
|
return self._pdf(value, *self.params)
|
||||||
return self._pdf
|
|
||||||
|
|
||||||
@data.setter
|
@property
|
||||||
def data(self, pdf):
|
def mu(self):
|
||||||
self._pdf = np.array(pdf)
|
return self._mu
|
||||||
|
|
||||||
|
@mu.setter
|
||||||
|
def mu(self, mu):
|
||||||
|
self._mu = mu
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def axis(self):
|
def axis(self):
|
||||||
@ -226,17 +266,12 @@ class ProbabilityDensityFunction(object):
|
|||||||
# calculate parameter for pdf representing function
|
# calculate parameter for pdf representing function
|
||||||
params = parameter[type](lbound, barycentre, rbound, decfact)
|
params = parameter[type](lbound, barycentre, rbound, decfact)
|
||||||
|
|
||||||
# calculate pdf values
|
# select pdf type
|
||||||
try:
|
pdf = branches[type]
|
||||||
pdf = branches[type](create_axis(x0, incr, npts), barycentre, *params)
|
|
||||||
except TypeError:
|
|
||||||
assert isinstance(barycentre, UTCDateTime), 'object not capable of' \
|
|
||||||
' timestamp representation'
|
|
||||||
pdf = branches[type](create_axis(x0, incr, npts),
|
|
||||||
barycentre.timestamp, *params)
|
|
||||||
|
|
||||||
# return the object
|
# return the object
|
||||||
return ProbabilityDensityFunction(x0, incr, npts, pdf)
|
return ProbabilityDensityFunction(x0, incr, npts, pdf, barycentre,
|
||||||
|
params)
|
||||||
|
|
||||||
def broadcast(self, pdf, si, ei, data):
|
def broadcast(self, pdf, si, ei, data):
|
||||||
try:
|
try:
|
||||||
@ -259,14 +294,14 @@ class ProbabilityDensityFunction(object):
|
|||||||
rval = 0
|
rval = 0
|
||||||
axis = self.axis - self.x0
|
axis = self.axis - self.x0
|
||||||
for n, x in enumerate(axis):
|
for n, x in enumerate(axis):
|
||||||
rval += x * self.data[n]
|
rval += x * self.data(n)
|
||||||
return rval * self.incr + self.x0
|
return rval * self.incr + self.x0
|
||||||
|
|
||||||
def standard_deviation(self):
|
def standard_deviation(self):
|
||||||
mu = self.expectation()
|
mu = self.mu
|
||||||
rval = 0
|
rval = 0
|
||||||
for n, x in enumerate(self.axis):
|
for n, x in enumerate(self.axis):
|
||||||
rval += (x - mu) ** 2 * self.data[n]
|
rval += (x - mu) ** 2 * self.data(n)
|
||||||
return rval * self.incr
|
return rval * self.incr
|
||||||
|
|
||||||
def prob_lt_val(self, value):
|
def prob_lt_val(self, value):
|
||||||
@ -280,8 +315,8 @@ class ProbabilityDensityFunction(object):
|
|||||||
return self.prob_limits((value, self.axis[-1]))
|
return self.prob_limits((value, self.axis[-1]))
|
||||||
|
|
||||||
def prob_limits(self, limits):
|
def prob_limits(self, limits):
|
||||||
lim_ind = np.logical_and(limits[0] <= self.axis, self.axis <= limits[1])
|
lim = np.arange(limits[0], limits[1], self.incr)
|
||||||
data = self.data[lim_ind]
|
data = [self.data(t) for t in lim]
|
||||||
min_est, max_est = 0., 0.
|
min_est, max_est = 0., 0.
|
||||||
for n in range(len(data) - 1):
|
for n in range(len(data) - 1):
|
||||||
min_est += min(data[n], data[n + 1])
|
min_est += min(data[n], data[n + 1])
|
||||||
@ -292,13 +327,20 @@ class ProbabilityDensityFunction(object):
|
|||||||
if not (self.axis[0] <= value <= self.axis[-1]):
|
if not (self.axis[0] <= value <= self.axis[-1]):
|
||||||
Warning('{0} not on axis'.format(value))
|
Warning('{0} not on axis'.format(value))
|
||||||
return None
|
return None
|
||||||
return self.data[find_nearest(self.axis, value)] * self.incr
|
return self.data(value) * self.incr
|
||||||
|
|
||||||
def quantile(self, prob_value, eps=0.01):
|
def quantile(self, prob_value, eps=0.01):
|
||||||
|
'''
|
||||||
|
|
||||||
|
:param prob_value:
|
||||||
|
:param eps:
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
l = self.axis[0]
|
l = self.axis[0]
|
||||||
r = self.axis[-1]
|
r = self.axis[-1]
|
||||||
m = (r + l) / 2
|
m = (r + l) / 2
|
||||||
diff = prob_value - self.prob_lt_val(m)
|
diff = prob_value - self.prob_lt_val(m)
|
||||||
|
|
||||||
while abs(diff) > eps:
|
while abs(diff) > eps:
|
||||||
if diff > 0:
|
if diff > 0:
|
||||||
l = m
|
l = m
|
||||||
@ -306,7 +348,6 @@ class ProbabilityDensityFunction(object):
|
|||||||
r = m
|
r = m
|
||||||
m = (r + l) / 2
|
m = (r + l) / 2
|
||||||
diff = prob_value - self.prob_lt_val(m)
|
diff = prob_value - self.prob_lt_val(m)
|
||||||
print(m, prob_value, self.prob_lt_val(m))
|
|
||||||
return m
|
return m
|
||||||
|
|
||||||
def quantile_distance(self, prob_value):
|
def quantile_distance(self, prob_value):
|
||||||
@ -318,7 +359,9 @@ class ProbabilityDensityFunction(object):
|
|||||||
def plot(self, label=None):
|
def plot(self, label=None):
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
plt.plot(self.axis, self.data)
|
axis = self.axis
|
||||||
|
|
||||||
|
plt.plot(axis, self.data(axis))
|
||||||
plt.xlabel('x')
|
plt.xlabel('x')
|
||||||
plt.ylabel('f(x)')
|
plt.ylabel('f(x)')
|
||||||
plt.autoscale(axis='x', tight=True)
|
plt.autoscale(axis='x', tight=True)
|
||||||
@ -338,6 +381,13 @@ class ProbabilityDensityFunction(object):
|
|||||||
|
|
||||||
return l1, r1
|
return l1, r1
|
||||||
|
|
||||||
|
def cincr(self, other):
|
||||||
|
if not self.incr == other.incr:
|
||||||
|
raise NotImplementedError(
|
||||||
|
'Upsampling of the lower sampled PDF not implemented yet!')
|
||||||
|
else:
|
||||||
|
return self.incr
|
||||||
|
|
||||||
def commonlimits(self, incr, other, max_npts=1e5):
|
def commonlimits(self, incr, other, max_npts=1e5):
|
||||||
'''
|
'''
|
||||||
Takes an increment incr and two left and two right limits and returns
|
Takes an increment incr and two left and two right limits and returns
|
||||||
@ -371,6 +421,15 @@ class ProbabilityDensityFunction(object):
|
|||||||
|
|
||||||
return x0, npts
|
return x0, npts
|
||||||
|
|
||||||
|
def commonparameter(self, other):
|
||||||
|
assert isinstance(other, ProbabilityDensityFunction), \
|
||||||
|
'both operands must be of type ProbabilityDensityFunction'
|
||||||
|
|
||||||
|
incr = self.cincr(other)
|
||||||
|
|
||||||
|
x0, npts = self.commonlimits(incr, other)
|
||||||
|
|
||||||
|
return x0, incr, npts
|
||||||
|
|
||||||
def rearrange(self, other):
|
def rearrange(self, other):
|
||||||
'''
|
'''
|
||||||
@ -382,15 +441,10 @@ class ProbabilityDensityFunction(object):
|
|||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
assert isinstance(other, ProbabilityDensityFunction), \
|
x0 = self.x0
|
||||||
'both operands must be of type ProbabilityDensityFunction'
|
incr = self.incr
|
||||||
|
npts = self.npts
|
||||||
|
|
||||||
if not self.incr == other.incr:
|
|
||||||
raise NotImplementedError('Upsampling of the lower sampled PDF not implemented yet!')
|
|
||||||
else:
|
|
||||||
incr = self.incr
|
|
||||||
|
|
||||||
x0, npts = self.commonlimits(incr, other)
|
|
||||||
|
|
||||||
pdf_self = np.zeros(npts)
|
pdf_self = np.zeros(npts)
|
||||||
pdf_other = np.zeros(npts)
|
pdf_other = np.zeros(npts)
|
||||||
|
7
pylot/testing/test_pdf.py
Normal file
7
pylot/testing/test_pdf.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from pylot.core.util.pdf import ProbabilityDensityFunction
|
||||||
|
pdf = ProbabilityDensityFunction.from_pick(0.34, 0.5, 0.54, type='exp')
|
||||||
|
pdf2 = ProbabilityDensityFunction.from_pick(0.34, 0.5, 0.54, type='exp')
|
||||||
|
diff = pdf - pdf2
|
Loading…
x
Reference in New Issue
Block a user