乐趣区

关于pandas:骚操作嵌套-JSON-秒变-Dataframe

首发于公众号:Python 数据迷信

作者:东哥腾飞

调用 API 和文档数据库会返回嵌套的 JSON 对象,当咱们应用 Python 尝试将嵌套构造中的键转换为列时,数据加载到 pandas 中往往会失去如下后果:

df = pd.DataFrame.from_records(results [“issues”],columns = [“key”,“fields”])

阐明:这里 results 是一个大的字典,issues 是 results 其中的一个键,issues 的值为一个嵌套 JSON 对象字典的列表,前面会看到 JSON 嵌套构造。

问题在于 API 返回了嵌套的 JSON 构造,而咱们关怀的键在对象中确处于不同级别。

嵌套的 JSON 构造张成这样的。

而咱们想要的是上面这样的。

上面以一个 API 返回的数据为例,API 通常蕴含无关字段的元数据。假如上面这些是咱们想要的字段。

  • key:JSON 密钥,在第一级的地位。
  • summary:第二级的“字段”对象。
  • status name:第三级地位。
  • statusCategory name:位于第 4 个嵌套级别。

如上,咱们抉择要提取的字段在 issues 列表内的 JSON 构造中别离处于 4 个不同的嵌套级别,一环扣一环。

{
  "expand": "schema,names",
  "issues": [
    {
      "fields": {
        "issuetype": {
          "avatarId": 10300,
          "description": "","id":"10005","name":"New Feature","subtask": False
        },
        "status": {
          "description": "A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.",
          "id": "5",
          "name": "Resolved",
          "statusCategory": {
            "colorName": "green",
            "id": 3,
            "key": "done",
            "name": "Done",
          }
        },
        "summary": "Recovered data collection Defraglar $MFT problem"
      },
      "id": "11861",
      "key": "CAE-160",
    },
    {
      "fields": {... more issues],
  "maxResults": 5,
  "startAt": 0,
  "total": 160
}

一个不太好的解决方案

一种抉择是间接撸码,写一个查找特定字段的函数,但问题是必须对每个嵌套字段调用此函数,而后再调用 .applyDataFrame中的新列。

为获取咱们想要的几个字段,首先咱们提取 fields 键内的对象至列:

df = (df["fields"]
    .apply(pd.Series)
    .merge(df, left_index=True, right_index = True)
)

从上表看出,只有 summary 是可用的,issuetype、status 等依然埋在嵌套对象中。

上面是提取 issuetype 中的 name 的一种办法。

# 提取 issue type 的 name 到一个新列叫 "issue_type"
df_issue_type = (df["issuetype"]
    .apply(pd.Series)
    .rename(columns={"name": "issue_type_name"})["issue_type_name"]
)
df = df.assign(issue_type_name = df_issue_type)

像下面这样,如果嵌套层级特地多,就须要本人手撸一个递归来实现了,因为每层嵌套都须要调用一个像下面解析并增加到新列的办法。

对于编程基础薄弱的敌人,手撸一个其实还挺麻烦的,尤其是对于数据分析师,焦急想用数据的时候,心愿能够疾速拿到结构化的数据进行剖析。

上面东哥分享一个 pandas 的内置解决方案。

内置的解决方案

pandas中有一个牛逼的内置性能叫 .json_normalize

pandas的文档中提到:将半结构化 JSON 数据规范化为立体表。

后面计划的所有代码,用这个内置性能仅须要 3 行就可搞定。步骤很简略,懂了上面几个用法即可。

确定咱们要想的字段,应用 . 符号连贯嵌套对象。

将想要解决的嵌套列表(这里是results["issues"])作为参数放进 .json_normalize 中。

过滤咱们定义的 FIELDS 列表。

FIELDS = ["key", "fields.summary", "fields.issuetype.name", "fields.status.name", "fields.status.statusCategory.name"]
df = pd.json_normalize(results["issues"])
df[FIELDS]

没错,就这么简略。

其它操作

记录门路

除了像下面那样传递 results["issues"] 列表之外,咱们还应用 record_path 参数在 JSON 对象中指定列表的门路。

# 应用门路而不是间接用 results["issues"]
pd.json_normalize(results, record_path="issues")[FIELDS]

自定义分隔符

还能够应用 sep 参数自定义嵌套构造连贯的分隔符,比方上面将默认的“.”替换“-”。

### 用 "-" 替换默认的 "."
FIELDS = ["key", "fields-summary", "fields-issuetype-name", "fields-status-name", "fields-status-statusCategory-name"]
pd.json_normalize(results["issues"], sep = "-")[FIELDS]

管制递归

如果不想递归到每个子对象,能够应用 max_level 参数管制深度。在这种状况下,因为 statusCategory.name 字段位于 JSON 对象的第 4 级,因而不会蕴含在后果 DataFrame 中。

# 只深刻到嵌套第二级
pd.json_normalize(results, record_path="issues", max_level = 2)

上面是 .json_normalizepandas官网文档阐明,如有不明确可自行学习,本次东哥就介绍到这里。

pandas 官网文档:https://pandas.pydata.org/pan…

原创不易,感觉不错点个赞。

欢送关注我的集体公众号:Python 数据迷信

数据迷信学习网站:datadeepin

退出移动版