如何在F#中改组“DenseMatrix”

时间:2016-11-07 13:29:33

标签: matrix f# mathnet mathdotnet fslab

在Matlab中,我们可以编写以下代码来混洗矩阵:

data = data(:, randperm(size(data,2)));

我用Math.NET编写的内容:

let csvfile = @"../UFLDL-tutorial-F#/housing.csv"
let housingAsLines = 
    File.ReadAllLines(csvfile)
        |> Array.map (fun t -> t.Split(',')
                            |> Array.map (fun t -> float t))
let housingAsMatrix= DenseMatrix.OfRowArrays housingAsLines
let housingAsMatrixT = housingAsMatrix.Transpose()

let v1 = DenseVector.Create(housingAsMatrixT.ColumnCount,1.0)
housingAsMatrixT.InsertRow(0,v1)

// How to shuffle a "DenseMatrix" in F#

使用F#切片语法和从零开始的索引在Matlab中模拟矩阵运算。但是,它不起作用。

housingAsMatrixT.[*,0]

我在vscode中收到了错误消息。

The field, constructor or member 'GetSlice' is not defined

请随时提出建议。谢谢。

3 个答案:

答案 0 :(得分:3)

使用神经网络我不得不改组矩阵数组并使用以下代码。请注意,基础数据结构是一个数组([]),并且数组中的每个项目都是Matrix。这不是改组矩阵,而是数组。它应该让你知道如何处理你的问题。

type Random() = 
    static member Shuffle (a : 'a[]) =
        let rand = new System.Random()
        let swap (a: _[]) x y =
            let tmp = a.[x]
            a.[x] <- a.[y]
            a.[y] <- tmp
        Array.iteri (fun i _ -> swap a i (rand.Next(i, Array.length a))) a

并称之为

Random.Shuffle trainingData

附录

以下是将byte[]转换为DenseMatrix

的代码
let byteArrayToMatrix (bytes : byte[]) : Matrix<double> =
    let (x : Vector<byte>) = Vector<byte>.Build.DenseOfArray bytes
    let (y : Vector<double>) = x.Map(fun x -> double x)
    let (z : Matrix<double>) = Matrix<double>.Build.DenseOfRowVectors y
    z

答案 1 :(得分:2)

你实际上有两个问题,1)如何切割matrices ala matlab和2)如何改组矩阵的列。

对于1)实际上你在评论中链接的Issue 277确实提供了解决方案。但是,您可能使用的是旧版本,或者可能未正确引用F#扩展名:

#r @"..\packages\MathNet.Numerics.3.13.1\lib\net40\MathNet.Numerics.dll"
#r @"..\packages\MathNet.Numerics.FSharp.3.13.1\lib\net40\MathNet.Numerics.FSharp.dll"

open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra
open MathNet.Numerics.Distributions
open System

//let m = DenseMatrix.randomStandard<float> 5 5
let m = DenseMatrix.random<float> 5 5 (ContinuousUniform(0., 1.))
let m' = m.[*,0]
m'
//val it : Vector<float> =
//seq [0.4710989485; 0.2220238937; 0.566367266; 0.2356496324; ...]

这将提取矩阵的第一列。

现在2),假设你需要改组矩阵或包含矩阵的数组,你可以使用下面的一些方法。在mathnet.numerics中可能有更优雅的方法。

要对上面的向量进行置换:m'.SelectPermutation()SelectPermutationInplace用于数组。还有其他便利功能,如.Column(idx),。EnumerateColumnsIndexed()EnumerateColumns()等。

所以m'.SelectPermutation()会改变m&#39;的元素。或者将列(你的matlab函数所做的)洗牌:

let idx = Combinatorics.GeneratePermutation 5
idx
//val it : int [] = [|2; 0; 1; 4; 3|]
let m2 = idx |> Seq.map (fun i -> m.Column(i)) |> DenseMatrix.ofColumnSeq
m2.Column(1) = m.Column(0)
//val it : bool = true

由于原始矩阵的第一列移动到新矩阵的第二列,因此两者应相等。

答案 2 :(得分:2)

@GuyCoder和@ s952163,谢谢你的帮助。我实现了一个快速和肮脏的版本。它不够好但它有效。

请随时发表评论。谢谢。

#load "../packages/FsLab.1.0.2/FsLab.fsx"
open System
open System.IO
open MathNet.Numerics.LinearAlgebra.Double
open MathNet.Numerics
open MathNet.Numerics.LinearAlgebra
open MathNet.Numerics.Distributions

// implementation of the Fisher-Yates shuffle by Mathias
// http://www.clear-lines.com/blog/post/Optimizing-some-old-F-code.aspx
let swap fst snd i =
   if i = fst then snd else
   if i = snd then fst else
   i
let shuffle items (rng: Random) =
   let rec shuffleTo items upTo =
      match upTo with
      | 0 -> items
      | _ ->
         let fst = rng.Next(upTo)
         let shuffled = List.permute (swap fst (upTo - 1)) items
         shuffleTo shuffled (upTo - 1)
   let length = List.length items
   shuffleTo items length

let csvfile = @"/eUSB/sync/fsharp/UFLDL-tutorial-F#/housing.csv"
let housingAsLines = 
    File.ReadAllLines(csvfile)
        |> Array.map (fun t -> t.Split(',')
                            |> Array.map (fun t -> float t))
let housingAsMatrix= DenseMatrix.OfRowArrays housingAsLines
let housingAsMatrixTmp = housingAsMatrix.Transpose()
let v1 = DenseVector.Create(housingAsMatrixTmp.ColumnCount,1.0)
let housingAsMatrixT = housingAsMatrixTmp.InsertRow(0,v1)

let m = housingAsMatrixT.RowCount - 1
let listOfArray = [0..m]
let random = new Random()
let shuffled = shuffle listOfArray random

let z = [for i in shuffled -> (housingAsMatrixT.[i, *])]
let final = DenseMatrix.OfRowVectors z