F#CSVProvider仅报告第一列数据

时间:2017-07-12 11:43:15

标签: csv f#

firstRow is of type string

在任何csv文件上使用CSVprovider时,我使用了以下内容:

http://spatialkeydocs.s3.amazonaws.com/FL_insurance_sample.csv.zip

    type statsProvider = CsvProvider<"../../FL_insurance_sample.csv",",">

    let stats = statsProvider.Load("../../FL_insurance_sample.csv")

    let firstRow = stats.Rows |> Seq.head

CSVProvider仅返回第一列中的数据。它确实正确地标识了列(18)和列的名称,但是当你查看行的类型时,它们只是键入字符串,而不是元组或结构...

在屏幕截图中看到firstRow的类型应该是特定类型,例如元组或结构不是字符串。

我做错了什么?使用Visual Studio 2017,FSharp 4.1,.net 4.5.2和FSharp.Data 2.3.3

注意:至少还有3个csv文件会发生这种情况。我选择这个特殊的csv仅用于演示。

1 个答案:

答案 0 :(得分:1)

我无法重现您的问题:您提供的示例CSV文件对我来说效果很好。但是,我使用的是VS Code,而不是Visual Studio;问题的根源可能是Visual Studio 2017中的某个位置,而不是FSharp.Data中的某个位置。这是我做的:

  1. 创建一个新的空项目文件夹。
  2. 将Paket引导程序复制到.paket/paket.bootstrapper.exe
  3. 运行paket init
  4. 修改paket.dependencies文件以添加FSharp.Data
  5. 运行paket install
  6. 运行paket generate-load-scripts,它在.paket/load文件夹中创建了一堆脚本,一次加载所有依赖项。 (我喜欢这个功能用于编写脚本!)
  7. 使用以下内容创建script.fsx

    #load ".paket/load/net452/FSharp.Data.fsx"
    open FSharp.Data
    
    type Csv = CsvProvider<"/home/rmunn/Downloads/tmp/csv/FL_insurance_sample.csv">
    let data = Csv.GetSample()
    
    printfn "%A" data.Headers
    
    let firstRow = data.Rows |> Seq.head
    printfn "%A" firstRow
    
  8. 在VS Code中,选择整个脚本文件并按Alt + Enter将其发送到F#Interactive窗口。

  9. 这是我得到的输出:

    F# Interactive for F# 4.1
    Freely distributed under the Apache 2.0 Open Source License
    
    For help type #help;;
    > # silentCd @"/home/rmunn/code/fsharp/tmp/foo";;
    - # 1 @"/home/rmunn/code/fsharp/tmp/foo/script.fsx"
    - ;;
    
    (snip the copy of my script that F# Interactive echoed)
    
    [Loading /home/rmunn/code/fsharp/tmp/foo/.paket/load/net452/Zlib.Portable.fsx
     Loading /home/rmunn/code/fsharp/tmp/foo/.paket/load/net452/FSharp.Data.fsx]
    namespace FSI_0002.Zlib
    
    namespace FSI_0002.FSharp
    
    Some
      [|"policyID"; "statecode"; "county"; "eq_site_limit"; "hu_site_limit";
        "fl_site_limit"; "fr_site_limit"; "tiv_2011"; "tiv_2012";
        "eq_site_deductible"; "hu_site_deductible"; "fl_site_deductible";
        "fr_site_deductible"; "point_latitude"; "point_longitude"; "line";
        "construction"; "point_granularity"|]
    (119736, "FL", "CLAY COUNTY", 498960M, 498960M, 498960M, 498960M, 498960M,
     792148.9M, 0M, 9979.2M, 0, 0, 30.102261M, -81.711777M, "Residential", "Masonry",
     1)
    type Csv = FSharp.Data.CsvProvider<...>
    val data : FSharp.Data.CsvProvider<...>
    val firstRow : FSharp.Data.CsvProvider<...>.Row =
      (119736, "FL", "CLAY COUNTY", 498960M, 498960M, 498960M, 498960M, 498960M,
       792148.9M, 0M, 9979.2M, 0, 0, 30.102261M, -81.711777M, "Residential",
       "Masonry", 1)
    val it : unit = ()
    

    然而,所有人都没有顺利完成 。当我尝试处理每一行时,我得到以下异常:

      

    System.Exception:无法根据模式解析行2439:期望fl_site_deductible中的Int32,得到68817.6

    (我省略了回溯,因为知道FSharp.Data中哪个行号抛出该异常对你没有特别帮助。)

    可以在CsvProvider documentation的“控制列类型”部分中看到此问题的原因,其中包含:

      

    默认情况下,CSV类型提供程序会检查前1000行以推断类型,但您可以通过指定CsvProvider的InferRows静态参数来自定义它们。如果指定0,则将使用整个文件。

    有两种方法可以解决“推断的int但应该是小数”的问题。一种方法是将InferRows=0添加到CsvProvider类型定义中。另一种方法是指定一个显式模式,通过仅查看前1000个来告诉CsvProvider哪些行会出错。 (如果您的数据集很大,这是非常可取的,因为查看所有行以推断数据类型将花费太长时间)。有关示例,请参阅文档,但您可以执行Schema="fl_site_deductible=decimal"

    之类的操作

    因此,如果您无法让代码在Visual Studio中运行,请参阅VS Code(使用Ionide-Paket,Ionide-FSharp和Ionide-FAKE扩展)是否适合您。