我正在Python / NumPy中实现贝叶斯变换点检测(如果您有兴趣看一下paper)。我需要计算范围[a, b]
中数据的可能性,其中a
和b
可以包含从1
到n
的所有值。但是我可以在某些点修剪计算,这样我就不必计算每一个可能性。另一方面,一些可能性被使用不止一次,因此我可以通过将值保存在矩阵P[a, b]
中来节省时间。现在我检查值是否已经计算,每当我使用它,但我发现有点麻烦。它看起来像这样:
# ...
P = np.ones((n, n)) * np.inf # a likelihood can't get inf, so I use it
# as pseudo value
for a in range(n):
for b in range(a, n):
# The following two lines get annoying and error prone if you
# use P more than once
if P[a, b] == np.inf:
P[a, b] = likelihood(data, a, b)
Q[a] += P[a, b] * g[a] * Q[a - 1] # some computation using P[a, b]
# ...
我想知道,在每次使用if ...
之前,是否有更直观和pythonic的方法来实现这一点,而没有P[a, b]
语句。如果不满足某些条件,就像自动函数调用一样。我当然可以使likelihood
函数意识到它可以保存值,但它需要某种状态(例如成为一个对象)。我想避免这种情况。
似然函数
由于在评论中被要求,我添加了似然函数。它实际上计算先前的共轭,然后计算可能性。所有的日志表示......所以它非常复杂。
from scipy.special import gammaln
def gaussian_obs_log_likelihood(data, t, s):
n = s - t
mean = data[t:s].sum() / n
muT = (n * mean) / (1 + n)
nuT = 1 + n
alphaT = 1 + n / 2
betaT = 1 + 0.5 * ((data[t:s] - mean) ** 2).sum() + ((n)/(1 + n)) * (mean**2 / 2)
scale = (betaT*(nuT + 1))/(alphaT * nuT)
# splitting the PDF of the student distribution up is /much/ faster. (~ factor 20)
prob = 1
for yi in data[t:s]:
prob += np.log(1 + (yi - muT)**2/(nuT * scale))
lgA = gammaln((nuT + 1) / 2) - np.log(np.sqrt(np.pi * nuT * scale)) - gammaln(nuT/2)
return n * lgA - (nuT + 1)/2 * prob
虽然我使用的是Python 2.7,但2.7和3.x的答案都很受欢迎。
答案 0 :(得分:4)
我会使用defaultdict
的兄弟(你不能直接使用defaultdict
,因为它不会告诉你缺少的密钥):
class Cache(object):
def __init__(self):
self.cache = {}
def get(self, a, b):
key = (a,b)
result = self.cache.get(key, None)
if result is None:
result = likelihood(data, a, b)
self.cache[key] = result
return result
另一种方法是在likelihood
as described here上使用缓存装饰器。