如何在 F# 中随机播放 "DenseMatrix"

How to shuffle a "DenseMatrix" in F#

在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#

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

housingAsMatrixT.[*,0]

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

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

对于神经网络,我不得不打乱矩阵数组并使用以下代码。请注意,基本数据结构是一个数组 ([]),数组中的每一项都是一个矩阵。这不是洗牌矩阵,而是一个数组。它应该让您了解如何处理您的问题。

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) 如何在 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' 的元素。或随机排列列(您的 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

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

@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