首页 > 解决方案 > F# 和 Web API Json 用于在 DataFrame 中进行分析

问题描述

我试图通过从 python 重写一些脚本来学习 F#,我在其中查询 graphql 端点并将 json 加载到 Pandas DataFrame 中以进行清理和分析:

像这样的json:

apiResponse = {"data":
                    {"Shipments":{"ErrorMessage":null,
                    "Success":true,
                    "ValidationResult":null,
                    "TotalCount":494,
                    "Data":[
                       {"Building":"B7",
                        "Comment":"Test",
                        "CompletedDate":"2021-04-12T10:13:13.436Z",
                        "ItemId":"dd4520bb-aa0a-...",
                        "NoOfUnit":5,
                        "Organization":{
                              "OrganizationId":"cac43a32-1f08-...",
                              "OrganizationName":"XXX"},
                       "Adress":"Road 5"
                      },
                      {"Building":"B7",
                      ....}]}}}

Python:

data = request.json()
#only the "Data" path
json_list = data['data']['Shipments']['Data']
df = json_normalize(json_list)

使用 Fsharp.Data 的方法相同,而“file.json”只是“Data[]”部分(我试图创建一个小提琴,但我无法让它运行。这里


type ApiTypes = JsonProvider<"file.json"> //where file.json has only "Data" path of apiResponse
let jsonResponse = JsonValue.Parse(apiResponse)
let data = jsonResponse?data
let Shipments = data?Shipments
let Data = Shipments?Data

let input = 
 ApiTypes.Parse(Data.ToString())

let df = Frame.ofRecords input

但这不起作用。所以我的问题:

  1. 这是使用这个 json 的正确方法吗?
  2. 有没有更好的方法来创建一个带有 json 的 DataFrame?

任何帮助表示赞赏。谢谢

标签: jsonf#deedlefsharp.data.typeproviders

解决方案


我对 Deedle 没有任何经验,但我认为ofRecords 需要一个实际的静态类型才能正常工作,因此它可能与JsonProvider. (至少我无法让它工作。)

相反,我会手动定义类型,然后对其进行反序列化,如下所示:

open Newtonsoft.Json.Linq

type Datum =
    {
        Building : string
        Comment : string
        CompletedDate : DateTime
        ItemId : Guid
        NoOfUnit : int
        Organization :
            {|
                OrganizationId : Guid
                OrganizationName : string
            |}
        Adress : string
    }

let jobj = JObject.Parse(apiResponse)
let frame =
    jobj.["data"].["Shipments"].["Data"].Children()
        |> Seq.map (fun jtok -> jtok.ToObject<Datum>())
        |> Frame.ofRecords

推荐阅读