Защитите вложенный объект от сглаживания при использовании pandas.json_normalize

В 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"
          }
        }
      ]
    }
'''

Это отдельная запись JSON из ответа API. Здесь есть только один элемент в списке верхнего уровня, но их может быть больше, каждый из которых имеет ту же структуру, что и показанный здесь. Я хотел бы импортировать это в DataFrame без столбцов, содержащих структурированный элемент, а именно, я хочу сгладить / нормализовать их все. Ну ... почти все. json_normalize() отлично справляется с этим:

      import pandas as pd

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

А вот столбцы DataFrame:

      >>> print(f.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')

Разыскиваемое поведение

Но мне нужно, скажем так, «защитить» geometry объект во входном ответе JSON против сглаживания, так что вместо этого я получаю эти столбцы:

      # 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')

Есть ли способ сделать это правильно?

1 ответ

Учитывать max_level=0. За<strong> <tcode id="6180976"></tcode></strong>документы :

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')
Другие вопросы по тегам