<commit_before>.. _tutorial:

========
Tutorial
========

.. currentmodule:: hmmlearn


``hmmlearn`` implements the Hidden Markov Models (HMMs).
The HMM is a generative probabilistic model, in which a sequence of observable
:math:`\mathbf{X}` variables is generated by a sequence of internal hidden
states :math:`\mathbf{Z}`. The hidden states are not be observed directly.
The transitions between hidden states are assumed to have the form of a
(first-order) Markov chain. They can be specified by the start probability
vector :math:`\boldsymbol{\pi}` and a transition probability matrix
:math:`\mathbf{A}`. The emission probability of an observable can be any
distribution with parameters :math:`\boldsymbol{{\theta}}` conditioned on the
current hidden state. The HMM is completely determined by
:math:`\boldsymbol{\pi, \mathbf{A}}` and :math:`\boldsymbol{{\theta}}`.

There are three fundamental problems for HMMs:

* Given the model parameters and observed data, estimate the optimal
  sequence of hidden states.

* Given the model parameters and observed data, calculate the likelihood
  of the data.

* Given just the observed data, estimate the model parameters.


The first and the second problem can be solved by the dynamic programming
algorithms known as
the Viterbi algorithm and the Forward-Backward algorithm, respectively.
The last one can be solved by an iterative Expectation-Maximization (EM)
algorithm, known as the Baum-Welch algorithm.

.. topic:: References:

  [Rabiner89] `A tutorial on hidden Markov models and selected applications in speech recognition <http://www.cs.ubc.ca/~murphyk/Bayes/rabiner.pdf>`_
  Lawrence, <NAME>, 1989


Using HMM
=========

Classes in this module include :class:`~hmm.MultinomialHMM`,
:class:`~hmm.GaussianHMM`, and :class:`~hmm.GMMHMM`. They implement HMM with
emission probabilities determined by multinomial distributions, Gaussian
distributions and mixtures of Gaussian distributions.


Building HMM and generating samples
------------------------------------

You can build an HMM instance by passing the parameters described above to the
constructor. Then, you can generate samples from the HMM by calling
:meth:`~base._BaseHMM.sample`.::

    >>> import numpy as np
    >>> from hmmlearn import hmm
    >>> np.random.seed(42)

    >>> model = hmm.GaussianHMM(n_components=3, covariance_type="full")
    >>> model.startprob_ = np.array([0.6, 0.3, 0.1])
    >>> model.transmat_ = np.array([[0.7, 0.2, 0.1],
    ...                             [0.3, 0.5, 0.2],
    ...                             [0.3, 0.3, 0.4]])
    >>> model.means_ = np.array([[0.0, 0.0], [3.0, -3.0], [5.0, 10.0]])
    >>> model.covars_ = np.tile(np.identity(2), (3, 1, 1))
    >>> X, Z = model.sample(100)

The transition matrix need not to be ergodic. For instance, a left-right HMM can
be defined as follows::

    >>> lr = hmm.GaussianHMM(n_components=3, covariance_type="diag",
    ...                      init_params="cm", params="cmt")
    >>> lr.startprob_ = np.array([0.0, 0.0, 1.0])
    >>> lr.transmat_ = np.array([[0.5, 0.5, 0.0],
    ...                          [0.0, 0.5, 0.5],
    ...                          [0.0, 0.0, 1.0]])

.. topic:: Examples:

 * :ref:`example_auto_examples_plot_hmm_sampling.py`

Training HMM parameters and inferring the hidden states
-------------------------------------------------------

You can train an HMM by calling the :meth:`~base._BaseHMM.fit` method. The input
is a matrix of concatenated sequences of observations along with the lengths of
the sequences. Note, since the EM-algorithm is a gradient-based optimization
method, it will generally get stuck in local optima. You should in general try
to run ``fit`` with various initializations and select the highest scored model.

The score of the model can be calculated by the :meth:`~base._BaseHMM.score` method.

The inferred optimal hidden states can be obtained by calling
:meth:`~base._BaseHMM.predict` method. The ``predict`` method can be
specified with decoder algorithm. Currently the Viterbi algorithm
(``"viterbi"``), and maximum a posteriori estimation (``"map"``) are supported.

This time, the input is a single sequence of observed values.  Note, the states
in ``remodel`` will have a different order than those in the generating model.::

    >>> remodel = hmm.GaussianHMM(n_components=3, covariance_type="full", n_iter=100)
    >>> remodel.fit(X)  # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
    GaussianHMM(algorithm='viterbi',...
    >>> Z2 = remodel.predict(X)

.. note:: Monitoring convergence

   The number of EM-algorithm iteration is upper bounded by the ``n_iter``
   parameter. The training proceeds until ``n_iter`` steps were performed or the
   change in score is lower than the specified threshold ``tol``. Note, that
   depending on the data EM-algorithm may or may not achieve convergence in the
   given number of steps.

   You can use the ``monitor`` attribute to diagnose convergence::

       >>> remodel.monitor_  # doctest: +ELLIPSIS
       ConvergenceMonitor(history=[...],
                 iter=12, n_iter=100, tol=0.01, verbose=False)
       >>> remodel.monitor_.converged
       True

.. topic:: Examples:

 * :ref:`example_auto_examples_plot_hmm_stock_analysis.py`

Implementing HMMs with custom emission probabilities
----------------------------------------------------

If you want to implement other emission probability (e.g. Poisson), you have to
implement a new HMM class by inheriting the :class:`~base._BaseHMM` and
overriding the methods `__init__`, `_compute_log_likelihood`,
`_set` and `_get` for additional parameters,
`_initialize_sufficient_statistics`, `_accumulate_sufficient_statistics` and
`_do_mstep`.
<commit_msg>DOC fixed left-right HMM example<commit_after>.. _tutorial:

========
Tutorial
========

.. currentmodule:: hmmlearn


``hmmlearn`` implements the Hidden Markov Models (HMMs).
The HMM is a generative probabilistic model, in which a sequence of observable
:math:`\mathbf{X}` variables is generated by a sequence of internal hidden
states :math:`\mathbf{Z}`. The hidden states are not be observed directly.
The transitions between hidden states are assumed to have the form of a
(first-order) Markov chain. They can be specified by the start probability
vector :math:`\boldsymbol{\pi}` and a transition probability matrix
:math:`\mathbf{A}`. The emission probability of an observable can be any
distribution with parameters :math:`\boldsymbol{{\theta}}` conditioned on the
current hidden state. The HMM is completely determined by
:math:`\boldsymbol{\pi, \mathbf{A}}` and :math:`\boldsymbol{{\theta}}`.

There are three fundamental problems for HMMs:

* Given the model parameters and observed data, estimate the optimal
  sequence of hidden states.

* Given the model parameters and observed data, calculate the likelihood
  of the data.

* Given just the observed data, estimate the model parameters.


The first and the second problem can be solved by the dynamic programming
algorithms known as
the Viterbi algorithm and the Forward-Backward algorithm, respectively.
The last one can be solved by an iterative Expectation-Maximization (EM)
algorithm, known as the Baum-Welch algorithm.

.. topic:: References:

  [Rabiner89] `A tutorial on hidden Markov models and selected applications in speech recognition <http://www.cs.ubc.ca/~murphyk/Bayes/rabiner.pdf>`_
  Lawrence, <NAME>, 1989


Using HMM
=========

Classes in this module include :class:`~hmm.MultinomialHMM`,
:class:`~hmm.GaussianHMM`, and :class:`~hmm.GMMHMM`. They implement HMM with
emission probabilities determined by multinomial distributions, Gaussian
distributions and mixtures of Gaussian distributions.


Building HMM and generating samples
------------------------------------

You can build an HMM instance by passing the parameters described above to the
constructor. Then, you can generate samples from the HMM by calling
:meth:`~base._BaseHMM.sample`.::

    >>> import numpy as np
    >>> from hmmlearn import hmm
    >>> np.random.seed(42)

    >>> model = hmm.GaussianHMM(n_components=3, covariance_type="full")
    >>> model.startprob_ = np.array([0.6, 0.3, 0.1])
    >>> model.transmat_ = np.array([[0.7, 0.2, 0.1],
    ...                             [0.3, 0.5, 0.2],
    ...                             [0.3, 0.3, 0.4]])
    >>> model.means_ = np.array([[0.0, 0.0], [3.0, -3.0], [5.0, 10.0]])
    >>> model.covars_ = np.tile(np.identity(2), (3, 1, 1))
    >>> X, Z = model.sample(100)

The transition matrix need not to be ergodic. For instance, a left-right HMM can
be defined as follows::

    >>> lr = hmm.GaussianHMM(n_components=3, covariance_type="diag",
    ...                      init_params="cm", params="cmt")
    >>> lr.startprob_ = np.array([1.0, 0.0, 0.0])
    >>> lr.transmat_ = np.array([[0.5, 0.5, 0.0],
    ...                          [0.0, 0.5, 0.5],
    ...                          [0.0, 0.0, 1.0]])

.. topic:: Examples:

 * :ref:`example_auto_examples_plot_hmm_sampling.py`

Training HMM parameters and inferring the hidden states
-------------------------------------------------------

You can train an HMM by calling the :meth:`~base._BaseHMM.fit` method. The input
is a matrix of concatenated sequences of observations along with the lengths of
the sequences. Note, since the EM-algorithm is a gradient-based optimization
method, it will generally get stuck in local optima. You should in general try
to run ``fit`` with various initializations and select the highest scored model.

The score of the model can be calculated by the :meth:`~base._BaseHMM.score` method.

The inferred optimal hidden states can be obtained by calling
:meth:`~base._BaseHMM.predict` method. The ``predict`` method can be
specified with decoder algorithm. Currently the Viterbi algorithm
(``"viterbi"``), and maximum a posteriori estimation (``"map"``) are supported.

This time, the input is a single sequence of observed values.  Note, the states
in ``remodel`` will have a different order than those in the generating model.::

    >>> remodel = hmm.GaussianHMM(n_components=3, covariance_type="full", n_iter=100)
    >>> remodel.fit(X)  # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
    GaussianHMM(algorithm='viterbi',...
    >>> Z2 = remodel.predict(X)

.. note:: Monitoring convergence

   The number of EM-algorithm iteration is upper bounded by the ``n_iter``
   parameter. The training proceeds until ``n_iter`` steps were performed or the
   change in score is lower than the specified threshold ``tol``. Note, that
   depending on the data EM-algorithm may or may not achieve convergence in the
   given number of steps.

   You can use the ``monitor`` attribute to diagnose convergence::

       >>> remodel.monitor_  # doctest: +ELLIPSIS
       ConvergenceMonitor(history=[...],
                 iter=12, n_iter=100, tol=0.01, verbose=False)
       >>> remodel.monitor_.converged
       True

.. topic:: Examples:

 * :ref:`example_auto_examples_plot_hmm_stock_analysis.py`

Implementing HMMs with custom emission probabilities
----------------------------------------------------

If you want to implement other emission probability (e.g. Poisson), you have to
implement a new HMM class by inheriting the :class:`~base._BaseHMM` and
overriding the methods `__init__`, `_compute_log_likelihood`,
`_set` and `_get` for additional parameters,
`_initialize_sufficient_statistics`, `_accumulate_sufficient_statistics` and
`_do_mstep`.

{'fraction_non_alphanumeric': 0.13387477076237883, 'fraction_numerical': 0.015893808401013013, 'mean_word_length': 3.3709923664122137, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 109, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7509687', 'n_tokens_mistral': 3433, 'n_tokens_neox': 3191, 'n_words': 1248}