2

So I have verified that the starting version of what I'm trying to do works, but for some reason when putting it into the Matrix.map high order function it breaks down.

Here is the failing function:

let SumSquares (theta:Vector<float>) (y:Vector<float>) (trainingData:Matrix<float>) =
    let m = trainingData.RowCount
    let theta' = theta.ToRowMatrix()
    trainingData     
    |> Matrix.mapRows(fun a r -> (theta' * r) - y.[a] )

Here are some sample tests

Set up:

let tData = matrix [[1.0; 2.0]
                    [1.0; 3.0]
                    [1.0; 3.0]
                    [1.0; 4.0]]   
let yVals = vector [5.0; 6.0; 7.0; 11.0]      
let theta = vector [1.0; 0.2]  

Test raw functionality of basic operation (theta transpose * vector - actual)

let theta' = theta.ToRowMatrix()
(theta.ToRowMatrix() * tData.[0, 0 .. 1]) - yVals.[0]

Testing in actual function:

tData |> SumSquares theta yVals

Here is a copy/paste of actual error. It reads as though its having issues of me mapping a larger vector to a smaller vector.

Parameter name: target

at MathNet.Numerics.LinearAlgebra.Storage.VectorStorage1.CopyToRow(MatrixStorage1 target, Int32 rowIndex, ExistingData existingData)
at FSI_0061.SumSquares(Vector1 theta, Vector1 y, Matrix`1 trainingData) in C:\projects\deleteme\ASPNet5Test\ConsoleApplication1\ConsoleApplication1\MachineLearning.fsx:line 23
at .$FSI_0084.main@() in C:\projects\deleteme\ASPNet5Test\ConsoleApplication1\ConsoleApplication1\MachineLearning.fsx:line 39
Stopped due to error

TylerH
  • 20,799
  • 66
  • 75
  • 101
David Crook
  • 2,722
  • 3
  • 23
  • 49

2 Answers2

2

I found an even better easier way to do this. I have to credit s952163 for starting me down a good path, but this approach is even more optimized:

let square (x:Vector<float>) = x * x 
let subtract (x:Vector<float>) (y:Vector<float>) = y - x
let divideBy (x:float) (y:float) = y / x

let SumSquares (theta:Vector<float>) (y:Vector<float>) (trainingData:Matrix<float>) =
    let m = trainingData.RowCount |> float
    (trainingData * theta)
    |> subtract y
    |> square
    |> divideBy m
David Crook
  • 2,722
  • 3
  • 23
  • 49
1

Since you know the number of rows you can just map to that. Arguably this is not pretty:

let SumSquares (theta:Vector<float>) (y:Vector<float>) (trainingData:Matrix<float>) =
    let m = trainingData.RowCount
    let theta' = theta.ToRowMatrix()                                             
    [0..m-1] |> List.map (fun i -> (((theta' * trainingData.[i,0..1]) |> Seq.exactlyOne) - yVals.[i] ))

Edit:
My guess is that mapRows wants everything to be in the same shape, and your output vector is different. So if you want to stick to the Vector type, this will just enumerate the indexed rows:

tData.EnumerateRowsIndexed() |> Seq.map (fun (i,r) -> (theta' * r) - yVals.[i])
and you can also use Matrix.toRowSeqi if you prefer to pipe it through, and get back a Matrix:

tData 
    |> Matrix.toRowSeqi 
    |> Seq.map (fun (i,x) -> (theta' * x) - yVals.[i]) 
    |> DenseMatrix.ofRowSeq
s952163
  • 6,276
  • 4
  • 23
  • 47
  • That last one is money. Thats what I ended up implementing, works like flipping charm! – David Crook May 17 '16 at 17:07
  • Actually I rolled with this, because its sum of squares: let SumSquares (theta:Vector) (y:Vector) (trainingData:Matrix) = let theta' = theta.ToRowMatrix() trainingData |> Matrix.toRowSeqi |> Seq.map(fun (i,r) -> vector [ square((theta' * r) - y.[i]) ] ) |> DenseMatrix.ofRowSeq – David Crook May 17 '16 at 17:13
  • if you can duplicate the post I just did, I'll credit you with the answer. – David Crook May 17 '16 at 21:14
  • Should be ok as it is for future reference, and your comment says it all. Gave me an opportunity to look at Mathnet. Your solution is pretty clean and neat. – s952163 May 17 '16 at 23:22