VB NMF Example

← All NMath Stats Code Examples

 

Imports System
Imports System.Text
Imports System.Collections.Generic

Imports CenterSpace.NMath.Core
Imports CenterSpace.NMath.Stats
Imports System.IO

Namespace CenterSpace.NMath.Stats.Examples.VisualBasic

  ' A .NET example in Visual Basic illustrating Non-negative Matrix Factorization (NMF)
  Module NMFExample

    Sub Main()
      ' Load the example data into a DataFrame
      Dim Frame As DataFrame = DataFrame.Load("NMFExample.dat", False, False, ",", True)

      ' Construct a Nonnegative Matrix Factorization object that will perform 200
      ' iterations when computing the factors.
      Dim Fact As NMFact = New NMFact(200)

      ' Now, perform the factorization data = WH Imports the the default initial
      ' initial values for WH (which are uniform random in (0, 1) ), the default
      ' update algorithm (NMFMultiplicativeUpdate) and k = 2.
      Fact.Factor(Frame, 2)

      ' Look at the results. Note that since the initial values for W and H are
      ' random, the results will not be exactly the same on each run of the
      ' program.
      Console.WriteLine()
      Console.WriteLine("Output 0, Default initial W, H, and algorithm -----------------")
      PrintResults(Fact)
      ' Note that the values of W and H are not close to the expected values

      ' Set up some initial values for W and H so we can play with some of the 
      ' factorizations parameters and observe the effects without the random
      ' variations induced by random initial values.
      Dim RNG As RandGenUniform = New RandGenUniform(124)
      Dim initialW As DoubleMatrix = New DoubleMatrix(3, 2, RNG)
      Dim initialH As New DoubleMatrix(2, 4, RNG)

      ' Factor and print the results
      Fact.Factor(Frame, 2, initialW, initialH)
      Console.WriteLine()
      Console.WriteLine()
      Console.WriteLine("Output 1 -------------------------------------------------------")
      PrintResults(Fact)

      ' Note that the factorization is pretty darn good - the cost function 
      ' is on the order of 10e-18 and the difference of the elements of WH
      ' and V are all on the order of 10e-9 or 10e-10. But we are not close
      ' to the expected results. This shows the non-uniqueness of NMF 
      ' solutions. Let's up the number of iterations to, say, 1000 and see
      ' if our factorization improves:
      Fact.NumIterations = 1000
      initialW = New DoubleMatrix(3, 2, RNG)
      initialH = New DoubleMatrix(2, 4, RNG)
      Fact.Factor(Frame, 2, initialW, initialH)
      Console.WriteLine()
      Console.WriteLine()
      Console.WriteLine("Output 2, 1000 iterations ----------------------------------")
      PrintResults(Fact)

      ' Cost goes way down, all the elements of V - WH are 0 or on the order
      ' of 10e-15 - that's basically 0 within the limits of a double precision
      ' number (15 significant digits). Within machine precision, the 
      ' factorization is exact and the solution is definitely a local minimum
      ' of the function ||V - WH||. Let's try and make it converge to the 
      ' expected solution by setting the initial values very close to the 
      ' expected values.
      initialW = New DoubleMatrix("3x2[1 5  2 1  3 4]")
      initialW = initialW + 0.01
      initialH = New DoubleMatrix("2x4[1 4 3 2  8 1 2 7]")
      initialH = initialH - 0.01
      Fact.Factor(Frame, 2, initialW, initialH)
      Console.WriteLine()
      Console.WriteLine()
      Console.WriteLine("Output 3, initial W, H close to expected values --------------------")
      PrintResults(Fact)

      ' Wow. We still converge to the same solution as before. That solution
      ' must be a very strong attractor for this algorithm. Let's try a 
      ' different algorithm. The GD-CLS algorithm uses the multiplicative
      ' method, which is basically a version of the gradient descent (GD) 
      ' optimization scheme, to approximate the basis vector matrix W. H
      ' is calculated Imports a constrained least squares (CLS).
      Fact.UpdateAlgorithm = New NMFGdClsUpdate()
      Dim delta As Double = 0.01
      initialW = New DoubleMatrix("3x2[1 5  2 1  3 4]")
      initialW = initialW + delta
      initialH = New DoubleMatrix("2x4[1 4 3 2  8 1 2 7]")
      initialH = initialH + delta
      Fact.Factor(Frame, 2, initialW, initialH)
      Console.WriteLine()
      Console.WriteLine()
      Console.WriteLine("Output 4, GD-CLS algorithm initial W, H close to expected values -----")
      PrintResults(Fact)

      ' Now, that's more like it. We can find the expected solution if we 
      ' out right on top of it.

      Console.WriteLine()
      Console.WriteLine("Press Enter Key")
      Console.Read()
    End Sub

    Sub PrintResults(ByVal Fact As NMFact)
      ' Matrices rounded for better legibility

      ' Look at the results:
      Console.WriteLine()
      Console.WriteLine("Factored Matrix: ")
      Console.WriteLine(Fact.V.ToTabDelimited("G5"))
      Console.WriteLine()
      Console.WriteLine("W: ")
      Console.WriteLine(Fact.W.ToTabDelimited("G5"))
      Console.WriteLine()
      Console.WriteLine("H: ")
      Console.WriteLine(Fact.H.ToTabDelimited("G5"))
      Console.WriteLine()
      Console.WriteLine("Cost (error) = " & Fact.Cost)

      ' Look at the product of the factors and the difference from
      ' the factored matrix V
      Dim WH As DoubleMatrix = NMathFunctions.Product(Fact.W, Fact.H)
      Dim D As DoubleMatrix = Fact.V - WH
      Console.WriteLine()
      Console.WriteLine("WH = ")
      Console.WriteLine(WH.ToTabDelimited("G5"))
      Console.WriteLine()
      Console.WriteLine("V - WH = ")
      Console.WriteLine(D.ToTabDelimited("G5"))
      Console.WriteLine()

    End Sub
  End Module
End Namespace

← All NMath Stats Code Examples
Top