Использование pandas и json_normalize для выравнивания вложенного ответа JSON API

У меня есть глубоко вложенный JSON, который я пытаюсь превратить в фрейм данных Pandas, используя json_normalize.

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

{
    "per_page": 2,
    "total": 1,
    "data": [{
            "total_time": 0,
            "collection_mode": "default",
            "href": "https://api.surveymonkey.com/v3/responses/5007154325",
            "custom_variables": {
                "custvar_1": "one",
                "custvar_2": "two"
            },
            "custom_value": "custom identifier for the response",
            "edit_url": "https://www.surveymonkey.com/r/",
            "analyze_url": "https://www.surveymonkey.com/analyze/browse/",
            "ip_address": "",
            "pages": [
                {
                    "id": "103332310",
                    "questions": [{
                            "answers": [{
                                    "choice_id": "3057839051"
                                }
                            ],
                            "id": "319352786"
                        }
                    ]
                },
                {
                    "id": "44783164",
                    "questions": [{
                            "id": "153745381",
                            "answers": [{
                                    "text": "some_name"
                                }
                            ]
                        }
                    ]
                },
                {
                    "id": "44783183",
                    "questions": [{
                            "id": "153745436",
                            "answers": [{
                                    "col_id": "1087201352",
                                    "choice_id": "1087201369",
                                    "row_id": "1087201362"
                                }, {
                                    "col_id": "1087201353",
                                    "choice_id": "1087201373",
                                    "row_id": "1087201362"
                                }
                                ]
                            }
                        ]
                }
            ],
            "date_modified": "1970-01-17T19:07:34+00:00",
            "response_status": "completed",
            "id": "5007154325",
            "collector_id": "50253586",
            "recipient_id": "0",
            "date_created": "1970-01-17T19:07:34+00:00",
            "survey_id": "105723396"
        }
    ],
    "page": 1,
    "links": {
        "self": "https://api.surveymonkey.com/v3/surveys/123456/responses/bulk?page=1&per_page=2"
    }
}

Я хотел бы получить фрейм данных, который содержит question_id, page_id, response_id и данные ответа, например:

    choice_id      col_id      row_id       text   question_id       page_id      response_id
0  3057839051         NaN         NaN        NaN     319352786     103332310       5007154325
1         NaN         NaN         NaN  some_name     153745381      44783164       5007154325
2  1087201369  1087201352  1087201362        NaN     153745436      44783183       5007154325
3  1087201373  1087201353  1087201362        NaN     153745436      44783183       5007154325

Я могу приблизиться, запустив следующий код (Python 3.6):

df = json_normalize(data=so_survey_responses['data'], record_path=['pages', 'questions'], meta='id', record_prefix ='question_')
print(df)

Что возвращает:

                                    question_answers question_id          id
0                      [{'choice_id': '3057839051'}]   319352786  5007154325
1                            [{'text': 'some_name'}]   153745381  5007154325
2  [{'col_id': '1087201352', 'choice_id': '108720...   153745436  5007154325

Но если я попытаюсь запустить json_normalize в более глубоком гнезде и сохранить данные «question_id» из приведенного выше результата, я смогу получить только возвращаемые значения page_id, а не истинные значения question_id:

answers_df = json_normalize(data=so_survey_responses['data'], record_path=['pages', 'questions', 'answers'], meta=['id', ['questions', 'id'], ['pages', 'id']])
print(answers_df)

Возвращает:

    choice_id      col_id      row_id       text          id questions.id   pages.id
0  3057839051         NaN         NaN        NaN  5007154325    103332310  103332310
1         NaN         NaN         NaN  some_name  5007154325     44783164   44783164
2  1087201369  1087201352  1087201362        NaN  5007154325     44783183   44783183
3  1087201373  1087201353  1087201362        NaN  5007154325     44783183   44783183

Усложняющим фактором может быть то, что все вышеперечисленные (question_id, page_id, response_id) являются «id:» в данных JSON.

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

Дополнительный контекст: я пытаюсь создать фрейм данных Вывод ответа SurveyMonkey API.

Моя долгосрочная цель — воссоздать таблицу Excel "все ответы", которую они экспортируют. сервис предоставляет.

Я планирую сделать это, настроив кадр данных ответа (см. выше), а затем используя .apply() для сопоставления ответов с их вывод API структуры опроса.

Я обнаружил, что API SurveyMonkey довольно тусклый в предоставлении полезного вывода, но я новичок в Pandas, поэтому, вероятно, это на мне.


person user2752159    schedule 07.11.2018    source источник
comment
Вам когда-нибудь удавалось форматировать ответы от Survey Monkey API таким образом, чтобы (даже отдаленно) они напоминали лист Excel из их службы экспорта? Если да, не могли бы вы спасти мою неделю, поделившись кодом?   -  person MajorBriggs    schedule 20.01.2019


Ответы (2)


Вам нужно изменить параметр meta вашего последнего параметра, и, если вы хотите переименовать столбцы именно так, как вы хотите, вы можете сделать это с помощью rename:

answers_df = json_normalize(data=so_survey_responses['data'],
                        record_path=['pages', 'questions', 'answers'],
                        meta=['id', ['pages', 'questions', 'id'], ['pages', 'id']])\
.rename(index=str,
        columns={'id': 'response_id', 'pages.questions.id': 'question_id', 'pages.id': 'page_id'})
person y.luis    schedule 13.11.2018

Невозможно сделать это полностью общим способом, используя json_normalize(). Вы можете использовать аргументы record_path и meta, чтобы указать, как вы хотите обрабатывать JSON.

Однако вы можете использовать flatten package, чтобы сгладить ваш глубоко вложенный JSON, а затем преобразовать его в фрейм данных Pandas. . На странице есть пример использования того, как сгладить глубоко вложенный JSON и преобразовать в кадр данных Pandas.

person Abhinav Sood    schedule 12.11.2018