public void LearnTest11()
{
// Suppose we have a set of six sequences and we would like to
// fit a hidden Markov model with mixtures of Normal distributions
// as the emission densities.
// First, let's consider a set of univariate sequences:
double[][] sequences =
{
new double[] { 1, 1, 2, 2, 2, 3, 3, 3 },
new double[] { 1, 2, 2, 2, 3, 3 },
new double[] { 1, 2, 2, 3, 3, 5 },
new double[] { 2, 2, 2, 2, 3, 3, 3, 4, 5, 5, 1 },
new double[] { 1, 1, 1, 2, 2, 5 },
new double[] { 1, 2, 2, 4, 4, 5 },
};
// Now we can begin specifying a initial Gaussian mixture distribution. It is
// better to add some different initial parameters to the mixture components:
var density = new Mixture<NormalDistribution>(
new NormalDistribution(mean: 2, stdDev: 1.0), // 1st component in the mixture
new NormalDistribution(mean: 0, stdDev: 0.6), // 2nd component in the mixture
new NormalDistribution(mean: 4, stdDev: 0.4), // 3rd component in the mixture
new NormalDistribution(mean: 6, stdDev: 1.1) // 4th component in the mixture
);
// Let's then create a continuous hidden Markov Model with two states organized in a forward
// topology with the underlying univariate Normal mixture distribution as probability density.
var model = new HiddenMarkovModel<Mixture<NormalDistribution>>(new Forward(2), density);
// Now we should configure the learning algorithms to train the sequence classifier. We will
// learn until the difference in the average log-likelihood changes only by as little as 0.0001
var teacher = new BaumWelchLearning<Mixture<NormalDistribution>>(model)
{
Tolerance = 0.0001,
Iterations = 0,
// Note, however, that since this example is extremely simple and we have only a few
// data points, a full-blown mixture wouldn't really be needed. Thus we will have a
// great chance that the mixture would become degenerated quickly. We can avoid this
// by specifying some regularization constants in the Normal distribution fitting:
FittingOptions = new MixtureOptions()
{
Iterations = 1, // limit the inner e-m to a single iteration
InnerOptions = new NormalOptions()
{
Regularization = 1e-5 // specify a regularization constant
}
}
};
// Finally, we can fit the model
double logLikelihood = teacher.Run(sequences);
// And now check the likelihood of some approximate sequences.
double a1 = Math.Exp(model.Evaluate(new double[] { 1, 1, 2, 2, 3 })); // 2.3413833128741038E+45
double a2 = Math.Exp(model.Evaluate(new double[] { 1, 1, 2, 5, 5 })); // 9.94607618459872E+19
// We can see that the likelihood of an unrelated sequence is much smaller:
double a3 = Math.Exp(model.Evaluate(new double[] { 8, 2, 6, 4, 1 })); // 1.5063654166181737E-44
Assert.IsTrue(a1 > 1e+6);
Assert.IsTrue(a2 > 1e+6);
Assert.IsTrue(a3 < 1e-6);
Assert.IsFalse(Double.IsNaN(a1));
Assert.IsFalse(Double.IsNaN(a2));
Assert.IsFalse(Double.IsNaN(a3));
}