Uso de pandas y json_normalize para aplanar la respuesta API JSON anidada

votos
2

Tengo un JSON profundamente anidado que estoy tratando de convertirse en una trama de datos utilizando pandas json_normalize .

Una muestra genérica de los datos JSON que estoy trabajando con un aspecto se parece a esto (He añadido contexto de lo que estoy tratando de hacer en la parte inferior del post):

{
    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
    }
}

Me gustaría terminar con una trama de datos que contiene los question_id, page_id, RESPONSE_ID, y los datos de respuesta como esta:

    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

Puedo acercarme ejecutando el siguiente código (Python 3.6):

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

Que devuelve:

                                    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

Pero si trato de ejecutar json_normalize en un nido profundo y mantener los datos de los '' question_id partir del resultado anterior, sólo puedo obtener los valores page_id para volver, no verdaderos valores 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)

Devoluciones:

    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

Un factor de complicación puede ser que todo lo anterior (question_id, page_id, RESPONSE_ID) son 'id:' en los datos JSON.

Estoy seguro de que esto es posible, pero no puedo llegar allí. Ningún ejemplo de cómo hacer esto?

Un contexto adicional: Estoy tratando de crear una trama de datos de salida de respuesta de la API de SurveyMonkey .

Mi objetivo a largo plazo es volver a crear las todas las respuestas hoja de Excel que su servicio de exportación ofrece .

Planeo hacer esto consiguiendo la trama de datos de respuesta establecido (arriba), y luego usar .apply () para que coincida con las respuestas con su estructura de la encuesta de salida de API .

He encontrado la API de SurveyMonkey bastante mediocre en proporcionar una salida útil, pero soy nuevo en pandas por lo que es probable que en mí.

Publicado el 07/11/2018 a las 22:35
fuente por usuario
En otros idiomas...                            


2 respuestas

votos
4

Es necesario modificar el metaparámetro de su última opción, y, si desea cambiar el nombre de las columnas que ser exactamente de la manera deseada, se puede hacer con 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'})
Respondida el 13/11/2018 a las 00:58
fuente por usuario

votos
1

No hay manera de hacer esto de una manera completamente genérico utilizando json_normalize(). Puede utilizar las record_pathy metalos argumentos para indicar cómo desea que el JSON para ser procesada.

Sin embargo, se puede utilizar el paquete de aplanar para aplanar su JSON anidada y luego convertir eso a una trama de datos pandas. La página tiene el uso de ejemplo de cómo alisar un JSON están anidadas y convertir a una trama de datos pandas.

Respondida el 12/11/2018 a las 19:55
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more