【问题标题】:Converting nested JSON file with duplicate keys to dataframe in Python在Python中将具有重复键的嵌套JSON文件转换为数据框
【发布时间】:2019-07-06 18:45:16
【问题描述】:

假设以下 JSON 文件片段将在 Python 上展平。

{
  "locations" : [ {
    "timestampMs" : "1549913792265",
    "latitudeE7" : 323518421,
    "longitudeE7" : -546166813,
    "accuracy" : 13,
    "altitude" : 1,
    "verticalAccuracy" : 2,
    "activity" : [ {
      "timestampMs" : "1549913286057",
      "activity" : [ {
        "type" : "STILL",
        "confidence" : 100
      } ]
    }, {
      "timestampMs" : "1549913730454",
      "activity" : [ {
        "type" : "DRIVING",
        "confidence" : 100
      } ]
    } ]
  }, {
    "timestampMs" : "1549912693813",
    "latitudeE7" : 323518421,
    "longitudeE7" : -546166813,
    "accuracy" : 13,
    "altitude" : 1,
    "verticalAccuracy" : 2,
    "activity" : [ {
      "timestampMs" : "1549911547308",
      "activity" : [ {
        "type" : "ACTIVE",
        "confidence" : 100
      } ]
    }, {
      "timestampMs" : "1549912330473",
      "activity" : [ {
        "type" : "BIKING",
        "confidence" : 100
      } ]
    } ]
  } ]
}

我们的目标是把它变成一个扁平的数据框,像这样:

location_id timestampMs ... verticalAccuracy activity_timestampMs activity_activity_type ...
1           1549913792265   13               1549913286057        "STILL"
1           1549913792265   13               1549913730454        "DRIVING"
etc.

考虑到关键的“活动”在不同的嵌套级别重复,如何做到这一点?

【问题讨论】:

    标签: python json pandas dataframe


    【解决方案1】:

    这是一个使用json_normalize (documentation) 的解决方案,假设您发布的 JSON sn-p 在名为 d 的 python 字典中。

    from pandas.io.json import json_normalize
    
    # Build a list of paths to JSON fields that will end up as metadata
    # in the final DataFrame
    meta = list(js['locations'][0].keys())
    
    # meta is now this:
    # ['timestampMs',
    # 'latitudeE7',
    # 'longitudeE7',
    # 'accuracy',
    # 'altitude',
    # 'verticalAccuracy',
    # 'activity']
    
    # Almost correct. We need to remove 'activity' and append
    # the list ['activity', 'timestampMs'] to meta.
    meta.remove('activity')
    meta.append(['activity', 'timestampMs'])
    
    # meta is now this:
    # ['timestampMs',
    # 'latitudeE7',
    # 'longitudeE7',
    # 'accuracy',
    # 'altitude',
    # 'verticalAccuracy',
    # ['activity', 'timestampMs']]
    
    # Use json_normalize on the list of dicts
    # that lives at d['locations'], passing in
    # the appropriate record path and metadata
    # paths, and specifying the double 'activity_'
    # record prefix.
    json_normalize(d['locations'], 
                   record_path=['activity', 'activity'], 
                   meta=meta,
                   record_prefix='activity_activity_')
    
       activity_activity_confidence activity_activity_type    timestampMs  latitudeE7  longitudeE7  accuracy  altitude  verticalAccuracy activity.timestampMs
    0                           100                  STILL  1549913792265   323518421   -546166813        13         1                 2        1549913286057
    1                           100                DRIVING  1549913792265   323518421   -546166813        13         1                 2        1549913730454
    2                           100                 ACTIVE  1549912693813   323518421   -546166813        13         1                 2        1549911547308
    3                           100                 BIKING  1549912693813   323518421   -546166813        13         1                 2        1549912330473
    

    编辑

    如果['activity', 'activity']记录路径有时会丢失,上面的代码会抛出错误。以下解决方法应该适用于这种特定情况,但很脆弱,并且根据输入数据的大小可能会慢得令人无法接受:

    # Create an example by deleting one of the 'activity' paths 
    # from the original dict
    del d['locations'][0]['activity']
    
    pd.concat([json_normalize(x, 
                              record_path=['activity', 'activity'] 
                                          if 'activity' in x.keys() else None, 
                              meta=meta, 
                              record_prefix='activity_activity_') 
               for x in d['locations']], 
              axis=0, 
              ignore_index=True,
              sort=False)
    
       accuracy  altitude  latitudeE7  longitudeE7    timestampMs  verticalAccuracy  activity_activity_confidence activity_activity_type activity.timestampMs
    0        13         1   323518421   -546166813  1549913792265                 2                           NaN                    NaN                  NaN
    1        13         1   323518421   -546166813  1549912693813                 2                         100.0                 ACTIVE        1549911547308
    2        13         1   323518421   -546166813  1549912693813                 2                         100.0                 BIKING        1549912330473
    

    【讨论】:

    • 谢谢@Peter!将其标记为正确,因为它回答了我的问题并且有效!但是,在使用完整数据集时,我得到 KeyError: 'activity'。目前正在调查可能是什么问题。
    • 当我在 R 上导入 JSON 文件时,很容易发现问题。显然,并非所有“位置”都包含“活动”(即更高级别的“活动” - 它自动包含较低级别的“活动”)级别“活动”)。有什么想法吗?
    • @Deuterium,感谢您接受 - 有趣的后续问题。我已经在答案的底部编辑了一个可能的解决方案,但是我遇到了 JSON 经验的限制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2021-12-21
    • 1970-01-01
    • 2019-07-08
    • 2019-05-09
    相关资源
    最近更新 更多