F# CSV TypeProvider 在控制台应用程序中不太健壮
F# CSV TypeProvider less robust in console application
我正在尝试使用来自冠状病毒大流行的实时数据进行实验(不幸的是,祝我们所有人好运)。
我开发了一个小脚本,我正在过渡到控制台应用程序:它使用 CSV 类型的提供程序。
我有以下问题。假设我们想按地区过滤意大利传播,我们可以将此代码放入 .fsx 文件中:
open FSharp.Data
let provinceData = CsvProvider< @"https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/dati-province/dpc-covid19-ita-province.csv" , IgnoreErrors = true>.GetSample()
let filterDataByProvince province =
provinceData.Rows
|> Seq.filter (fun x -> x.Sigla_provincia = province)
由于序列惰性,假设我强制编译器将罗马省的数据加载到内存中,我可以添加:
let romeProvince = filterDataByProvince "RM" |> Seq.toArray
FSI 在本地 运行 这很好用。
现在,如果我使用 .fs 文件将此代码转换为控制台应用程序;我声明完全相同的函数并使用完全相同类型的提供程序加载器;但我没有使用最后一行来收集数据,而是将其放入主函数中:
[<EntryPoint>]
let main _ =
let romeProvince = filterDataByProvince "RM" |> Seq.toArray
Console.Read() |> ignore
0
这导致以下 运行时间异常:
System.Exception
HResult=0x80131500
Message=totale_casi is missing
Source=FSharp.Data
StackTrace:
at <StartupCode$FSharp-Data>.$TextRuntime.GetNonOptionalValue@139-4.Invoke(String message)
at CoronaSchiatta.Evoluzione.provinceData@10.Invoke(Object parent, String[] row) in C:\Users\glddm\source\repos\CoronaSchiatta\CoronaSchiatta\CoronaEvolution.fs:line 10
at FSharp.Data.Runtime.CsvHelpers.parseIntoTypedRows@174.GenerateNext(IEnumerable`1& next)
你能解释一下吗?
有些行可能有奇怪的格式,但 FSI 会话对这些行很健壮,而控制台版本很脆弱;为什么?我该如何解决?
我正在使用 VS2019 社区版,目标为 .NET Framework 4.7.2,F# 运行时间:4.7.0.0;
作为 FSI,我使用以下内容:FSI Microsoft (R) F# Interactive version 10.7.0.0 for F# 4.7
PS:另请注意,如果我使用 CsvFile 而不是类型提供程序,如:
let test = @"https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/dati-province/dpc-covid19-ita-province.csv"
|> CsvFile.Load |> (fun x -> x.Rows ) |> Seq.filter ( fun x-> x.[6 ] = "RM")
|> Seq.iter ( fun x -> x.[9] |> Console.WriteLine )
然后它在控制台应用程序中也像魅力一样工作。当然,我想使用类型提供程序,否则我必须添加类型定义,将模式映射到列(这会更脆弱)。最后一行只是一个快速测试。
脆弱性
如果您没有好的架构或示例,CSV 类型提供程序可能会很脆弱。
现在出现 运行 时间错误几乎可以肯定是因为您的数据不匹配。
你怎么想出来的?一种方法是先 运行 通过您的数据:
provinceData.Rows |> Seq.iteri (fun i x -> printfn "Row %d: %A" (i + 1) x)
这 运行 到第 2150 行。果然,下一行:
2020-03-11 17:00:00,ITA,19,Sicilia,994,In fase di definizione/aggiornamento,,0,0,
您可以看到缺少最后一个值 (totale_casi
)。
CsvProvider 的选项之一是 InferRows
。这是提供程序为了构建架构而扫描的行数 - 它的默认值恰好是 1000。
所以:
type COVID = CsvProvider<uri, InferRows = 0>
防止将来发生这种情况的更好方法是从数据子集中手动定义样本:
type COVID = CsvProvider<"sample-dpc-covid19-ita-province.csv">
和sample-dpc-covid19-ita-province.csv
是:
data,stato,codice_regione,denominazione_regione,codice_provincia,denominazione_provincia,sigla_provincia,lat,long,totale_casi
2020-02-24 18:00:00,ITA,13,Abruzzo,069,Chieti,CH,42.35103167,14.16754574,0
2020-02-24 18:00:00,ITA,13,Abruzzo,066,L'Aquila,AQ,42.35122196,13.39843823,
2020-02-24 18:00:00,ITA,13,Abruzzo,068,Pescara,PE,42.46458398,14.21364822,0
2020-02-24 18:00:00,ITA,13,Abruzzo,067,Teramo,TE,42.6589177,13.70439971,0
有了这个 totale_casi
的类型现在是 Nullable<int>
。
如果你不介意NaN
值,你也可以使用:
CsvProvider<..., AssumeMissingValues = true>
为什么 FSI 看起来更稳健?
FSI 并不更可靠。这是我最好的猜测:
您的架构源正在定期更新。
键入 Providers cache the schema,这样它就不会在您每次编译代码时都重新生成架构,这可能是不切实际的。当您重新启动 FSI 会话时,您最终会重新生成您的类型提供程序,但控制台应用程序并非如此。因此,使用更新的源代码有时可能会减少出错的可能性。
我正在尝试使用来自冠状病毒大流行的实时数据进行实验(不幸的是,祝我们所有人好运)。
我开发了一个小脚本,我正在过渡到控制台应用程序:它使用 CSV 类型的提供程序。
我有以下问题。假设我们想按地区过滤意大利传播,我们可以将此代码放入 .fsx 文件中:
open FSharp.Data
let provinceData = CsvProvider< @"https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/dati-province/dpc-covid19-ita-province.csv" , IgnoreErrors = true>.GetSample()
let filterDataByProvince province =
provinceData.Rows
|> Seq.filter (fun x -> x.Sigla_provincia = province)
由于序列惰性,假设我强制编译器将罗马省的数据加载到内存中,我可以添加:
let romeProvince = filterDataByProvince "RM" |> Seq.toArray
FSI 在本地 运行 这很好用。
现在,如果我使用 .fs 文件将此代码转换为控制台应用程序;我声明完全相同的函数并使用完全相同类型的提供程序加载器;但我没有使用最后一行来收集数据,而是将其放入主函数中:
[<EntryPoint>]
let main _ =
let romeProvince = filterDataByProvince "RM" |> Seq.toArray
Console.Read() |> ignore
0
这导致以下 运行时间异常:
System.Exception
HResult=0x80131500
Message=totale_casi is missing
Source=FSharp.Data
StackTrace:
at <StartupCode$FSharp-Data>.$TextRuntime.GetNonOptionalValue@139-4.Invoke(String message)
at CoronaSchiatta.Evoluzione.provinceData@10.Invoke(Object parent, String[] row) in C:\Users\glddm\source\repos\CoronaSchiatta\CoronaSchiatta\CoronaEvolution.fs:line 10
at FSharp.Data.Runtime.CsvHelpers.parseIntoTypedRows@174.GenerateNext(IEnumerable`1& next)
你能解释一下吗?
有些行可能有奇怪的格式,但 FSI 会话对这些行很健壮,而控制台版本很脆弱;为什么?我该如何解决?
我正在使用 VS2019 社区版,目标为 .NET Framework 4.7.2,F# 运行时间:4.7.0.0; 作为 FSI,我使用以下内容:FSI Microsoft (R) F# Interactive version 10.7.0.0 for F# 4.7
PS:另请注意,如果我使用 CsvFile 而不是类型提供程序,如:
let test = @"https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/dati-province/dpc-covid19-ita-province.csv"
|> CsvFile.Load |> (fun x -> x.Rows ) |> Seq.filter ( fun x-> x.[6 ] = "RM")
|> Seq.iter ( fun x -> x.[9] |> Console.WriteLine )
然后它在控制台应用程序中也像魅力一样工作。当然,我想使用类型提供程序,否则我必须添加类型定义,将模式映射到列(这会更脆弱)。最后一行只是一个快速测试。
脆弱性
如果您没有好的架构或示例,CSV 类型提供程序可能会很脆弱。
现在出现 运行 时间错误几乎可以肯定是因为您的数据不匹配。 你怎么想出来的?一种方法是先 运行 通过您的数据:
provinceData.Rows |> Seq.iteri (fun i x -> printfn "Row %d: %A" (i + 1) x)
这 运行 到第 2150 行。果然,下一行:
2020-03-11 17:00:00,ITA,19,Sicilia,994,In fase di definizione/aggiornamento,,0,0,
您可以看到缺少最后一个值 (totale_casi
)。
CsvProvider 的选项之一是 InferRows
。这是提供程序为了构建架构而扫描的行数 - 它的默认值恰好是 1000。
所以:
type COVID = CsvProvider<uri, InferRows = 0>
防止将来发生这种情况的更好方法是从数据子集中手动定义样本:
type COVID = CsvProvider<"sample-dpc-covid19-ita-province.csv">
和sample-dpc-covid19-ita-province.csv
是:
data,stato,codice_regione,denominazione_regione,codice_provincia,denominazione_provincia,sigla_provincia,lat,long,totale_casi
2020-02-24 18:00:00,ITA,13,Abruzzo,069,Chieti,CH,42.35103167,14.16754574,0
2020-02-24 18:00:00,ITA,13,Abruzzo,066,L'Aquila,AQ,42.35122196,13.39843823,
2020-02-24 18:00:00,ITA,13,Abruzzo,068,Pescara,PE,42.46458398,14.21364822,0
2020-02-24 18:00:00,ITA,13,Abruzzo,067,Teramo,TE,42.6589177,13.70439971,0
有了这个 totale_casi
的类型现在是 Nullable<int>
。
如果你不介意NaN
值,你也可以使用:
CsvProvider<..., AssumeMissingValues = true>
为什么 FSI 看起来更稳健?
FSI 并不更可靠。这是我最好的猜测:
您的架构源正在定期更新。 键入 Providers cache the schema,这样它就不会在您每次编译代码时都重新生成架构,这可能是不切实际的。当您重新启动 FSI 会话时,您最终会重新生成您的类型提供程序,但控制台应用程序并非如此。因此,使用更新的源代码有时可能会减少出错的可能性。