Flatten a JSON file in Pandas

I am trying to change a JSON file to a pandas DataFrame. I have tried a number of solution such as pd.jason_normalize(data.json) but it doesn't work.

The file appears to be more complex and has nested JSON data. How do I flatten this file so I can read the contents as a DataFrame?

Images are to give context on he structure

[![enter image description here][1]][1]

data = pd.read_json("papers.json")

>>>(Output)

data.head(5)


paper
0   {'id': 1, 'preliminary_decision': 'accept', 'r...
1   {'id': 2, 'preliminary_decision': 'accept', 'r...
2   {'id': 3, 'preliminary_decision': 'accept', 'r...
3   {'id': 4, 'preliminary_decision': 'accept', 'r...
4   {'id': 5, 'preliminary_decision': 'accept', 'r...

>>>(Output)

paper[0]

{'id': 1, 'preliminary_decision': 'accept', 'review': > [{'confidence': '4', 'evaluation': '1', 'id': 1, 'lan': 'es', > 'orientation': '0', 'remarks: '', 'text': '- El artículo aborda > un problema contingente y muy relevante, e incluye tanto un > diagnóstico nacional de uso de buenas prácticas como una solución > (buenas prácticas concretas). - El lenguaje es adecuado. - El > artículo se siente como la concatenación de tres artículos diferentes: > (1) resultados de una encuesta, (2) buenas prácticas de seguridad, (3) > incorporación de buenas prácticas. - El orden de las secciones sería > mejor si refleja este orden (la versión revisada es #2, #1, #3). - El > artículo no tiene validación de ningún tipo, ni siquiera por > evaluación de expertos.', 'timespan': '2010-07-05'},
> {'confidence': '4', 'evaluation': '1', 'id': 2, 'lan': 'es', > 'orientation': '1', 'remarks': '', 'text': 'El artículo presenta > recomendaciones prácticas para el desarrollo de software seguro. Se > describen las mejores prácticas recomendadas para desarrollar software > que sea proactivo ante los ataques, y se realiza un análisis de costos > de estas prácticas en desarrollo de software. Todo basado en una > revisión de prácticas propuestas en la bibliografía y su contraste con > datos obtenidos de una encuesta en empresas. Finalmente se recomienda > una guía. Sería ideal aplicar la guía propuesta a empresas no > involucradas en la encuesta que sirvió para originarla de modo de > poder evaluar su efectividad en forma independiente.', 'timespan': > '2010-07-05'}, {'confidence': '5', 'evaluation': '1', 'id': 3, > 'lan': 'es', 'orientation': '1', 'remarks': '', 'text': '- El > tema es muy interesante y puede ser de mucha ayuda una guía para > incorporar prácticas de seguridad. - La presentación (descripción, > etapa y uso) de las 9 prácticas para el desarrollo de software seguro. > - El “estado real del desarrollo de software en Chile” (como lo indica en su paper) no se puede lograr con solamente 22 encuestas de un total > de 50. - Presenta nueve tablas que corresponden a las prácticas para > el desarrollo de software seguro, pero la guía presenta 10 prácticas. > ¿explica por qué? - Sugiero mejorar la guía, el mayor aporte está en > la secuencia de incorporación que propone. Además, no debería > explicar la práctica en Observaciones ni diferenciarla con otras > prácticas en esa columna, sino que debería dar sugerencias de cómo > aplicarla. - En el texto indica “Más adelante, se presentan además > tres prácticas extras…” ¿cuáles son o no leí correctamente? - De > acuerdo a formato, poner como mínimo 5 palabras clave. - Sugiero > mencionar las prácticas antes de mostrar cada tabla. - Algunas > referencias están incompletas, por ejemplo, falta año en referencia > 17, falta año y tipo de evento en referencia 11, falta editorial en > referencia 19 (¿es un libro?) - Algunos títulos llevan una coma dentro > de las comillas, ejemplo, referencia 1', 'timespan': > '2010-07-05'}]}

( Expected Output)

[ id, preliminary_decision, review, confidence, evaluation, id, lan, orientation, remarks, text, timespan']


Solution 1:

You can use some parameters to json_normalize to achieve what you like to get.

Assuming data is a dataframe and you have JSON object in paper column.

pd.json_normalize(data.paper, record_path=['review'], meta=['id', 'preliminary_decision'], meta_prefix='paper.') 

You need to use either record_prefix or meta_prefix to avoid conflicts of columns, since you have id in root and within review array.

Solution 2:

Similar question here

But in your case you only want the last key to be considered

def flatten_data(data):
    out = {}

    def flatten(x, name=''):
        if type(x) is dict:
            for a in x:
                flatten(x[a], a)
        elif type(x) is list:
            i = 0
            for i,a in enumerate(x):
                flatten(a, i)
        else:
            out[name] = x
    flatten(data);
    return out

df = pd.DataFrame([flatten(y) for y in data]);