Skip to content
Numerical Method , home
Menu

Forum Applications Trading Strategies (Algo Quant)

HMM Error for training the model

  1. RyuParticipant January 20, 2012 at 7:13 am

    Hi,

    I am training a HMM with SuanShu but once it got errors in some cases. I tried a few different settings but the errors still occurred. Let me summarize how the error occurs.

    Set HMM with 3 states with 5 discrete values in the emission probability at each state. Then I randomized a matrix A of size 3 x 3 and matrix B of size 3 x 5. Now I also get 100 observations, where the first 99 values are between 1 and 4, and the 100th value is 5. Then it runs out an infinite value matrices A and B. I suspect the issue is due to that the training algorithm finds that the value 5 cannot be found from the previous occurrences and cannot determine the probability of the model at value 5 in observation. For more details, you can refer to the following .java.

    Is it an algorithmic issue or something would be fixed? Thanks.

    Main Program:

    <br />
    package com.numericalmethod.suanshu.examples;<br />
    import com.numericalmethod.suanshu.matrix.doubles.Matrix;<br />
    import com.numericalmethod.suanshu.stats.hmm.rabiner.HmmTrainByEM;<br />
    import com.numericalmethod.suanshu.stats.hmm.rabiner.HiddenMarkovModel;<br />
    import com.numericalmethod.suanshu.matrix.doubles.matrixtype.dense.DenseMatrix;<br />
    import com.numericalmethod.suanshu.vector.doubles.dense.DenseVector;<br />
    import org.junit.Test;<br />
    import java.io.*;<br />
    import java.util.*;<br />
    <br />
    /**<br />
    *<br />
    * @author Chan<br />
    */<br />
    <br />
    <br />
    public class Test_HMM_20120120 {<br />
            public static void main( String args[]) {     <br />
            org.junit.runner.JUnitCore.main("com.numericalmethod.suanshu.examples.Test_HMM_20120120");<br />
        }<br />
        @Test<br />
        public void test_0010(){<br />
            // Initialization<br />
            double ThresholdValue = 0.500;                                          //Input 1<br />
            int[] ActiveCol = {1, 2, 3};                                            //Input 2<br />
            int number_row_a = 3, number_col_a = number_row_a;                      //Input 3<br />
            int NumberofTotalCol = 5;                                               //Input 4<br />
            int number_row_b = number_row_a, number_col_b = ActiveCol.length*2-1;<br />
            int WinSize = 100;               <br />
            int nTraining = 10;<br />
            DenseVector PI_0 = new DenseVector(MarkovModel_pre_20120119.GenerateRandomMatrix(1, number_row_a).t());       <br />
            DenseMatrix A_0 = new DenseMatrix(MarkovModel_pre_20120119.GenerateRandomMatrix(number_row_a, number_col_a));<br />
            DenseMatrix B_0 = new DenseMatrix(MarkovModel_pre_20120119.GenerateRandomMatrix(number_row_b, number_col_b));           <br />
            HiddenMarkovModel model_0 = new HiddenMarkovModel(PI_0, A_0, B_0);<br />
           <br />
            DenseVector Obs = new DenseVector(MarkovModel_pre_20120119.GenerateRandomMatrix(1, WinSize).t());<br />
            System.out.print(Obs.toString());<br />
            int[] TempArray = new int[WinSize+1];<br />
            for (int i = 0; i<winsize ; i++){           <br></winsize>
                if (Obs.get(i+1)&lt;0.25/WinSize)<br />
                    TempArray<i> = 1;<br />
                else if (Obs.get(i+1)>=0.25/WinSize &#038;&#038; Obs.get(i+1)&lt;0.5/WinSize)<br />
                    TempArray</i><i> = 2;<br />
                else if (Obs.get(i+1)>=0.5/WinSize &#038;&#038; Obs.get(i+1)&lt;0.75/WinSize)<br />
                    TempArray</i><i> = 3;<br />
                else<br />
                    TempArray</i><i> = 4;<br />
                System.out.println(TempArray</i><i>);<br />
            }<br />
           <br />
            TempArray[WinSize] = 4;<br />
            for (int k=0; k<ntraining ; k++)                                //train nTraining times<br></ntraining>
                model_0 = new HmmTrainByEM().train(model_0, TempArray);<br />
           <br />
            System.out.println(model_0.A().toString()); <br />
            System.out.println(model_0.B().toString());<br />
        }<br />
    }<br />
    <br />
    </i>
    

    It depends to another .java with method GenerateRandomMatrix from class MarkovModel_pre_20120119. Just copy it in another .java and use it in the main program. Method GenerateRandomMatrix is to generate random matrices.

    <br />
    <br />
    package com.numericalmethod.suanshu.examples;<br />
    <br />
    import com.numericalmethod.suanshu.matrix.doubles.Matrix;<br />
    import com.numericalmethod.suanshu.matrix.doubles.matrixtype.dense.DenseMatrix;<br />
    import java.util.*;<br />
    import java.io.*;<br />
    <br />
    /**<br />
    *<br />
    * @author Chan<br />
    */<br />
    <br />
    <br />
    public class MarkovModel_pre_20120119 {<br />
        public static void main(String args[]) {<br />
            // Test out the functions<br />
            //Matrix A = new DenseMatrix(GetObservationState(readData("C:\text.txt", 2, 100), 0.005));             <br />
            //System.out.println(A.toString());       <br />
        }<br />
       <br />
       <br />
        public static DenseMatrix readData(String FilePath, int ColSize, int WinSize, int[] ActiveCol)<br />
          {<br />
             <br />
              // Col1 = Date; Col2 = Closed price; Col3 = Return;<br />
              DenseMatrix temp_Data = new DenseMatrix(new double[1000][ActiveCol.length +1]);<br />
              // Col1 = Date; Col2 = Closed price; Col3 = Normalized return;<br />
              DenseMatrix output_Data = new DenseMatrix(new double [1000][ActiveCol.length +1]);<br />
    <br />
             <br />
              try{<br />
                  // Open the file that is the first<br />
                  // command line parameter<br />
                  FileInputStream fstream = new FileInputStream(FilePath);<br />
                 <br />
                  // Get the object of DataInputStream<br />
                  DataInputStream in = new DataInputStream(fstream);<br />
                  BufferedReader br = new BufferedReader(new InputStreamReader(in));<br />
                  String strLine;<br />
                  //Read File Line By Line<br />
                  int i =1;<br />
                  strLine = br.readLine();<br />
                  while ((strLine = br.readLine()) != null &#038;&#038; i < = 1000)   {                 <br />
                      // Input the first col and second col to date and close price<br />
                      int colCount = 1;<br />
                      for (int col = 1; col < = ColSize; col++)<br />
                      {                                                                 <br />
                          for (int ActiveColn = 1; ActiveColn< =ActiveCol.length; ActiveColn++)<br />
                              if (col == ActiveCol[ActiveColn-1]){                           <br />
                                temp_Data.set(i, colCount++, Double.parseDouble(strLine.split(",")[col-1])) ;                     <br />
                                break;<br />
                          }<br />
                      }<br />
                      i++;<br />
                    }<br />
                  //Close the input stream<br />
                  in.close();<br />
                }catch (Exception e){//Catch exception if any<br />
                        System.err.println("Error: " + e.getMessage());<br />
              }<br />
             <br />
              // Calculate the return, the first one return cannot be calculated<br />
                for (int i = 1000; i>=2; i--){<br />
                    if (temp_Data.get(i, 1)>0)<br />
                        for (int col=ActiveCol.length +1; col >=3 ;col--)<br />
                            temp_Data.set(i, col, (temp_Data.get(i, col-1)-temp_Data.get(i-1, col-1))/temp_Data.get(i-1, col-1));<br />
                }<br />
    <br />
                // Assign date and price<br />
                for (int i = 1000; i>WinSize; i-- ){               <br />
                    output_Data.set(i-WinSize, 1, temp_Data.get(i, 1));<br />
                    output_Data.set(i-WinSize, 2, temp_Data.get(i, 2));<br />
                }<br />
               <br />
                // Assign all the observations<br />
                for (int col = 3; col< =ActiveCol.length +1; col++)<br />
                {<br />
                    for (int i = 1000; i>WinSize; i-- ){<br />
                        double mean = 0, variance = 0;<br />
                        for (int j = 0; i<winsize ; j++)<br></winsize>
                            mean+=temp_Data.get(i-j, 3);                   <br />
                        mean = mean/WinSize;<br />
    <br />
                        for (int j = 0; j<winsize ; j++)<br></winsize>
                            variance+=(temp_Data.get(i-j, 3)-mean)*(temp_Data.get(i-j, 3)-mean);                   <br />
                        variance = variance/WinSize;<br />
                        output_Data.set(i-WinSize, col, (temp_Data.get(i,col)-mean)/Math.sqrt(variance));<br />
                    }<br />
                }<br />
              return output_Data;<br />
          }<br />
       <br />
        public static DenseMatrix GetObservationState(DenseMatrix Obser, double Threshold)<br />
        {<br />
            // Find out the size of a non-zero submatrix of Obser<br />
            int NonZeroRowSize = 0;<br />
            for (int i = 1; i < = Obser.nRows(); i++)<br />
                if (Obser.get(i,1)>0) NonZeroRowSize++;<br />
           <br />
            DenseMatrix output_GetObser = new DenseMatrix (new double[NonZeroRowSize][Obser.nCols()]);<br />
            for (int i = 1; i< =NonZeroRowSize; i++)<br />
            {<br />
                    // Assign Date<br />
                    output_GetObser.set(i, 1, Obser.get(i, 1));<br />
                    // Assign Price<br />
                    output_GetObser.set(i, 2, Obser.get(i, 2));<br />
                    // Assign state<br />
                    for (int col = 3; col < = Obser.nCols(); col++)<br />
                    {<br />
                        if (Obser.get(i, col)< (-1)*Threshold)<br />
                            output_GetObser.set(i, col, 1);<br />
                        else if (Obser.get(i, col)> Threshold)<br />
                            output_GetObser.set(i, col, 3);<br />
                        else<br />
                            output_GetObser.set(i, col, 2);<br />
                    }<br />
               <br />
            }<br />
           <br />
            return GenerateObservationValue(output_GetObser);<br />
        }<br />
    <br />
       <br />
    // It generate the state by the weighted average of observation state (default factors 1)<br />
    // If the observation<i> = {1, 2, 3, 3, 2}, then translate it to {-1, 0, 1, 1, 0}<br />
    // Add all those observation value. Max value = Size; Min Value = -Size<br />
        public static DenseMatrix GenerateObservationValue(DenseMatrix output_GetObser)<br />
        {<br />
            DenseMatrix OutMx = new DenseMatrix(new double [output_GetObser.nRows()][3]);<br />
            for (int row = 1; row< =output_GetObser.nRows(); row ++)<br />
            {<br />
                int SumObservation = 0;<br />
                for (int col = 3; col < = output_GetObser.nCols(); col++)<br />
                    SumObservation += output_GetObser.get(row, col);<br />
                // Consider there are two observations, min_value = 2 and max_value = 6<br />
                // We need to transfer it to observation values from 1 to 5<br />
                OutMx.set(row, 1, output_GetObser.get(row, 1));<br />
                OutMx.set(row, 2, output_GetObser.get(row, 2));<br />
                OutMx.set(row, 3, SumObservation-(output_GetObser.nCols()-3));<br />
            }       <br />
            return OutMx;<br />
        }<br />
       <br />
        // Return a random matrix<br />
        public static DenseMatrix GenerateRandomMatrix(int rowsize, int colsize){<br />
            Random generator = new Random();<br />
    <br />
            double r1 = generator.nextDouble();<br />
            double r2 = generator.nextDouble();<br />
            double sum = r1 + r2;<br />
            r1 = r1/sum;<br />
            r2 = r2/sum;               <br />
            double sum_a;       <br />
           <br />
            DenseMatrix ResultMatrix = new DenseMatrix(new double[rowsize][colsize]);<br />
            double[] r_a = new double[colsize+1];<br />
           <br />
           <br />
            for ( int j = 1; j< =rowsize;j++){<br />
                sum_a =0;<br />
                for (int i=1;i< =colsize;i++){<br />
                    r_a</i><i> = generator.nextDouble();<br />
                    sum_a = r_a</i><i> + sum_a;<br />
                }<br />
                for (int i=1;i< =colsize;i++){<br />
                   r_a</i><i> = r_a</i><i>/sum_a;<br />
                }<br />
                for ( int k = 1;k< = colsize;k++){<br />
                    ResultMatrix.set(j, k, r_a[k]);<br />
                }<br />
            }<br />
            return ResultMatrix;<br />
        }<br />
    }<br />
    </i>