Элегантное преобразование json в фрейм данных pandas (без циклов for)

#python #json #pandas

#python #json #pandas

Вопрос:

Я пытаюсь разобрать JSON в фрейм данных pandas

Вот мой json:

 In [1]: data
Out[1]: 
[
  {
    "field_1": {
      "key1": value1,
      "key2": value2
    },
    "field_2": {
      "key1": value3,
      "key2": value4
    },
    "data_A": [
      {
        "key1": value5,
        "key2": value6
      },
      {
        "key1": value7,
        "key2": value8
      }
    ]
    "data_B": [
      {
        "key1": value9,
        "key2": value10
      }
    ]
  },
  {
    "field_1": {
      "key1": value11,
      "key2": value12
    },
    "field_2": {
      "key1": value13,
      "key2": value14
    },
    "data_B": [
      {
        "key1": value15,
        "key2": value16
      },
      {
        "key1": value17,
        "key2": value18
      }
    ]
  },
  ... 
]
  

Как вы можете видеть, каждый мой объект в data содержит field_1 и field_2. Он также содержит либо data_A, либо data_B (по крайней мере, один из двух). data_A, когда он существует, представляет собой список из одного или нескольких элементов, а data_B, когда он существует, представляет собой список из одного или нескольких элементов.

Чего бы я хотел, так это следующего результата:

 In [2]: df_A
Out[2]: 
   data_A.key1  data_A.key2  field_1.key_1  field_1.key_2  field_2.key_1  field_2.key_2
0       value5       value6         value1         value2         value3         value4 
1       value7       value8         value1         value2         value3         value3
...

In [3]: df_B
Out[3]: 

   data_B.key1  data_B.key2  field_1.key_1  field_1.key_2  field_2.key_1  field_2.key_2
0       value9      value10         value1         value2         value3         value4
1      value15      value16        value11        value12        value13        value14
2      value17      value18        value11        value12        value13        value14
...

  

Я могу сделать это с помощью циклов for, но есть ли более эффективный и элегантный способ?

Ответ №1:

Если вы используете Linux или Mac с Python 3.6 , вы можете использовать библиотеку (bamboo), которую я написал для преобразования вложенных данных (например, JSON) в Pandas. Если вы работаете в Windows или используете другую версию Python, но все еще заинтересованы в библиотеке, дайте мне знать, и я посмотрю, смогу ли я создать более переносимую версию.

Вы можете установить bamboo из pypi: pip install bamboo-nested

Преобразование полностью выполняется в расширении C и numpy, поэтому оно должно быть очень производительным.

Вот как это будет работать с предоставленным вами JSON (я внес несколько небольших изменений, чтобы сделать его допустимым примером JSON):

 s = '''
[
    {
        "field_1": {
            "key1": "value1",
            "key2": "value2"
        },
        "field_2": {
            "key1": "value3",
            "key2": "value4"
        },
        "data_A": [
            {
                "key1": "value5",
                "key2": "value6"
            },
            {
                "key1": "value7",
                "key2": "value8"
            }
        ],
        "data_B": [
            {
                "key1": "value9",
                "key2": "value10"
            }
        ]
    },
    {
        "field_1": {
            "key1": "value11",
            "key2": "value12"
        },
        "field_2": {
            "key1": "value13",
            "key2": "value14"
        },
        "data_B": [
            {
                "key1": "value15",
                "key2": "value16"
            },
            {
                "key1": "value17",
                "key2": "value18"
            }
        ]
    }
]
'''

from bamboo import from_json
tree = from_json(s)
df_A = tree.flatten(exclude=[tree.data_B])  # you can also refer to pieces of the tree with string names, i.e. "exclude=['data_B']"
df_B = tree.flatten(exclude=[tree.data_A])
print(df_A)
print(df_B)
  

Полученный результат является:

   data_A_key1 data_A_key2 field_1_key1 field_1_key2 field_2_key1 field_2_key2
0      value5      value6       value1       value2       value3       value4
1      value7      value8       value1       value2       value3       value4
  data_B_key1 data_B_key2 field_1_key1 field_1_key2 field_2_key1 field_2_key2
0      value9     value10       value1       value2       value3       value4
1     value15     value16      value11      value12      value13      value14
2     value17     value18      value11      value12      value13      value14
  

Это не совсем то, что вы просили, но очень близко (по умолчанию для создания имен столбцов используются символы подчеркивания). Вы можете изменить название столбца, передав другое в параметр «name_strategy» параметра «flatten». В настоящее время у меня нет возможности изменить разделитель имен столбцов по умолчанию, но я могу добавить это.

Я надеюсь, это поможет!

Комментарии:

1. Вы также можете использовать Pandas напрямую, чтобы получить нечто подобное, но вы должны быть очень конкретны в отношении столбцов, которые вы хотите включить. Вам также понадобятся пустые значения для отсутствующих ключей (например, «data_A»: [] во второй записи). print(json_normalize(json.loads(s), 'data_B', [['field_1', 'key1'], ['field_1', 'key2'], ['field_2', 'key1'], ['field_2', 'key2']])) print(json_normalize(json.loads(s), 'data_A', [['field_1', 'key1'], ['field_1', 'key2'], ['field_2', 'key1'], ['field_2', 'key2']])) bamboo должен быть быстрее и проще для изучения данных, но, возможно, подхода Pandas достаточно.