【问题标题】:Using pandas and json_normalize to flatten nested JSON API response使用 pandas 和 json_normalize 扁平化嵌套的 JSON API 响应
【发布时间】:2019-04-11 10:35:56
【问题描述】:

我有一个深度嵌套的 JSON,我正在尝试使用 json_normalize 将其转换为 Pandas 数据框。

我正在使用的 JSON 数据的 generic sample 看起来像这样(我在帖子底部添加了我正在尝试做的事情的上下文):

{
    "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)在 JSON 数据中都是 'id:'。

我确信这是可能的,但我无法到达那里。如何做到这一点的任何例子?

其他上下文: 我正在尝试创建SurveyMonkey API response output 的数据框。

我的长期目标是重新创建"all responses" excel sheet that their export service provides

我计划通过设置响应数据框(上图)来做到这一点,然后使用.apply() 将响应与他们的survey structure API output 匹配。

我发现 SurveyMonkey API 在提供有用的输出方面相当乏善可陈,但我是 Pandas 的新手,所以它可能就在我身上。

【问题讨论】:

  • 您是否曾经成功地以某种方式(甚至是模糊地)类似于他们的导出服务中的 Excel 表来格式化来自 Survey Monkey API 的响应?如果是这样,你会通过分享代码来节省我的一周吗?

标签: python json pandas surveymonkey


【解决方案1】:

您需要修改最后一个选项的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'})

【讨论】:

    【解决方案2】:

    使用json_normalize() 无法以完全通用的方式执行此操作。您可以使用 record_pathmeta 参数来指示您希望如何处理 JSON。

    但是,您可以使用 flatten package 来展平深层嵌套的 JSON,然后将其转换为 Pandas 数据框。该页面有 example usage 说明如何将深度嵌套的 JSON 展平并转换为 Pandas 数据框。

    【讨论】:

      猜你喜欢
      • 2017-09-18
      • 2019-04-24
      • 1970-01-01
      • 2022-01-17
      • 1970-01-01
      • 2019-02-12
      • 1970-01-01
      • 1970-01-01
      • 2020-07-21
      相关资源
      最近更新 更多