F # CSV TypeProvider менее надежен в консольном приложении - PullRequest
3 голосов
/ 15 марта 2020

Я пытаюсь поэкспериментировать с живыми данными из пандемии Коронавируса c (к сожалению и удачи всем нам).

Я разработал небольшой скрипт и перехожу в консольное приложение: он использует поставщиков типа 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 Community Edition с таргетингом. NET Framework 4.7.2, среда исполнения F #: 4.7.0.0; в качестве FSI я использую следующее: FSI Microsoft (R) F # Интерактивная версия 10.7.0.0 для 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 )

Тогда это работает как брелок и в консольном приложении. Конечно, я хотел бы использовать провайдеры типов, в противном случае я должен добавить определение типа, сопоставив схему со столбцами (и это будет более fr agile). Последняя строка была просто быстрой проверкой.

1 Ответ

3 голосов
/ 15 марта 2020

Хрупкость

Поставщики CSV-типов могут быть fr agile, если у вас нет хорошей схемы или образца.

Теперь получение ошибки во время выполнения почти наверняка, потому что ваши данные не ' не совпадают. Как вы это понимаете? Один из способов - сначала просмотреть ваши данные:

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 не более устойчивый. Это мое лучшее предположение:

Ваш источник схемы регулярно обновляется. Поставщики типов кэшируют схему , чтобы она не генерировала схему каждый раз, когда вы компилируете код, что может быть непрактично. Когда вы перезапускаете сеанс FSI, вы в конечном итоге регенерируете своего поставщика типов, но не с консольным приложением. Поэтому иногда он может быть менее подвержен ошибкам, работая с более новым источником.

...