1
1
from __future__ import division
2
2
import numpy as np
3
- from scipy .special import gammaln
3
+ from scipy .special import gammaln , multigammaln
4
4
from scipy .misc import comb
5
5
from decorator import decorator
6
6
@@ -39,12 +39,13 @@ def offline_changepoint_detection(data, prior_func,
39
39
"""Compute the likelihood of changepoints on data.
40
40
41
41
Keyword arguments:
42
- data -- the time series data
43
- prior_func -- a function given the likelihood of a changepoint given the
44
- distance to the last one
42
+ data -- the time series data
43
+ prior_func -- a function given the likelihood of a changepoint given the distance to the last one
45
44
observation_log_likelihood_function -- a function giving the log likelihood
46
45
of a data part
47
- P -- the likelihoods if pre-computed
46
+ truncate -- the cutoff probability 10^truncate to stop computation for that changepoint log likelihood
47
+
48
+ P -- the likelihoods if pre-computed
48
49
"""
49
50
50
51
n = len (data )
@@ -65,9 +66,9 @@ def offline_changepoint_detection(data, prior_func,
65
66
Q [n - 1 ] = P [n - 1 , n - 1 ]
66
67
67
68
for t in reversed (range (n - 1 )):
68
- P_next_cp = - np .inf # == - log(0)
69
+ P_next_cp = - np .inf # == log(0)
69
70
for s in range (t , n - 1 ):
70
- P [t , s ] = observation_log_likelihood_function (data , t , s + 1 )
71
+ P [t , s ] = observation_log_likelihood_function (data , t , s + 1 )
71
72
72
73
# compute recursion
73
74
summand = P [t , s ] + Q [s + 1 ] + g [s + 1 - t ]
@@ -82,7 +83,7 @@ def offline_changepoint_detection(data, prior_func,
82
83
83
84
# (1 - G) is numerical stable until G becomes numerically 1
84
85
if G [n - 1 - t ] < - 1e-15 : # exp(-1e-15) = .99999...
85
- antiG = np .log (1 - np .exp (G [n - 1 - t ]))
86
+ antiG = np .log (1 - np .exp (G [n - 1 - t ]))
86
87
else :
87
88
# (1 - G) is approx. -log(G) for G close to 1
88
89
antiG = np .log (- G [n - 1 - t ])
@@ -108,28 +109,65 @@ def gaussian_obs_log_likelihood(data, t, s):
108
109
s += 1
109
110
n = s - t
110
111
mean = data [t :s ].sum (0 ) / n
111
-
112
+
112
113
muT = (n * mean ) / (1 + n )
113
114
nuT = 1 + n
114
115
alphaT = 1 + n / 2
115
116
betaT = 1 + 0.5 * ((data [t :s ] - mean ) ** 2 ).sum (0 ) + ((n )/ (1 + n )) * (mean ** 2 / 2 )
116
117
scale = (betaT * (nuT + 1 ))/ (alphaT * nuT )
117
-
118
+
118
119
# splitting the PDF of the student distribution up is /much/ faster.
119
120
# (~ factor 20) using sum over for loop is even more worthwhile
120
121
prob = np .sum (np .log (1 + (data [t :s ] - muT )** 2 / (nuT * scale )))
121
122
lgA = gammaln ((nuT + 1 ) / 2 ) - np .log (np .sqrt (np .pi * nuT * scale )) - gammaln (nuT / 2 )
122
-
123
+
123
124
return np .sum (n * lgA - (nuT + 1 )/ 2 * prob )
124
125
126
+ def ifm_obs_log_likelihood (data , t , s ):
127
+ '''Independent Features model from xuan et al'''
128
+ s += 1
129
+ n = s - t
130
+ x = data [t :s ]
131
+ if len (x .shape )== 2 :
132
+ d = x .shape [1 ]
133
+ else :
134
+ d = 1
135
+ x = np .atleast_2d (x ).T
136
+
137
+ N0 = d # weakest prior we can use to retain proper prior
138
+ V0 = np .var (x )
139
+ Vn = V0 + (x ** 2 ).sum (0 )
140
+
141
+ # sum over dimension and return (section 3.1 from Xuan paper):
142
+ return d * ( - (n / 2 )* np .log (np .pi ) + (N0 / 2 )* np .log (V0 ) - \
143
+ gammaln (N0 / 2 ) + gammaln ((N0 + n )/ 2 ) ) - \
144
+ ( ((N0 + n )/ 2 )* np .log (Vn ) ).sum (0 )
145
+
146
+ def fullcov_obs_log_likelihood (data , t , s ):
147
+ '''Full Covariance model from xuan et al'''
148
+ s += 1
149
+ n = s - t
150
+ x = data [t :s ]
151
+ if len (x .shape )== 2 :
152
+ dim = x .shape [1 ]
153
+ else :
154
+ dim = 1
155
+ x = np .atleast_2d (x ).T
156
+
157
+ N0 = dim # weakest prior we can use to retain proper prior
158
+ V0 = np .var (x )* np .eye (dim )
159
+ Vn = V0 + np .array ([np .outer (x [i ], x [i ].T ) for i in xrange (x .shape [0 ])]).sum (0 )
160
+
161
+ # section 3.2 from Xuan paper:
162
+ return - (dim * n / 2 )* np .log (np .pi ) + (N0 / 2 )* np .linalg .slogdet (V0 )[1 ] - \
163
+ multigammaln (N0 / 2 ,dim ) + multigammaln ((N0 + n )/ 2 ,dim ) - \
164
+ ((N0 + n )/ 2 )* np .linalg .slogdet (Vn )[1 ]
125
165
126
166
def const_prior (r , l ):
127
167
return 1 / (l )
128
168
129
-
130
169
def geometric_prior (t , p ):
131
170
return p * ((1 - p ) ** (t - 1 ))
132
171
133
-
134
172
def neg_binominal_prior (t , k , p ):
135
173
return comb (t - k , k - 1 ) * p ** k * (1 - p ) ** (t - k )
0 commit comments