HMM Procedure

Gaussian Hidden Markov Model

Let bold upper Y Subscript t Baseline equals left-parenthesis y Subscript 1 t Baseline comma ellipsis comma y Subscript p t Baseline right-parenthesis Superscript prime Baseline comma t equals 1 comma ellipsis comma upper T, denote a p-dimensional time series vector of random variables. Conditional on a latent variable bold upper S Subscript t, bold upper Y Subscript t follows a normal distribution,

StartLayout 1st Row  bold upper Y Subscript t Baseline vertical-bar bold upper S Subscript t Baseline tilde upper N left-parenthesis mu Subscript bold upper S Sub Subscript t Subscript Baseline comma normal upper Sigma Subscript bold upper S Sub Subscript t Subscript Baseline right-parenthesis EndLayout

where mu Subscript bold upper S Sub Subscript t and normal upper Sigma Subscript bold upper S Sub Subscript t are mean and covariance parameters whose values depend on the variable bold upper S Subscript t. The variable bold upper S Subscript t, the so-called state, follows the first-order Markov chain; that is,

StartLayout 1st Row  p left-parenthesis bold upper S Subscript t Baseline vertical-bar bold upper S Subscript t minus 1 Baseline comma bold upper S Subscript t minus 2 Baseline comma ellipsis comma bold upper S 1 right-parenthesis equals p left-parenthesis bold upper S Subscript t Baseline vertical-bar bold upper S Subscript t minus 1 Baseline right-parenthesis EndLayout

where p left-parenthesis period vertical-bar period right-parenthesis denotes the conditional probability. The range of bold upper S Subscript t is a finite set, StartSet 1 comma ellipsis comma upper K EndSet. The transition probability from state i to state j is expressed as

StartLayout 1st Row  a Subscript i j Baseline equals p left-parenthesis bold upper S Subscript t Baseline equals j vertical-bar bold upper S Subscript t minus 1 Baseline equals i right-parenthesis EndLayout

The upper K times upper K matrix bold upper A equals StartSet a Subscript i j Baseline EndSet is called the transition probability matrix (TPM). The last element in the model is the initial state probability vector (ISPV), pi, of the first state bold upper S 1:

StartLayout 1st Row  pi equals StartSet pi Subscript i Baseline equals p left-parenthesis bold upper S 1 equals i right-parenthesis comma i equals 1 comma ellipsis comma upper K EndSet EndLayout

Because the variable bold upper S Subscript t is unobservable and follows a Markov chain and because bold upper Y Subscript t follows a Gaussian distribution conditional on bold upper S Subscript t, the model is called the Gaussian hidden Markov model (Gaussian HMM). The Gaussian HMM is sometimes described as StartSet pi comma bold upper A comma bold upper B EndSet, where bold upper B identical-to StartSet mu Subscript i Baseline comma normal upper Sigma Subscript i Baseline comma i equals 1 comma ellipsis comma upper K EndSet, consisting of parameters that define the state-dependent distribution of observable variables.

Consider a bivariate Gaussian HMM that has the following parameter values:

StartLayout 1st Row  pi equals StartBinomialOrMatrix 0.5 Choose 0.5 EndBinomialOrMatrix comma bold upper A equals Start 2 By 2 Matrix 1st Row 1st Column 0.001 2nd Column 0.999 2nd Row 1st Column 0.999 2nd Column 0.001 EndMatrix EndLayout
StartLayout 1st Row  mu 1 equals StartBinomialOrMatrix 1 Choose 1 EndBinomialOrMatrix comma normal upper Sigma 1 equals Start 2 By 2 Matrix 1st Row 1st Column 1 2nd Column 0 2nd Row 1st Column 0 2nd Column 1 EndMatrix comma mu 2 equals StartBinomialOrMatrix negative 1 Choose negative 1 EndBinomialOrMatrix comma normal upper Sigma 2 equals Start 2 By 2 Matrix 1st Row 1st Column 1 2nd Column 0 2nd Row 1st Column 0 2nd Column 1 EndMatrix EndLayout

The following statements simulate the bivariate vector time series from the previous model to provide test data for the HMM procedure:

%let pi1 = 0.5;
%let a11 = 0.001;
%let a22 = 0.001;
%let mu1_1 = 1;
%let mu1_2 = 1;
%let sigma1_11 = 1;
%let sigma1_21 = 0;
%let sigma1_22 = 1;
%let mu2_1 = -1;
%let mu2_2 = -1;
%let sigma2_11 = 1;
%let sigma2_21 = 0;
%let sigma2_22 = 1;
%let T = 10000;
%let seed = 1234;

data DGPone;
   retain cd1_11 cd1_21 cd1_22 cd2_11 cd2_21 cd2_22;
   do t = 1 to &T.;
      if(t=1) then do;
         /* initial probability distribution */
         p = &pi1.;
         /* Cholesky decomposition of sigma1 */
         cd1_11 = sqrt(&sigma1_11.);
         cd1_21 = &sigma1_21./sqrt(&sigma1_11.);
         cd1_22 = sqrt(&sigma1_22.-&sigma1_21.*&sigma1_21./&sigma1_11.);
         /* Cholesky decomposition of sigma2 */
         cd2_11 = sqrt(&sigma2_11.);
         cd2_21 = &sigma2_21./sqrt(&sigma2_11.);
         cd2_22 = sqrt(&sigma2_22.-&sigma2_21.*&sigma2_21./&sigma2_11.);
      end;
      else do;
         /* transition probability matrix */
         if(lags=1) then p = &a11.;
         else p = 1-&a22.;
      end;
      u = uniform(&seed.);
      if(u<=p) then s=1;
      else s = 2;
      e1 = normal(&seed.); e2 = normal(&seed.);
      if(s=1) then do;
         /* (x,y) ~ N(mu1, Sigma1) at state 1 */
         x = &mu1_1. + cd1_11*e1;
         y = &mu1_2. + cd1_21*e1+cd1_22*e2;
      end;
      else do;
         /* (x,y) ~ N(mu2, Sigma2) at state 2 */
         x = &mu2_1. + cd2_11*e1;
         y = &mu2_2. + cd2_21*e1+cd2_22*e2;
      end;
      output;
      lags = s;
   end;
run;

data One;
   set DGPone;
   keep t x y;
run;

In general, the data generating process is unknown. What can be seen is the data table One, but not the data table DGPone.

The following statements plot the simulated series x:

proc sgplot data=One;
   series x=t y=x;
run;

Figure 1 shows the plot of x, whose points seem to fall randomly around 0.

Figure 1: Plot of Time Series x

Plot of Time Series


The following statements plot the simulated series y:

proc sgplot data=One;
   series x=t y=y;
run;

Figure 2 shows the plot of y, whose points also seem to fall randomly around 0.

Figure 2: Plot of Time Series y

Plot of Time Series


Ignoring the sequential information, the following statements plot the observed points left-parenthesis x comma y right-parenthesis:

proc sgplot data=One;
   scatter y=y x=x;
run;

As shown in Figure 3, it seems that the points come from two different cluster centers, and many of them lie between two cluster centers.

Figure 3: Unclassified Observations

Unclassified Observations


It is very difficult for any cluster analysis methods that cannot use the sequential information to find the correct states for the points that lie between two cluster centers. The simplest cluster analysis method to classify the points, because of the symmetry shown in Figure 3, is to draw a line y equals negative x, classify all points above the line to one state, and classify all points below the line to another state.[6] The following statements implement this simplest cluster analysis method and calculate the accuracy, based on the data table DGPone:

/* classify the data points by the line y = -x */
data Cluster;
   set One;
   if(y>-x) then state = 1;
   else state = 2;
   keep t state;
run;

data clusterCheck;
   merge DGPone(in=a) Cluster(in=b);
   by t;
   if(s=state) then correct = 1;
   else correct = 0;
   if(a=b);
   keep correct;
run;

data clusterAccuracy;
   set clusterCheck;
   retain count 0 correctCount 0;
   count = count + 1;
   correctCount = correctCount + correct;
   if(count>&T.-0.5) then do;
      accuracy = correctCount / count;
      if(accuracy<0.5) then accuracy = 1 - accuracy;
      output;
   end;
   keep accuracy;
run;

proc print data = clusterAccuracy noobs; run;

The accuracy of the cluster analysis, which is shown in Figure 4, is 92.02%. This implies that the cluster analysis cannot choose the correct states for about 800 data points!

Figure 4: Accuracy of Cluster Analysis

accuracy
0.9202


What is the big difference that you get by using the sequential information through HMMs? Before estimating any model, make a copy of the data in the library:

   data mylib.One; set One; run;

The following statements estimate the two-state Gaussian HMM and then classify the data points through decoding; here decoding means to find the best possible state path for the observed data. The SORT=DESC(MU) option requests that the states be labeled in descending order of the mean parameter values; for more information about the label switching problem, see the section Label Switching Problem.

proc hmm data=mylib.One labelSwitch=(sort=desc(mu));
   id time=t;
   model x y / type=gaussian nstate=2;
   optimize printLevel=3 printIterFreq=1;
   decode out=mylib.oneDecode;
run;

The number of observations and model information are shown in Figure 5.

Figure 5: Number of Observations and Model Information

Observation Information
Number of Observations10000
Number of Missing Observations0

Model Information
Type of ModelGaussian HMM
StationaryYes
Number of States2
Number of Dependent Variables2


The default method, which is the maximum likelihood method, is applied; this is a nonlinear optimization problem. The initial parameter values and the objective function value at the start of the optimization are shown in Figure 6.

Figure 6: Initial Parameter Values and Objective Function Value

Optimization Start
ParameterEstimate
TPM1_10.500000
TPM1_20.500000
TPM2_10.500000
TPM2_20.500000
MU1_10.642059
MU1_20.513308
MU2_1-1.609545
MU2_2-1.329369
SIGMA1_1_11.152038
SIGMA1_2_10.320856
SIGMA1_2_21.478814
SIGMA2_1_10.525065
SIGMA2_2_1-0.243910
SIGMA2_2_20.892018

Initial Value of Objective Function-34510.54106


The details of the optimization algorithm are shown in Figure 7.

Figure 7: Optimization Algorithm Details

Algorithm Settings
Maximum Number of Iterations128
Tolerance for Optimality Error1E-6
Tolerance for Infeasibility1E-6
Maximum Allowed Time (seconds)1.797693E308
Maximum Magnitude of Objective Function Value1E20
Random Seed1
Solution Type1
Multi-Start Globalization Scheme0
Multi-Start Globalization Bound Range2


The iterations of the optimization process are shown in Figure 8.

Figure 8: Iterations of the Optimization Process

Iteration History
IterationObjective
Function
Optimality
Error
InfeasibilityFunction
Calls
Gradient
Calls
Hessian
Calls
1-34510.54106610.243920.00000210
2-29343.35393350.546140.0000011101
3-28606.4500478.052030.0000019182
4-28467.876801.420970.0000028273
5-28460.412820.349980.0000037364
6-28459.087280.100300.0000046455
7-28458.800390.029680.0000055546
8-28458.735760.008120.0000064637
9-28458.725520.001670.0000073728
10-28458.724840.000180.0000082819
11-28458.724830.000000.00000919010


The final parameter values and the objective function value at the end of the optimization are shown in Figure 9.

Figure 9: Final Parameter Values and Objective Function Value

Optimization Results
ParameterEstimate
TPM1_10.002071
TPM1_20.997929
TPM2_10.999863
TPM2_20.000137
MU1_11.006466
MU1_20.994184
MU2_1-0.993036
MU2_2-1.007869
SIGMA1_1_11.011152
SIGMA1_2_10.006387
SIGMA1_2_20.988329
SIGMA2_1_10.992333
SIGMA2_2_1-0.005378
SIGMA2_2_21.008722

Final Value of Objective Function-28458.72483


The estimates of the initial state probability vector (ISPV) are shown in Figure 10.

Figure 10: Estimates of Initial State Probability Vector

Initial State Probabilities
StateEstimation
10.50048
20.49952


The estimates of the transition probability matrix (TPM) are shown in Figure 11.

Figure 11: Estimates of Transition Probability Matrix

Estimated Transition Probability Matrix
State12
10.002070.99793
20.999860.00014


The estimates of the mean vector of the Gaussian distribution for each state are shown in Figure 12.

Figure 12: Estimate of Mean Vector for Each State

Mu
Statexy
11.006470.99418
2-0.99304-1.00787


The estimates of the covariance matrix of the Gaussian distribution for each state are shown in Figure 13.

Figure 13: Estimate of Covariance Matrix for Each State

Sigma
StateVariablexy
1x1.011150.00639
 y0.006390.98833
2x0.99233-0.00538
 y-0.005381.00872


The estimates of all parameters are shown in Figure 14, which displays columns for the parameter name, estimate value, standard error, t-value, and p-value.

Figure 14: Parameter Estimates

Parameter Estimates
ParameterEstimateStandard
Error
t ValuePr > |t|
TPM1_10.0020710.0007112.910.0036
TPM1_20.9979290.0007111403.15<.0001
TPM2_10.9998630.0003422926.28<.0001
TPM2_20.0001370.0003420.400.6888
MU1_11.0064660.01422870.74<.0001
MU1_20.9941840.01405470.74<.0001
MU2_1-0.9930360.014096-70.45<.0001
MU2_2-1.0078690.014217-70.89<.0001
SIGMA1_1_11.0111520.02025249.93<.0001
SIGMA1_2_10.0063870.0141390.450.6514
SIGMA1_2_20.9883290.01975750.02<.0001
SIGMA2_1_10.9923330.01985949.97<.0001
SIGMA2_2_1-0.0053780.014159-0.380.7041
SIGMA2_2_21.0087220.02019449.95<.0001


The log likelihood and information criteria are shown in Figure 15.

Figure 15: Log Likelihood and Information Criteria

Fit Statistics
Log Likelihood-28458.72483
AIC56941.449663
AICC56941.480904
BIC57027.973748
HQC56970.737507


The accuracy of classification through the Gaussian HMM is calculated by the following statements:

data gHmmCheck;
   merge DGPone(in=a) mylib.oneDecode(in=b);
   by t;
   if(s=state) then do; correct=1; ds = s; end;
   else do; correct=0; ds = -s; end;
   if(a=b);
   keep t x y s correct ds;
run;

%let qFlipState = -1;
data gHmmAccuracy;
   set gHmmCheck;
   retain count 0 correctCount 0;
   count = count + 1;
   correctCount = correctCount + correct;
   if(count>&T.-0.5) then do;
      accuracy = correctCount / count;
      if(accuracy<0.5) then call symputx("qFlipState",1,'G');
      else call symputx("qFlipState",0,'G');
      if(accuracy<0.5) then accuracy = 1 - accuracy;
      output;
   end;
   keep accuracy;
run;

data gHmmCheck;
   set gHmmCheck;
   if(&qFlipState.=1) then do;
      ds = -ds;
      correct = 1 - correct;
   end;
run;

proc print data = gHmmAccuracy noobs; run;

The accuracy of the Gaussian HMM, which is shown in Figure 16, is 99.99%. This means that the Gaussian HMM successfully takes advantage of the sequential information: only 1 data point cannot be correctly classified, compared to about 800 points that cannot be correctly classified by the cluster analysis method without the sequential information.

Figure 16: Accuracy of Decoding by the Gaussian HMM

accuracy
0.9999


To show how well the data are classified, the previous statements label any incorrectly classified data points with negative state values. In this example, only 1 point is not correctly classified. You plot the classified data points by using the following statements. The plot is shown in Figure 17.

proc sgplot data=gHmmCheck;
   scatter y=y x=x / group=ds;
run;

Figure 17: Classified Data Points by Gaussian HMM

Classified Data Points by Gaussian HMM




[6] In theory, no cluster analysis method, without using the sequential information, could do a better job on this data table than this simplest cluster analysis method.

Last updated: July 09, 2026