F # - Записать документ FrameData в CSV - PullRequest
0 голосов
/ 23 мая 2018

Мне нужно записать Deedle FrameData (включая столбец «ID» и дополнительный столбец «Delta» с пустыми записями) в CSV.Хотя я могу создать двумерный массив FrameData , я не могу правильно записать его в файл CSV.

module SOQN = 

    open System
    open Deedle
    open FSharp.Data

    //  TestInput.csv
    //  ID,Alpha,Beta,Gamma
    //  1,no,1,hi
    //  ...

    //  TestOutput.csv
    //  ID,Alpha,Beta,Gamma,Delta
    //  1,"no","1","hi",""
    //  ...

    let inputCsv = @"D:\TestInput.csv"
    let outputCsv = @"D:\TestOutput.csv"
    let (df:Frame<obj,string>) = Frame.ReadCsv(inputCsv, hasHeaders=true, inferTypes=false, separators=",", indexCol="ID")

    // See http://www.fssnip.net/sj/title/Insert-Deedle-frame-into-Excel
    let data4Frame (frame:Frame<_,_>) = frame.GetFrameData()

    // See http://www.fssnip.net/sj/title/Insert-Deedle-frame-into-Excel
    let boxOptional obj =
        match obj with
        | Deedle.OptionalValue.Present obj -> box (obj.ToString()) 
        | _ -> box ""

    // See http://www.fssnip.net/sj/title/Insert-Deedle-frame-into-Excel
    let frameToArray (data:FrameData) =
        let transpose (array:'T[,]) =
          Array2D.init (array.GetLength(1)) (array.GetLength(0)) (fun i j -> array.[j, i])
        data.Columns
        |> Seq.map (fun (typ, vctr) -> vctr.ObjectSequence |> Seq.map boxOptional |> Array.ofSeq)
        |> array2D
        |> transpose

    let main = 
        printfn ""
        printfn "Output Deedle FrameData To CSV"
        printfn ""
        let dff = data4Frame df
        let rzlt = frameToArray dff     
        printfn "rzlt: %A" rzlt     
        do 
            use writer = new StreamWriter(outputCsv)
            writer.WriteLine("ID,Alpha,Beta,Gamma,Delta")
            // writer.WriteLine rzlt
        0

    [<EntryPoint>]
    main
    |> ignore

Чего мне не хватает?

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Я бы не стал использовать FrameData для этого - фреймные данные в основном являются внутренними, и хотя для них есть некоторые законные применения, я не думаю, что это имеет смысл для этой задачи.

Если вы простоВы хотите добавить пустой столбец Delta во входной CSV-файл, тогда вы можете сделать следующее:

let df : Frame<int, _> = Frame.ReadCsv("C:/temp/test-input.csv", indexCol="ID")
df.AddColumn("Delta", [])
df.SaveCsv("C:/temp/test-output.csv", ["ID"])

Это сделает почти все, что вам нужно - он записывает столбец ID и дополнительный столбец Delta,

Единственное предостережение в том, что он не добавляет лишних кавычек вокруг данных.Это не требуется спецификацией CSV, если вам не нужно экранировать запятую в столбце, и я не думаю, что есть простой способ заставить Дидла сделать это.

Итак, я думаю, что вы быдолжны написать свои собственные записи в файл CSV.Ниже показано, как это сделать, но он не корректно экранирует кавычки и запятые (поэтому вы должны использовать SaveCsv, даже если он не вставляется в кавычки, когда они не нужны):

use writer = new StreamWriter("C:/temp/test-output.csv")
writer.WriteLine("ID,Alpha,Beta,Gamma,Delta")
for key, row in Series.observations df.Rows do
  writer.Write(key)
  for value in Series.valuesAll row do
    writer.Write(",")
    writer.Write(sprintf "\"%O\"" (if value.IsSome then value.Value else box ""))
  writer.WriteLine()
0 голосов
/ 23 мая 2018

Вы можете получить пример записи в CSV из источника библиотеки (там используется FrameData)

После добавления оболочки:

type FrameData with 
    member frameData.SaveCsv(path:string, ?includeRowKeys, ?keyNames, ?separator, ?culture) = 
      use writer = new StreamWriter(path)
      writeCsv writer (Some path) separator culture includeRowKeys keyNames frameData

Вы могли бы написать так:

dff.SaveCsv outputCsv 
...