@@ -191,6 +191,35 @@ def likelihood(self, x):
191
191
alpha [t ] = alpha [t - 1 ].dot (self .A ) * B [:,t ]
192
192
return alpha [- 1 ].sum ()
193
193
194
+ def get_state_sequence (self , x ):
195
+ # returns the most likely state sequence given observed sequence x
196
+ # using the Viterbi algorithm
197
+ T = len (x )
198
+
199
+ # make the emission matrix B
200
+ B = np .zeros ((self .M , T ))
201
+ for j in range (self .M ):
202
+ for t in range (T ):
203
+ for k in range (self .K ):
204
+ p = self .R [j ,k ] * mvn .pdf (x [t ], self .mu [j ,k ], self .sigma [j ,k ])
205
+ B [j ,t ] += p
206
+
207
+ # perform Viterbi as usual
208
+ delta = np .zeros ((T , self .M ))
209
+ psi = np .zeros ((T , self .M ))
210
+ delta [0 ] = self .pi * B [:,0 ]
211
+ for t in range (1 , T ):
212
+ for j in range (self .M ):
213
+ delta [t ,j ] = np .max (delta [t - 1 ]* self .A [:,j ]) * B [j ,t ]
214
+ psi [t ,j ] = np .argmax (delta [t - 1 ]* self .A [:,j ])
215
+
216
+ # backtrack
217
+ states = np .zeros (T , dtype = np .int32 )
218
+ states [T - 1 ] = np .argmax (delta [T - 1 ])
219
+ for t in range (T - 2 , - 1 , - 1 ):
220
+ states [t ] = psi [t + 1 , states [t + 1 ]]
221
+ return states
222
+
194
223
def likelihood_multi (self , X ):
195
224
return np .array ([self .likelihood (x ) for x in X ])
196
225
@@ -245,6 +274,10 @@ def fake_signal(init=simple_init):
245
274
L = hmm .log_likelihood_multi (signals ).sum ()
246
275
print ("LL for actual params:" , L )
247
276
277
+ # print most likely state sequence
278
+ print ("Most likely state sequence for initial observation:" )
279
+ print (hmm .get_state_sequence (signals [0 ]))
280
+
248
281
if __name__ == '__main__' :
249
282
# real_signal() # will break
250
283
fake_signal (init = simple_init )
0 commit comments