Чтение нескольких записей JSON в фрейм данных Pandas
Я хотел бы знать, есть ли эффективный способ чтения памяти многозадачного файла JSON (каждая строка - JSON dict) в фреймворк pandas. Ниже приведен пример с двумя строками с рабочим решением, мне это нужно для потенциально очень большого количества записей. Примером использования будет обработка вывода из функции Hadoop Pig JSonStorage.
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)
Ответы
Ответ 1
Примечание: теперь read_json
строкой json поддерживается в read_json
(начиная с 0.19.0):
In [31]: pd.read_json('{"a":1,"b":2}\n{"a":3,"b":4}', lines=True)
Out[31]:
a b
0 1 2
1 3 4
или с файлом /filepath, а не строкой json:
pd.read_json(json_file, lines=True)
Это будет зависеть от размера ваших DataFrames, что быстрее, но другой вариант - использовать str.join
чтобы разбить вашу многострочную строку "JSON" (Примечание: это не допустимый json), в допустимый json и использовать read_json:
In [11]: '[%s]' % ','.join(test.splitlines())
Out[11]: '[{"a":1,"b":2},{"a":3,"b":4}]'
Для этого крошечного примера это медленнее, если около 100 это аналогично, значительный выигрыш, если он больше...
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
Примечание: в то время соединение было на удивление быстрым.
Ответ 2
Если вы пытаетесь сохранить память, то при чтении файла строка за раз будет намного более эффективной с точки зрения памяти:
with open('test.json') as f:
data = pd.DataFrame(json.loads(line) for line in f)
Кроме того, если вы import simplejson as json
, скомпилированные расширения C, включенные в simplejson
, намного быстрее, чем модуль pure-Python json
.
Ответ 3
Как и в Pandas 0.19, read_json
имеет встроенную поддержку JSON с разделителями строк:
pd.read_json(jsonfile, lines=True)
Ответ 4
++++++++ Update ++++++++++++++
Начиная с v0.19, Pandas поддерживает это изначально (см. https://github.com/pandas-dev/pandas/pull/13351). Просто запустите:
df=pd.read_json('test.json', lines=True)
++++++++ Старый ответ ++++++++++
Существующие ответы хороши, но для небольшого разнообразия, вот еще один способ достижения вашей цели, для которой требуется простой шаг предварительной обработки за пределами python, чтобы pd.read_json()
мог потреблять данные.
- Установите jq https://stedolan.github.io/jq/.
- Создайте действительный файл json с
cat test.json | jq -c --slurp . > valid_test.json
- Создайте фрейм с
df=pd.read_json('valid_test.json')
В записной книжке ipython вы можете запустить команду оболочки непосредственно из интерфейса ячейки с помощью
!cat test.json | jq -c --slurp . > valid_test.json
df=pd.read_json('valid_test.json')