pandas – leyendo múltiples registros JSON en el dataframe

Me gustaría saber si hay una forma eficiente de leer los archivos JSON de múltiples registros (cada línea es un dictado JSON) en un dataframe de pandas. A continuación se muestra un ejemplo de 2 líneas con solución de trabajo, lo necesito para un número potencialmente muy grande de registros. Un ejemplo de uso sería procesar la salida de la función JadoStorage de Hadoop Pig.

import json import pandas as pd test='''{"a":1,"b":2} {"a":3,"b":4}''' #df=pd.read_json(test,orient='records') doesn't work, expects [] l=[ json.loads(l) for l in test.splitlines()] df=pd.DataFrame(l) 

Nota: json separado por líneas ahora es compatible con read_json (desde 0.19.0):

 In [31]: pd.read_json('{"a":1,"b":2}\n{"a":3,"b":4}', lines=True) Out[31]: ab 0 1 2 1 3 4 

o con un archivo / ruta de acceso en lugar de una cadena json:

 pd.read_json(json_file, lines=True) 

Dependerá del tamaño de tus DataFrames, que es más rápido, pero otra opción es usar str.join para romper tu línea múltiple “JSON” (Nota: no es json válido), en json válido y usar read_json:

 In [11]: '[%s]' % ','.join(test.splitlines()) Out[11]: '[{"a":1,"b":2},{"a":3,"b":4}]' 

Para este pequeño ejemplo, esto es más lento, si alrededor de 100 es similar, las ganancias significativas si es más grande …

 In [21]: %timeit pd.read_json('[%s]' % ','.join(test.splitlines())) 1000 loops, best of 3: 977 µs per loop In [22]: %timeit l=[ json.loads(l) for l in test.splitlines()]; df = pd.DataFrame(l) 1000 loops, best of 3: 282 µs per loop In [23]: test_100 = '\n'.join([test] * 100) In [24]: %timeit pd.read_json('[%s]' % ','.join(test_100.splitlines())) 1000 loops, best of 3: 1.25 ms per loop In [25]: %timeit l = [json.loads(l) for l in test_100.splitlines()]; df = pd.DataFrame(l) 1000 loops, best of 3: 1.25 ms per loop In [26]: test_1000 = '\n'.join([test] * 1000) In [27]: %timeit l = [json.loads(l) for l in test_1000.splitlines()]; df = pd.DataFrame(l) 100 loops, best of 3: 9.78 ms per loop In [28]: %timeit pd.read_json('[%s]' % ','.join(test_1000.splitlines())) 100 loops, best of 3: 3.36 ms per loop 

Nota: de ese tiempo la unión es sorprendentemente rápida.

Si está tratando de ahorrar memoria, entonces leer el archivo una línea a la vez será mucho más eficiente en memoria:

 with open('test.json') as f: data = pd.DataFrame(json.loads(line) for line in f) 

Además, si import simplejson as json , las extensiones de C comstackdas incluidas con simplejson son mucho más rápidas que el módulo json Python puro.

A partir de Pandas 0.19, read_json tiene soporte nativo para JSON delimitado por líneas :

 pd.read_json(jsonfile, lines=True) 

++++++++ Update +++++++++++++++

A partir de v0.19, Pandas admite esto de forma nativa (consulte https://github.com/pandas-dev/pandas/pull/13351 ). Solo corre:

 df=pd.read_json('test.json', lines=True) 

++++++++ Respuesta anterior +++++++++++

Las respuestas existentes son buenas, pero para una pequeña variedad, esta es otra forma de lograr su objective que requiere un simple procesamiento previo fuera de python para que pd.read_json() pueda consumir los datos.

  • Instale jq https://stedolan.github.io/jq/ .
  • Cree un archivo json válido con cat test.json | jq -c --slurp . > valid_test.json cat test.json | jq -c --slurp . > valid_test.json
  • Cree el dataframe con df=pd.read_json('valid_test.json')

En el cuaderno de ipython, puede ejecutar el comando de shell directamente desde la interfaz de la celda con

 !cat test.json | jq -c --slurp . > valid_test.json df=pd.read_json('valid_test.json')