HMM Procedure
Gaussian Mixture Hidden Markov Model for Time Series Data and Cross-Sectional Time Series Data
Let
, denote a p-dimensional time series vector of random variables. Conditional on a latent variable
,
follows a Gaussian mixture distribution,
where the variable is the (hidden) state;
represents the Gaussian mixture distribution; M is the number of components at each state; and the
, are mixture component probabilities (MCPs, also called mixture weights), which satisfy the basic requirement for weights (
and
). The
and
are the mean and covariance parameters for the jth Gaussian component at state
, and their values depend on the variable
. The state variable
follows the first-order Markov chain; that is,
where denotes the conditional probability. The range of
is a finite set,
. The transition probability from state i to state j is expressed as
The matrix
is called the transition probability matrix (TPM). The last element in the model is the initial state probability vector (ISPV),
, of the first state
:
Because the variable is unobservable and follows a Markov chain and because
follows a Gaussian mixture distribution conditional on
, the model is called the Gaussian mixture hidden Markov model (GM HMM). The GM HMM is sometimes described as
, where
, and it consists of parameters that define the state-dependent distribution of observable variables.
The GM HMM for cross-sectional time series data is similar to the extension from Gaussian HMM to Gaussian HMM for cross-sectional time series data; for more information, see the section Gaussian Hidden Markov Model for Cross-Sectional Time Series Data.
Consider a bistate bi-component GM HMM that has the following parameter values. The ISPV and TPM are
At state 1, the two components have weights
and the mean and covariance parameters for two components are
At state 2, the two components have weights
and the mean and covariance parameters for two components are
The following statements simulate the bivariate vector time series from the previous model to provide test data for the HMM procedure:
%let a11 = 0.98;
%let a22 = 0.95;
%let c1_1 = 0.6;
%let c1_2 = 0.4;
%let c2_1 = 0.7;
%let c2_2 = 0.3;
%let mu1_1_1 = 1;
%let mu1_1_2 = 1;
%let mu1_2_1 = -3;
%let mu1_2_2 = -3;
%let sigma1_1_11 = 1;
%let sigma1_1_21 = 0;
%let sigma1_1_22 = 1;
%let sigma1_2_11 = 1.69;
%let sigma1_2_21 = 1;
%let sigma1_2_22 = 1.69;
%let mu2_1_1 = -1;
%let mu2_1_2 = -1;
%let mu2_2_1 = 3;
%let mu2_2_2 = 3;
%let sigma2_1_11 = 1;
%let sigma2_1_21 = 0;
%let sigma2_1_22 = 1;
%let sigma2_2_11 = 1.69;
%let sigma2_2_21 = 1;
%let sigma2_2_22 = 1.69;
%let seed = 1234;
%let T = 200000;
data gmDGP;
retain cd1_1_11 cd1_1_21 cd1_1_22
cd1_2_11 cd1_2_21 cd1_2_22
cd2_1_11 cd2_1_21 cd2_1_22
cd2_2_11 cd2_2_21 cd2_2_22;
do t = 1 to &T.;
if(t=1) then do;
* initial probability distribution;
p = (1-&a22.)/((1-&a11.)+(1-&a22.));;
* Cholesky decomposition;
cd1_1_11 = sqrt(&sigma1_1_11.);
cd1_1_21 = &sigma1_1_21./cd1_1_11;
cd1_1_22 = sqrt(&sigma1_1_22.-cd1_1_21*cd1_1_21);
cd1_2_11 = sqrt(&sigma1_2_11.);
cd1_2_21 = &sigma1_2_21./cd1_2_11;
cd1_2_22 = sqrt(&sigma1_2_22.-cd1_2_21*cd1_2_21);
cd2_1_11 = sqrt(&sigma2_1_11.);
cd2_1_21 = &sigma2_1_21./cd2_1_11;
cd2_1_22 = sqrt(&sigma2_1_22.-cd2_1_21*cd2_1_21);
cd2_2_11 = sqrt(&sigma2_2_11.);
cd2_2_21 = &sigma2_2_21./cd2_2_11;
cd2_2_22 = sqrt(&sigma2_2_22.-cd2_2_21*cd2_2_21);
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;
* choose component;
u = uniform(&seed.);
if(u<=&c1_1.) then do;
* (x,y) ~ N(mu, Sigma) at state 1, component 1;
x = &mu1_1_1. + cd1_1_11*e1;
y = &mu1_1_2. + cd1_1_21*e1+cd1_1_22*e2;
end;
else do;
* (x,y) ~ N(mu, Sigma) at state 1, component 2;
x = &mu1_2_1. + cd1_2_11*e1;
y = &mu1_2_2. + cd1_2_21*e1+cd1_2_22*e2;
end;
end;
else do;
* choose component;
u = uniform(&seed.);
if(u<=&c2_1.) then do;
* (x,y) ~ N(mu, Sigma) at state 2, component 1;
x = &mu2_1_1. + cd2_1_11*e1;
y = &mu2_1_2. + cd2_1_21*e1+cd2_1_22*e2;
end;
else do;
* (x,y) ~ N(mu, Sigma) at state 2, component 2;
x = &mu2_2_1. + cd2_2_11*e1;
y = &mu2_2_2. + cd2_2_21*e1+cd2_2_22*e2;
end;
end;
output;
lags = s;
end;
run;
data gmTrain;
set gmDGP(where=(t<=&T./2));
keep t x y;
run;
data gmTest;
set gmDGP(where=(t>&T./2));
keep t x y;
run;
In general, the data generating process is unknown. The data tables gmTrain and gmTest can be seen, but the data table gmDGP cannot be seen.
First, assume that the following statements plot the simulated series x that is contained in the data table gmTrain:
proc sgplot data=gmTrain;
series x=t y=x;
run;
Figure 22 shows the plot of x, whose points seem to fall randomly around 0.
Figure 22: Plot of Time Series x

The following statements plot the simulated series y that is contained in the data set gmTrain:
proc sgplot data=gmTrain;
series x=t y=y;
run;
Figure 23 shows the plot of y, whose points also seem to fall randomly around 0.
Figure 23: Plot of Time Series y

Ignoring the sequential information, the following statements plot the observed points that are contained in the data table
gmTrain:
proc sgplot data=gmTrain;
scatter y=y x=x;
run;
Figure 24: Unclassified Observations

As shown in Figure 24, it seems that all points come from one bivariate Gaussian distribution that has a high positive correlation. However, according to the true DGP, some points are from state 1, in which there are two clusters, as shown in Figure 25:
proc sgplot data=gmDGP(where=(t<=&T./2 and s=1));
scatter y=y x=x;
run;
Figure 25: Observations from State 1

Other points are from state 2 in which there are two clusters, as shown in Figure 26:
proc sgplot data=gmDGP(where=(t<=&T./2 and s=2));
scatter y=y x=x;
run;
Figure 26: Observations from State 2

Without considering the sequential order, it is impossible to distinguish the two states.
Before you estimate any model, you should make a copy of the data in the library, as in the following DATA steps:
data mylib.gmTrain; set gmTrain; run;
data mylib.gmTest; set gmTest; run;
The following statements estimate the bistate bi-component GM HMM. The type of model is specified in the TYPE= option in the MODEL statement. The number of states is specified in the NSTATE= option in the MODEL statement. The number of components for each state is specified in the NCOMPONENT= option in the MODEL statement. The OUTMODEL= option in the SCORE statement outputs the model information for future scoring on new data table. The LABELSWITCH=(SORT=NONE) option in the PROC HMM statement suppresses the relabeling of states and components; for more information about the label switching problem, see the section Label Switching Problem.
proc hmm data=mylib.gmTrain labelSwitch=(sort=none);
id time=t;
model x y / type=gaussianMixture nstate=2 ncomponent=2;
optimize printLevel=3 printIterFreq=1;
score outmodel=mylib.gmModel;
run;
These statements assume that your engine libref is named mylib, but you can substitute any appropriately defined engine libref.
The number of observations and model information are shown in Figure 27.
Figure 27: Number of Observations and Model Information
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 28.
Figure 28: Initial Parameter Values and Objective Function Value
| Optimization Start | |
|---|---|
| Parameter | Estimate |
| TPM1_1 | 0.500000 |
| TPM1_2 | 0.500000 |
| TPM2_1 | 0.500000 |
| TPM2_2 | 0.500000 |
| MCP1_1 | 0.500000 |
| MCP1_2 | 0.500000 |
| MCP2_1 | 0.500000 |
| MCP2_2 | 0.500000 |
| MU1_1_1 | 0.416654 |
| MU1_1_2 | 0.961871 |
| MU1_2_1 | -3.422684 |
| MU1_2_2 | -3.125473 |
| MU2_1_1 | 2.963828 |
| MU2_1_2 | 1.590644 |
| MU2_2_1 | -0.815362 |
| MU2_2_2 | -2.039325 |
| SIGMA1_1_1_1 | 1.354409 |
| SIGMA1_1_2_1 | 0.762768 |
| SIGMA1_1_2_2 | 1.393576 |
| SIGMA1_2_1_1 | 0.961355 |
| SIGMA1_2_2_1 | 0.661717 |
| SIGMA1_2_2_2 | 1.581451 |
| SIGMA2_1_1_1 | 1.025889 |
| SIGMA2_1_2_1 | 1.399630 |
| SIGMA2_1_2_2 | 2.884377 |
| SIGMA2_2_1_1 | 0.749535 |
| SIGMA2_2_2_1 | 0.265184 |
| SIGMA2_2_2_2 | 0.633097 |
| Initial Value of Objective Function | -401529.3793 |
|---|
The details of the optimization algorithm are shown in Figure 29.
Figure 29: Optimization Algorithm Details
| Algorithm Settings | |
|---|---|
| Maximum Number of Iterations | 128 |
| Tolerance for Optimality Error | 1E-6 |
| Tolerance for Infeasibility | 1E-6 |
| Maximum Allowed Time (seconds) | 1.797693E308 |
| Maximum Magnitude of Objective Function Value | 1E20 |
| Random Seed | 1 |
| Solution Type | 1 |
| Multi-Start Globalization Scheme | 0 |
| Multi-Start Globalization Bound Range | 2 |
The iterations of the optimization process are shown in Figure 30.
Figure 30: Iterations of the Optimization Process
| Iteration History | ||||||
|---|---|---|---|---|---|---|
| Iteration | Objective Function | Optimality Error | Infeasibility | Function Calls | Gradient Calls | Hessian Calls |
| 1 | -401529.3793 | 2887.16466 | 0.00000 | 2 | 1 | 0 |
| 2 | -389554.1158 | 2133.36152 | 0.00000 | 10 | 9 | 1 |
| 3 | -386179.6546 | 1199.52355 | 0.00000 | 19 | 18 | 2 |
| 4 | -371985.2011 | 848.19186 | 0.00000 | 29 | 28 | 3 |
| 5 | -367516.0600 | 249.88933 | 0.00000 | 38 | 37 | 4 |
| 6 | -366322.8416 | 161.33937 | 0.00000 | 49 | 48 | 5 |
| 7 | -365982.2352 | 46.74362 | 0.00000 | 59 | 58 | 6 |
| 8 | -365945.5123 | 5.29758 | 0.00000 | 69 | 68 | 7 |
| 9 | -365945.0948 | 0.06672 | 0.00000 | 79 | 78 | 8 |
| 10 | -365945.0946 | 0.00000 | 0.00000 | 89 | 88 | 9 |
The final parameter values and the objective function value at the end of the optimization are shown in Figure 31.
Figure 31: Final Parameter Values and Objective Function Value
| Optimization Results | |
|---|---|
| Parameter | Estimate |
| TPM1_1 | 0.979636 |
| TPM1_2 | 0.020364 |
| TPM2_1 | 0.049729 |
| TPM2_2 | 0.950271 |
| MCP1_1 | 0.600332 |
| MCP1_2 | 0.399668 |
| MCP2_1 | 0.297811 |
| MCP2_2 | 0.702189 |
| MU1_1_1 | 0.993524 |
| MU1_1_2 | 0.996707 |
| MU1_2_1 | -3.003906 |
| MU1_2_2 | -3.005379 |
| MU2_1_1 | 3.005306 |
| MU2_1_2 | 3.009691 |
| MU2_2_1 | -0.997604 |
| MU2_2_2 | -1.005076 |
| SIGMA1_1_1_1 | 1.000305 |
| SIGMA1_1_2_1 | 0.007588 |
| SIGMA1_1_2_2 | 1.003672 |
| SIGMA1_2_1_1 | 1.704270 |
| SIGMA1_2_2_1 | 1.003413 |
| SIGMA1_2_2_2 | 1.688212 |
| SIGMA2_1_1_1 | 1.712932 |
| SIGMA2_1_2_1 | 1.014865 |
| SIGMA2_1_2_2 | 1.704181 |
| SIGMA2_2_1_1 | 1.015895 |
| SIGMA2_2_2_1 | 0.012899 |
| SIGMA2_2_2_2 | 1.006142 |
| Final Value of Objective Function | -365945.0946 |
|---|
The estimates of the initial state probability vector (ISPV) are shown in Figure 32.
Figure 32: Estimates of Initial State Probability Vector
| Initial State Probabilities | |
|---|---|
| State | Estimation |
| 1 | 0.70947 |
| 2 | 0.29053 |
The estimates of the transition probability matrix (TPM) are shown in Figure 33.
Figure 33: Estimates of Transition Probability Matrix
| Estimated Transition Probability Matrix | ||
|---|---|---|
| State | 1 | 2 |
| 1 | 0.97964 | 0.02036 |
| 2 | 0.04973 | 0.95027 |
The estimates of the mixture component probabilities (MCP) are shown in Figure 34.
Figure 34: Estimates of Mixture Component Probabilities
| Estimated Mixture Component Probabilities | ||
|---|---|---|
| State | Component | |
| 1 | 2 | |
| 1 | 0.60033 | 0.39967 |
| 2 | 0.29781 | 0.70219 |
The estimates of the mean vector of the Gaussian distribution for each component at each state are shown in Figure 35.
Figure 35: Estimate of Mean Vector for Each Component at Each State
| Mu | |||
|---|---|---|---|
| State | Component | x | y |
| 1 | 1 | 0.99352 | 0.99671 |
| 2 | -3.00391 | -3.00538 | |
| 2 | 1 | 3.00531 | 3.00969 |
| 2 | -0.99760 | -1.00508 | |
The estimates of the covariance matrix of the Gaussian distribution for each component at each state are shown in Figure 36.
Figure 36: Estimate of Covariance Matrix for Each Component at Each State
| Sigma | ||||
|---|---|---|---|---|
| State | Component | Variable | x | y |
| 1 | 1 | x | 1.00031 | 0.00759 |
| 1 | y | 0.00759 | 1.00367 | |
| 2 | x | 1.70427 | 1.00341 | |
| 2 | y | 1.00341 | 1.68821 | |
| 2 | 1 | x | 1.71293 | 1.01486 |
| 1 | y | 1.01486 | 1.70418 | |
| 2 | x | 1.01589 | 0.01290 | |
| 2 | y | 0.01290 | 1.00614 | |
The estimates of all parameters are shown in Figure 37, which displays columns for the parameter name, estimate value, standard error, t value, and p-value. The state labels ("1" and "2" in this example) and the component labels ("1" and "2" in this example) might exchange randomly, compared to the true DGP. In the preceding estimation, the state labels are the same as the labels in the DGP. The component labels for state 1 are also the same as the ones in the DGP, but the component labels for state 2 do exchange! Compared to the parameter values in the DGP, the estimates are very accurate.
Figure 37: Parameter Estimates
| Parameter Estimates | ||||
|---|---|---|---|---|
| Parameter | Estimate | Standard Error | t Value | Pr > |t| |
| TPM1_1 | 0.979636 | 0.000600 | 1632.32 | <.0001 |
| TPM1_2 | 0.020364 | 0.000600 | 33.93 | <.0001 |
| TPM2_1 | 0.049729 | 0.001422 | 34.98 | <.0001 |
| TPM2_2 | 0.950271 | 0.001422 | 668.37 | <.0001 |
| MCP1_1 | 0.600332 | 0.001987 | 302.17 | <.0001 |
| MCP1_2 | 0.399668 | 0.001987 | 201.17 | <.0001 |
| MCP2_1 | 0.297811 | 0.002966 | 100.42 | <.0001 |
| MCP2_2 | 0.702189 | 0.002966 | 236.78 | <.0001 |
| MU1_1_1 | 0.993524 | 0.005202 | 191.00 | <.0001 |
| MU1_1_2 | 0.996707 | 0.005225 | 190.77 | <.0001 |
| MU1_2_1 | -3.003906 | 0.009259 | -324.43 | <.0001 |
| MU1_2_2 | -3.005379 | 0.009199 | -326.71 | <.0001 |
| MU2_1_1 | 3.005306 | 0.017586 | 170.89 | <.0001 |
| MU2_1_2 | 3.009691 | 0.017492 | 172.06 | <.0001 |
| MU2_2_1 | -0.997604 | 0.007672 | -130.04 | <.0001 |
| MU2_2_2 | -1.005076 | 0.007645 | -131.47 | <.0001 |
| SIGMA1_1_1_1 | 1.000305 | 0.007559 | 132.33 | <.0001 |
| SIGMA1_1_2_1 | 0.007588 | 0.005615 | 1.35 | 0.1765 |
| SIGMA1_1_2_2 | 1.003672 | 0.007625 | 131.63 | <.0001 |
| SIGMA1_2_1_1 | 1.704270 | 0.018040 | 94.47 | <.0001 |
| SIGMA1_2_2_1 | 1.003413 | 0.015372 | 65.27 | <.0001 |
| SIGMA1_2_2_2 | 1.688212 | 0.017808 | 94.80 | <.0001 |
| SIGMA2_1_1_1 | 1.712932 | 0.033960 | 50.44 | <.0001 |
| SIGMA2_1_2_1 | 1.014865 | 0.028939 | 35.07 | <.0001 |
| SIGMA2_1_2_2 | 1.704181 | 0.033648 | 50.65 | <.0001 |
| SIGMA2_2_1_1 | 1.015895 | 0.011295 | 89.94 | <.0001 |
| SIGMA2_2_2_1 | 0.012899 | 0.008289 | 1.56 | 0.1197 |
| SIGMA2_2_2_2 | 1.006142 | 0.011248 | 89.45 | <.0001 |
The log likelihood and information criteria are shown in Figure 38.
Figure 38: Log Likelihood and Information Criteria
| Fit Statistics | |
|---|---|
| Log Likelihood | -365945.0946 |
| AIC | 731942.18929 |
| AICC | 731942.20333 |
| BIC | 732189.52535 |
| HQC | 732017.24975 |
The estimates from the data table gmTrain are used to score the testing data table gmTest to check the predictability in the following statements:
proc hmm data=mylib.gmTest;
score inmodel=mylib.gmModel;
decode out=mylib.gmDecode;
run;
The accuracy of classification through the GM HMM is calculated by the following statements:
data gmHmmCheck;
merge gmDGP(in=a where=(t>&T./2)) mylib.gmDecode(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 gmHmmAccuracy;
set gmHmmCheck;
retain count 0 correctCount 0;
count = count + 1;
correctCount = correctCount + correct;
if(count>&T./2-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 gmHmmCheck;
set gmHmmCheck;
if(&qFlipState.=1) then do;
ds = -ds;
correct = 1 - correct;
end;
run;
proc print data = gmHmmAccuracy noobs; run;
The accuracy of the GM HMM, which is shown in Figure 39, is about 98%. This means that the GM HMM successfully takes advantage of the sequential information.
Figure 39: Accuracy of Decoding by the GM HMM
| accuracy |
|---|
| 0.97835 |
Now, consider the GM HMM for cross-sectional time series data. Each section’s data follow the same GM HMM as described previously. The following statements generate the data table for analysis. There are 200 sections in the data table, and each section of time series consist of 1,000 observations.
%let a11 = 0.98;
%let a22 = 0.95;
%let c1_1 = 0.6;
%let c1_2 = 0.4;
%let c2_1 = 0.7;
%let c2_2 = 0.3;
%let mu1_1_1 = 1;
%let mu1_1_2 = 1;
%let mu1_2_1 = -3;
%let mu1_2_2 = -3;
%let sigma1_1_11 = 1;
%let sigma1_1_21 = 0;
%let sigma1_1_22 = 1;
%let sigma1_2_11 = 1.69;
%let sigma1_2_21 = 1;
%let sigma1_2_22 = 1.69;
%let mu2_1_1 = -1;
%let mu2_1_2 = -1;
%let mu2_2_1 = 3;
%let mu2_2_2 = 3;
%let sigma2_1_11 = 1;
%let sigma2_1_21 = 0;
%let sigma2_1_22 = 1;
%let sigma2_2_11 = 1.69;
%let sigma2_2_21 = 1;
%let sigma2_2_22 = 1.69;
%let seed = 1234;
%let T = 200000;
%let nSections = 200;
data gmDGP;
retain cd1_1_11 cd1_1_21 cd1_1_22
cd1_2_11 cd1_2_21 cd1_2_22
cd2_1_11 cd2_1_21 cd2_1_22
cd2_2_11 cd2_2_21 cd2_2_22;
do t = 1 to &T.;
sec = ceil(t*&nSections./&T.);
if(t=1) then do;
* initial probability distribution;
p = (1-&a22.)/((1-&a11.)+(1-&a22.));;
* Cholesky decomposition;
cd1_1_11 = sqrt(&sigma1_1_11.);
cd1_1_21 = &sigma1_1_21./cd1_1_11;
cd1_1_22 = sqrt(&sigma1_1_22.-cd1_1_21*cd1_1_21);
cd1_2_11 = sqrt(&sigma1_2_11.);
cd1_2_21 = &sigma1_2_21./cd1_2_11;
cd1_2_22 = sqrt(&sigma1_2_22.-cd1_2_21*cd1_2_21);
cd2_1_11 = sqrt(&sigma2_1_11.);
cd2_1_21 = &sigma2_1_21./cd2_1_11;
cd2_1_22 = sqrt(&sigma2_1_22.-cd2_1_21*cd2_1_21);
cd2_2_11 = sqrt(&sigma2_2_11.);
cd2_2_21 = &sigma2_2_21./cd2_2_11;
cd2_2_22 = sqrt(&sigma2_2_22.-cd2_2_21*cd2_2_21);
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;
* choose component;
u = uniform(&seed.);
if(u<=&c1_1.) then do;
* (x,y) ~ N(mu, Sigma) at state 1, component 1;
x = &mu1_1_1. + cd1_1_11*e1;
y = &mu1_1_2. + cd1_1_21*e1+cd1_1_22*e2;
end;
else do;
* (x,y) ~ N(mu, Sigma) at state 1, component 2;
x = &mu1_2_1. + cd1_2_11*e1;
y = &mu1_2_2. + cd1_2_21*e1+cd1_2_22*e2;
end;
end;
else do;
* choose component;
u = uniform(&seed.);
if(u<=&c2_1.) then do;
* (x,y) ~ N(mu, Sigma) at state 2, component 1;
x = &mu2_1_1. + cd2_1_11*e1;
y = &mu2_1_2. + cd2_1_21*e1+cd2_1_22*e2;
end;
else do;
* (x,y) ~ N(mu, Sigma) at state 2, component 2;
x = &mu2_2_1. + cd2_2_11*e1;
y = &mu2_2_2. + cd2_2_21*e1+cd2_2_22*e2;
end;
end;
output;
lags = s;
end;
run;
data gmTrain;
set gmDGP(where=(sec<=&nSections./2));
keep sec t x y;
run;
data gmTest;
set gmDGP(where=(sec>&nSections./2));
keep sec t x y;
run;
The following statements estimate the GM HMM for the cross-sectional time series data after making the copies of the data tables in the library. The SECTION= option in the ID statement requests that the cross-sectional time series data be analyzed.
data mylib.gmTrain; set gmTrain; run;
data mylib.gmTest; set gmTest; run;
proc hmm data=mylib.gmTrain labelSwitch=(sort=none);
id time=t section=sec;
model x y / type=gaussianMixture nstate=2 ncomponent=2;
optimize printLevel=3 printIterFreq=1;
score outmodel=mylib.gmModel;
filter out=mylib.gmFilter;
evaluate out=mylib.gmEval;
run;
The model information is shown in Figure 40. There are 100 sections in the data.
Figure 40: Model Information
| Model Information | |
|---|---|
| Type of Model | Gaussian Mixture HMM |
| Stationary | Yes |
| Number of States | 2 |
| Number of Components for a State | 2 |
| Number of Dependent Variables | 2 |
| Number of Sections | 100 |
The estimates of all parameters are shown in Figure 41; the estimates are very close to the parameter values in the DGP.
Figure 41: Parameter Estimates
| Parameter Estimates | ||||
|---|---|---|---|---|
| Parameter | Estimate | Standard Error | t Value | Pr > |t| |
| TPM1_1 | 0.979697 | 0.000598 | 1639.23 | <.0001 |
| TPM1_2 | 0.020303 | 0.000598 | 33.97 | <.0001 |
| TPM2_1 | 0.049991 | 0.001419 | 35.23 | <.0001 |
| TPM2_2 | 0.950009 | 0.001419 | 669.51 | <.0001 |
| MCP1_1 | 0.600330 | 0.001987 | 302.13 | <.0001 |
| MCP1_2 | 0.399670 | 0.001987 | 201.15 | <.0001 |
| MCP2_1 | 0.297864 | 0.002966 | 100.41 | <.0001 |
| MCP2_2 | 0.702136 | 0.002966 | 236.70 | <.0001 |
| MU1_1_1 | 0.993469 | 0.005202 | 190.97 | <.0001 |
| MU1_1_2 | 0.996750 | 0.005224 | 190.80 | <.0001 |
| MU1_2_1 | -3.004280 | 0.009259 | -324.45 | <.0001 |
| MU1_2_2 | -3.005705 | 0.009202 | -326.64 | <.0001 |
| MU2_1_1 | 3.004517 | 0.017596 | 170.75 | <.0001 |
| MU2_1_2 | 3.008912 | 0.017510 | 171.84 | <.0001 |
| MU2_2_1 | -0.997409 | 0.007674 | -129.97 | <.0001 |
| MU2_2_2 | -1.005153 | 0.007644 | -131.50 | <.0001 |
| SIGMA1_1_1_1 | 1.000332 | 0.007560 | 132.32 | <.0001 |
| SIGMA1_1_2_1 | 0.007321 | 0.005614 | 1.30 | 0.1922 |
| SIGMA1_1_2_2 | 1.003283 | 0.007624 | 131.60 | <.0001 |
| SIGMA1_2_1_1 | 1.703717 | 0.018034 | 94.47 | <.0001 |
| SIGMA1_2_2_1 | 1.002882 | 0.015368 | 65.26 | <.0001 |
| SIGMA1_2_2_2 | 1.687759 | 0.017806 | 94.78 | <.0001 |
| SIGMA2_1_1_1 | 1.713186 | 0.033969 | 50.43 | <.0001 |
| SIGMA2_1_2_1 | 1.015588 | 0.028964 | 35.06 | <.0001 |
| SIGMA2_1_2_2 | 1.705412 | 0.033689 | 50.62 | <.0001 |
| SIGMA2_2_1_1 | 1.015835 | 0.011301 | 89.89 | <.0001 |
| SIGMA2_2_2_1 | 0.012931 | 0.008291 | 1.56 | 0.1188 |
| SIGMA2_2_2_2 | 1.005816 | 0.011243 | 89.46 | <.0001 |
You can apply the estimates from the data table gmTrain to the testing data table gmTest to check the predictability in the following statements:
proc hmm data=mylib.gmTest;
score inmodel=mylib.gmModel;
decode out=mylib.gmDecode;
filter out=mylib.gmFilter2;
evaluate out=mylib.gmEval2;
run;
data gmHmmCheck;
merge gmDGP(in=a where=(sec>&nSections./2)) mylib.gmDecode(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 sec t x y s correct ds;
run;
%let qFlipState = -1;
data gmHmmAccuracy;
set gmHmmCheck;
retain count 0 correctCount 0;
count = count + 1;
correctCount = correctCount + correct;
if(count>&T./2-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 gmHmmCheck;
set gmHmmCheck;
if(&qFlipState.=1) then do;
ds = -ds;
correct = 1 - correct;
end;
run;
proc print data = gmHmmAccuracy noobs; run;
The accuracy of the GM HMM for cross-sectional time series data, which is shown in Figure 42, is also around 98%.
Figure 42: Accuracy of Decoding by the GM HMM for Cross-Sectional Time Series Data
| accuracy |
|---|
| 0.97827 |