Большой вложенный json в pandas dataframe python

У меня есть большой вложенный объект json, который я хотел бы прочитать в кадре данных pandas. Объект json имеет внутри много вложенных пар json. Базовое наслоение это:

  • Метаданные вызовов API (мне на это наплевать)
  • Метаданные ответов на опрос (я бы хотел, чтобы эта информация была включена в окончательный результат)
  • Страницы (страницы опросов с идентификационным номером и вопросами на этой странице)
  • Вопросы (quest_id и соответствующие response_id из вопросов)

Образец выглядит следующим образом:

{
    "per_page": 50,
    "total": 4,
    "data": [
        {
            "total_time": 5276,
            "href": "https://somelink.com",
            "custom_variables": {},
            "ip_address": "XXX.XXX.XX.XX",
            "id": "1111111",
            "logic_path": {},
            "date_modified": "2018-08-17T19:57:43+00:00",
            "response_status": "completed",
            "custom_value": "",
            "analyze_url": "https://somelink.com/respondent_id=1111111",
            "pages": [
                {
                    "id": "38638937",
                    "questions": []
                },
                {
                    "id": "38638938",
                    "questions": [
                        {
                            "id": "124810659",
                            "answers": [
                                {
                                    "text": "some_answer_text"
                                }
                            ]
                        },
                        {
                            "id": "124810660",
                            "answers": [
                                {
                                    "text": "some_other_answer_text"
                                }
                            ]
                        }
                    ]
                },
                {
                    "id": "38638944",
                    "questions": [
                        {
                            "id": "124810656",
                            "answers": [
                                {
                                    "col_id": "905794209",
                                    "choice_id": "905794459",
                                    "row_id": "905794204"
                                },
                                {
                                    "col_id": "905794210",
                                    "choice_id": "905794463",
                                    "row_id": "905794204"
                                },
                                {
                                    "col_id": "905794209",
                                    "choice_id": "905794459",
                                    "row_id": "905794205"
                                },
                                {
                                    "col_id": "905794210",
                                    "choice_id": "905794464",
                                    "row_id": "905794205"
                                }
                            ]
                        }
                    ]   
                }
                .
                .
                .
                .
                .
                .
                .
                .
            ],
            "page_path": [],
            "recipient_id": "4107168056",
            "collector_id": "216279750",
            "date_created": "2018-09-05T15:28:38+00:00",
            "survey_id": "222222222",
            "collection_mode": "default",
            "edit_url": "https://www.somelink.com/somerefnumber",
            "metadata": {
                "contact": {
                    "email": {
                        "type": "string",
                        "value": "[email protected]"
                    }
                }
            }
        },
        {
            "total_time": 6978,
            "href": "https://somelink.com",
            "custom_variables": {},
            "ip_address": "XXX.XXX.XX.XX",
            "id": "4444444",
            "logic_path": {},
            "date_modified": "2018-08-15T19:16:43+00:00",
            "response_status": "completed",
            "custom_value": "",
            "analyze_url": "https://somelink.com/respondent_id=4444444",
            "pages": [
                    .
                    .
                    .

            ]
        }

    ],
    "page": 1,
    "links": {
        "self": "https://api.somelink.com/22222222/responses/bulk?page=1&per_page=50"
    }
}

На странице может быть любое количество ответов, страниц и вопросов.

Мой вопрос: как я могу получить приведенный выше json в базу данных pandas, которая выглядит следующим образом: Форматированный фрейм данных Pandas (как excel для справки)

Я пытался использовать json_normalize, но я считаю, что делаю некоторые ошибки.

import pandas as pd
import requests
from pandas.io.json import json_normalize

headers={"Authorization": "Bearer %s" % MY_ACCESS_TOKEN,
                           "Content-Type": "application/json"}

url = "https://api.surveymonkey.com/v3/surveys/%s/responses/bulk" % (my_survey_id)
response = requests.get(url, headers=headers)
responses = response.json()

pages_data = json_normalize(data=responses['data'], record_path='pages', meta=['response_status', 'recipient_id', 'collector_id', 'survey_id', 'date_created', 'date_modified', 'ip_address', 'href', 'total_time'])
print(pages_data.head(10))
pages_data.to_csv("output.csv")

В качестве дополнительной информации это взято из API SurveyMonkey< /а>. SurveyMonkey позволяет экспортировать результаты опроса в csv через веб-интерфейс, но Я хотел бы использовать API для воссоздания стандартного отчета об ответах и, в конечном итоге, создания пользовательских отчетов/выполнения других действий.

Я использую python3.6. Я предполагаю, что мне нужно выполнить некоторую предварительную обработку, чтобы сгладить данные, но я не уверен, как это сделать. Любая помощь приветствуется!


person user2752159    schedule 29.10.2018    source источник
comment
если json всегда в одном и том же формате, не могли бы вы взять нужные вам значения, поместить их в список (или другой формат), а затем создать оттуда кадр данных?   -  person MattR    schedule 29.10.2018
comment
@MattR, JSON будет отличаться в зависимости от опроса. Я хотел бы программно сгладить JSON независимо от структуры опроса. Если бы я знал структуру опроса, я мог бы попытаться вручную извлечь значения в список. У вас есть фрагменты кода, которые могли бы помочь в этом?   -  person user2752159    schedule 30.10.2018
comment
вы можете думать о JSON как о словарях, поэтому все, что будет сглаживать словари (например, возможно, этот пост поможет вам.   -  person MattR    schedule 30.10.2018


Ответы (2)


Вот способ сгладить вложенный словарь в pandas с помощью glom. Цель состоит в том, чтобы извлечь выбранные ключи и значения из вложенного словаря и сохранить их в отдельном столбце фрейма данных pandas (:

Вот пошаговое руководство: https://medium.com/@enrico.alemani/flatten-nested-dictionaries-in-pandas-using-glom-7948345c88f5

import pandas as pd
from glom import glom
from ast import literal_eval


target = {
    "page": 10,
    "total": 100,
    "data":
        {
            "total_time": 100,
            "href": "https://mylink.com",
            "ip_address": "000.00.00.00",
            "id": "012345",
            "response_status": "completed",
        }
}

# Import data
df = pd.DataFrame([str(target)], columns=['target'])

# Extract id keys and save value into a separate pandas column
df['id'] = df['target'].apply(lambda row: glom(literal_eval(row), 'data.id'))
person iEriii    schedule 23.06.2020

Преобразуйте свой json в фреймворк данных:

df = pd.DataFrame(json)

после:

df = df.to_csv(file, sep='\t')
person Jose Salas    schedule 29.10.2018
comment
Кажется, это не совсем соответствует тому, что ищет OP. - person d_kennetz; 30.10.2018