Инструменты Pandas для работы с JSON
Основные подходы к работе с JSON в Pandas
Как наиболее эффективно загрузить JSON данные в Pandas DataFrame?
Библиотека Pandas предоставляет встроенную функцию read_json(), которая позволяет напрямую считывать JSON из строки, файла или URL, автоматически преобразуя его в DataFrame. Это предпочтительный способ, так как он оптимизирован и обрабатывает различные ориентации данных (например, records, columns, index).
import pandas as pd
# Пример JSON строки в формате records (список словарей)
json_data = '[{"name":"Alice","age":25},{"name":"Bob","age":30}]'
df = pd.read_json(json_data)
print(df)Pandas python json (работа с json в pandas)
name age 0 Alice 25 1 Bob 30
Для вложенных JSON рекомендуется использовать json_normalize() из модуля pandas.json. Эта функция распаковывает вложенные объекты в плоские таблицы.
from pandas import json_normalize
data = [
{"id": 1, "info": {"city": "Moscow", "zip": 101000}},
{"id": 2, "info": {"city": "SPb", "zip": 190000}}
]
df_flat = json_normalize(data, sep='_')
print(df_flat)
id info_city info_zip 0 1 Moscow 101000 1 2 SPb 190000
При использовании read_json() возможна ошибка ValueError, если строковый JSON не является корректным или ориентация не соответствует ожидаемой. Решение: проверить JSON валидатором (json.loads() перед передачей) и указать параметр orient явно.
Как загрузить JSON из файла с нестандартным расширением или сжатием?
Функция read_json() поддерживает сжатые файлы (gzip, bz2, xz) автоматически, если расширение соответствует. Если файл имеет другое расширение, можно указать compression.
df = pd.read_json('data.json.gz') # автоматическое распознавание
# или явно
df = pd.read_json('data.custom', compression='gzip')
При попытке прочитать файл с неизвестным сжатием возникает ValueError: Unrecognized compression type. Решение: распаковать файл вручную перед чтением.
Каким образом обработать JSON с произвольной структурой (например, с пропусками)?
Для нерегулярных структур можно сначала прочитать всё как Python объект через json.loads(), а затем с помощью pd.json_normalize() с параметрами record_path и meta извлечь нужные вложенные списки и метаданные.
import json
raw = '{"users":[{"name":"Ivan","scores":[10,20]},{"name":"Petr","scores":[15]}],"date":"2023"}'
dict_data = json.loads(raw)
df_users = json_normalize(
data=dict_data['users'],
record_path='scores', # список значений для развертывания
meta=['name'] # поля, остающиеся в каждой строке
)
print(df_users)
0 name 0 10 Ivan 1 20 Ivan 2 15 Petr
Если record_path отсутствует в отдельных записях, возникнет KeyError. Решение: предусмотреть проверку наличия ключа или использовать errors='ignore' при разборе.
Как сохранить DataFrame обратно в JSON в определённом формате?
Метод to_json() позволяет экспортировать DataFrame в JSON строку или файл, выбирая ориентацию (records, columns, index, split и др.) Дополнительно можно настроить сжатие, формат дат, кодировку.
df = pd.DataFrame({'A': [1,2], 'B': [3,4]})
df.to_json('output.json', orient='records', date_format='iso')
При записи с ориентацией 'records' в файл не сохраняется информация об индексе. Если индекс важен, следует использовать 'index' или добавить его как столбец.
Расширенные примеры работы с JSON в Pandas
Чтение очень больших JSON файлов с построчной обработкой
Когда JSON содержит огромное количество записей, загрузка всего файла может привести к нехватке памяти. Можно читать файл построчно, если он представляет собой NDJSON (Newline Delimited JSON) - каждая строка - отдельный JSON объект.
import pandas as pd
import json
chunks = []
with open('large_ndjson.json', 'r') as f:
for line in f:
if line.strip():
obj = json.loads(line)
chunks.append(obj)
df = pd.DataFrame(chunks)
print(df.shape)
Для ещё большей экономии памяти применяется библиотека ijson, которая парсит поток без полной загрузки.
import ijson
import pandas as pd
records = []
with open('huge.json', 'r') as f:
parser = ijson.parse(f)
for prefix, event, value in parser:
if (prefix, event) == ('item', 'map_key'):
# настройка извлечения
pass
# ... сборка DataFrame
Преобразование вложенных JSON с несколькими уровнями
Рассмотрим структуру с вложенными массивами объектов и метаданными на разных уровнях.
data = [
{
"order": 1,
"items": [
{"product": "phone", "qty": 1},
{"product": "case", "qty": 2}
],
"customer": {"name": "John", "loyalty": "gold"}
},
{
"order": 2,
"items": [
{"product": "laptop", "qty": 1}
],
"customer": {"name": "Jane", "loyalty": "silver"}
}
]
df_items = json_normalize(
data,
record_path='items',
meta=['order', ['customer', 'name'], ['customer', 'loyalty']]
)
print(df_items)
product qty order customer.name customer.loyalty 0 phone 1 1 John gold 1 case 2 1 John gold 2 laptop 1 2 Jane silver
Кастомная сериализация объектов datetime
При сохранении DataFrame с датами в JSON можно задать формат с помощью параметра date_format. Если требуется нестандартное представление, используется default_handler.
import datetime
df = pd.DataFrame({'date': [datetime.date(2024,1,1), datetime.date(2024,6,15)]})
json_str = df.to_json(orient='records', date_format='iso', default_handler=str)
print(json_str)
[{"date":"2024-01-01"},{"date":"2024-06-15"}]
Обработка JSON с пропущенными ключами и разными типами
Иногда в JSON могут отсутствовать некоторые поля или типы различаются. Через pd.json_normalize() пропуски заполняются NaN, а разные типы можно привести явно после загрузки.
json_mixed = '[{"a": 1, "b": "text"}, {"a": 2}, {"b": 3}]'
df_mixed = pd.read_json(json_mixed)
print(df_mixed.dtypes)
# a - float64, b - object
# Приведение типов
df_mixed['a'] = df_mixed['a'].astype('Int64')
df_mixed['b'] = pd.to_numeric(df_mixed['b'], errors='coerce')
print(df_mixed)
a b 0 1 text 1 2 NaN 2 NaN 3
Экспорт с сохранением иерархии (вложенные JSON)
Используя группировку и to_dict(), можно создать вложенный JSON из плоского DataFrame.
df = pd.DataFrame({
'city': ['Moscow', 'Moscow', 'SPb'],
'product': ['A', 'B', 'A'],
'sales': [100, 200, 150]
})
result = df.groupby('city').apply(lambda x: x[['product','sales']].to_dict('records')).to_dict()
import json
print(json.dumps(result, ensure_ascii=False, indent=2))
{
"Moscow": [
{"product": "A", "sales": 100},
{"product": "B", "sales": 200}
],
"SPb": [
{"product": "A", "sales": 150}
]
}