Как перетасовать DenseMatrix в 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# и индексацию с нуля. Тем не менее, это не работает.

housingAsMatrixT.[*,0]

И я получил сообщение об ошибке в vscode.

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

Пожалуйста, не стесняйтесь советовать. Спасибо.

3 ответа

Решение

На самом деле у вас есть два вопроса: 1) как нарезать матрицы аля matlab и 2) как перемешать столбцы матрицы.

Во-первых, проблема 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() будет тасовать элементы м '. Или перемешать столбцы (что делает ваша функция 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

Поскольку первый столбец исходной матрицы перемещен во второй столбец новой матрицы, оба должны быть равны.

С нейронными сетями мне пришлось перетасовать массив матриц и использовать следующий код. Обратите внимание, что базовая структура данных - это массив ([]), а каждый элемент в массиве - это матрица. Это не тасование матрицы, а массива. Это должно дать вам некоторое представление о том, как поступить с вашей проблемой.

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

@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
Другие вопросы по тегам