【问题标题】:Protect a nested object against flattening when using pandas.json_normalize使用 pandas.json_normalize 时保护嵌套对象不被展平
【发布时间】:2021-06-11 03:17:42
【问题描述】:

在 pandas >= 1.1.4 / Python 3 中,我想保护嵌套元素在使用 json_normalize() 时不被展平。

我无法在文档中弄清楚这样的事情。

实际示例

这里有一个具体的例子来说明主要思想:

res='''
    {
      "results": [
        {
          "geometry": {
            "type": "Polygon",
            "crs": 4326,
            "coordinates": 
              [[
                  [6.0, 49.0],
                  [6.0, 40.0],
                  [7.0, 40.0],
                  [7.0, 49.0],
                  [6.0, 49.0]
              ]]
          },
          "attribute": "layer.metadata",
          "bbox": [6, 40, 7, 49],
          "featureName": "Coniferous_Trees",
          "layerName": "State_Forests",
          "type": "Feature",
          "id": "17",
          "properties": {
            "resolution": "100",
            "Year": "2020",
            "label": "Coniferous"
          }
        }
      ]
    }
'''

这是来自 API 响应的单个 JSON 记录。在这里,顶级列表中只有一个元素,但还有更多,每个元素都遵循与此处所示相同的结构。我想将它导入到DataFrame 没有包含结构化元素的列,即,我想将它们全部展平/规范化。嗯,……几乎所有。 json_normalize() 在这方面做得非常出色:

import pandas as pd

data = json.loads(res)['results']
df = pd.DataFrame(pd.json_normalize(data))

以下是 DataFrame 的列:

>>> print(df.columns)
Index(['attribute', 'bbox', 'featureName', 'layerName', 'type', 'id',
       'geometry.type', 'geometry.crs', 'geometry.coordinates', # <-- the geometry has been flattened
       'properties.resolution', 'properties.Year', 'properties.label'],
      dtype='object')

想要的行为

但是我需要,比如说,“保护”输入 JSON 响应中的 geometry 对象以防止展平,以便我最终得到这些列:

# e.g. something like this:
df = pd.DataFrame(pd.json_normalize(data, protect="results.geometry"))
# or this if there isn't two objects with the same name:
df = pd.DataFrame(pd.json_normalize(data, protect="geometry"))

这会导致:

>>> print(df.columns)

Index(['attribute', 'bbox', 'featureName', 'layerName', 'type', 'id',
       'geometry', 'properties.resolution', # <-- the geometry element has been protected!
       'properties.Year', 'properties.label'],
      dtype='object')

有没有办法正确地做到这一点?

【问题讨论】:

    标签: python-3.x pandas dataframe json-normalize


    【解决方案1】:

    考虑max_level=0。每pandas.json_normalize docs

    max_level : int,默认无
    要标准化的最大级别数(字典深度)。如果没有,则归一化所有级别。

    data = json.loads(response)["results"]
    df = pd.DataFrame(pd.json_normalize(data, max_level=0))
    
    print(df.T)
    #                                                              0
    # geometry     {'type': 'Polygon', 'crs': 4326, 'coordinates'...
    # attribute                                       layer.metadata
    # bbox                                            [6, 40, 7, 49]
    # featureName                                   Coniferous_Trees
    # layerName                                        State_Forests
    # type                                                   Feature
    # id                                                          17
    # properties   {'resolution': '100', 'Year': '2020', 'label':...
    
    print(df.columns)
    # Index(['geometry', 'attribute', 'bbox', 'featureName', 'layerName', 'type', 'id', 
    #        'properties'], dtype='object')
    

    而且由于所有嵌套对象都未标准化,因此请使用数据整理来展开所需的列,例如 properties

    df = (
           df.drop(['properties'], axis="columns")
             .join(df["properties"].dropna().apply(pd.Series))
         )
    
    
    print(df.T)
    #                                                              0
    # geometry     {'type': 'Polygon', 'crs': 4326, 'coordinates'...
    # attribute                                       layer.metadata
    # bbox                                            [6, 40, 7, 49]
    # featureName                                   Coniferous_Trees
    # layerName                                        State_Forests
    # type                                                   Feature
    # id                                                          17
    # resolution                                                 100
    # Year                                                      2020
    # label                                               Coniferous
    
    print(df.columns)
    # Index(['geometry', 'attribute', 'bbox', 'featureName', 'layerName', 'type', 'id',
    #        'resolution', 'Year', 'label'], dtype='object')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-24
      • 2017-10-19
      • 2017-07-02
      • 2020-12-22
      • 2021-06-09
      • 1970-01-01
      • 2019-01-26
      • 2020-01-21
      相关资源
      最近更新 更多