【问题标题】:F# CSVProvider only reports first column dataF# CSVProvider 只报告第一列数据
【发布时间】:2017-07-12 11:43:14
【问题描述】:

在任何 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 仅用于演示。

【问题讨论】:

  • 当我在 vim 中打开该文件时,它全部显示在一行上。原来文件有mac换行符(\r)。尝试改用 unix 换行符 (\n)?
  • 虽然您包含的屏幕截图对于显示您在调试器中看到的值很有用,但通常最好将您的代码包含为 text 而不是屏幕截图,因为无法搜索屏幕截图中的代码。除了屏幕截图之外,您能否编辑您的问题以将您的代码作为文本包含在内?
  • @TheQuickBrownFox 我把文字改成Windows CRLF但是效果还是一样的

标签: csv f#


【解决方案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# 交互窗口。

这是我得到的输出:

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 类型定义中。另一种方法是指定一个显式模式,通过仅查看前 1,000 行来告诉 CsvProvider 哪些行会出错。 (如果您的数据集很大,这是更可取的,因为查看所有行以推断数据类型将花费太长时间)。有关示例,请参阅文档,但您会执行 Schema="fl_site_deductible=decimal" 之类的操作。

因此,如果您的代码无法在 Visual Studio 中运行,请查看 VS Code(带有 Ionide-Paket、Ionide-FSharp 和 Ionide-FAKE 扩展)是否适合您。

【讨论】:

  • 感谢我需要将其与更大的代码库集成的建议。迁移到 VSCode 会使这变得不切实际(尽管我从头开始尝试过 VS2015,但同样的问题)这个问题发生在几个(可能是所有)csv 文件上。您似乎正在运行 mac 或某种 linux,因此可能会有所作为。我在 Windows 上。
猜你喜欢
  • 1970-01-01
  • 2016-04-10
  • 1970-01-01
  • 2018-07-27
  • 1970-01-01
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多