Как прочитать JSON в pandas
Карьерник — квиз-тренажёр в Telegram с 1500+ вопросами для собесов аналитика. SQL, Python, A/B, метрики. Бесплатно.
Зачем это нужно
JSON — формат номер один для данных от API, event logs, NoSQL баз. Выгружаете из Amplitude / Mixpanel / Yandex Metrika → получаете JSON. API партнёра → JSON. Webhook-лог → JSON. Чтобы работать с этим в pandas — нужно уметь правильно парсить, учитывая разные orient-форматы и вложенные структуры.
Вложенный JSON — отдельная история. В колонке payload лежит структура {"user": {"name": ..., "email": ...}, "items": [...]}. Обычный read_json оставит это как dict в колонке — неудобно для анализа. json_normalize разворачивает вложенность в плоский DataFrame с колонками user.name, user.email и т.д.
В статье — все частые случаи:
read_jsonс разнымиorient(records, columns, index, values)- NDJSON (JSON Lines) — формат logs
json_normalizeдля вложенных структур и массивов- Парсинг JSON-колонки в существующем DataFrame
- Из API через
requests.get().json() - Чтение больших файлов чанками
- Работа с сложными вложенными структурами через
json.load
Базовое чтение
import pandas as pd
# из файла
df = pd.read_json('data.json')
# из строки
df = pd.read_json('{"a": [1, 2, 3], "b": [4, 5, 6]}')1. Orient (ориентация JSON)
JSON может быть по-разному структурирован. pandas понимает разные варианты через параметр orient.
records (самое частое)
[
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
]df = pd.read_json('data.json', orient='records')Это default, если JSON — массив объектов.
columns
{
"name": ["Alice", "Bob"],
"age": [30, 25]
}df = pd.read_json('data.json', orient='columns')index
{
"0": {"name": "Alice", "age": 30},
"1": {"name": "Bob", "age": 25}
}df = pd.read_json('data.json', orient='index')values
[[1, 2], [3, 4]]df = pd.read_json('data.json', orient='values')2. NDJSON / JSON Lines
Когда каждая строка файла — отдельный JSON-объект:
{"name": "Alice", "age": 30}
{"name": "Bob", "age": 25}
{"name": "Carol", "age": 35}Читается так:
df = pd.read_json('data.ndjson', lines=True)Популярный формат для логов и big data (каждая строка можно обработать отдельно).
3. Вложенный JSON — json_normalize
Для структур с вложенностью:
{
"data": [
{
"id": 1,
"user": {
"name": "Alice",
"email": "alice@example.com"
},
"amount": 100
},
...
]
}import json
with open('data.json') as f:
raw = json.load(f)
df = pd.json_normalize(raw['data'])
# колонки: id, user.name, user.email, amount4. json_normalize с record_path
Если вложенные массивы нужно «развернуть»:
[
{
"order_id": 1,
"items": [
{"product": "A", "qty": 2},
{"product": "B", "qty": 1}
]
}
]df = pd.json_normalize(
data,
record_path='items',
meta=['order_id']
)
# колонки: product, qty, order_id5. Из API
import requests
r = requests.get('https://api.example.com/users')
data = r.json()
df = pd.DataFrame(data)
# или
df = pd.json_normalize(data)6. Из столбца с JSON в DataFrame
Если у вас DataFrame, где одна колонка — JSON-строка:
import json
df['parsed'] = df['json_col'].apply(json.loads)
# извлечь поле
df['user_name'] = df['parsed'].apply(lambda d: d.get('user', {}).get('name'))
# или через json_normalize
parsed = pd.json_normalize(df['parsed'])
df = pd.concat([df, parsed], axis=1)7. Из больших файлов — чанками
# chunksize работает только с lines=True
chunks = pd.read_json('big.ndjson', lines=True, chunksize=10000)
for chunk in chunks:
process(chunk)8. Обработка ошибок
try:
df = pd.read_json('data.json')
except ValueError as e:
print(f"JSON parse error: {e}")Частые причины:
- Плохой JSON (неверные кавычки, trailing comma)
- Разная структура в строках
- Encoding (не UTF-8)
9. Гибкость: сначала json.load, потом DataFrame
Когда структура сложная — парсить отдельно:
import json
with open('complex.json') as f:
data = json.load(f)
# своя логика извлечения
rows = []
for item in data:
rows.append({
'id': item['id'],
'user_name': item['user']['name'],
'total': sum(i['price'] for i in item['items'])
})
df = pd.DataFrame(rows)10. Сохранение обратно
df.to_json('output.json', orient='records', force_ascii=False)
# с красивым форматированием
df.to_json('output.json', orient='records', indent=2, force_ascii=False)
# NDJSON
df.to_json('output.ndjson', orient='records', lines=True, force_ascii=False)force_ascii=False для корректных русских букв.
Частые ошибки
1. Wrong orient
# падает с ошибкой
pd.read_json('records-style.json') # default orient='columns'Правильно:
pd.read_json('records-style.json', orient='records')2. Вложенные данные не развернулись
read_json может оставить dict'ы в колонках. Используйте json_normalize.
3. lines=True для обычного JSON
# падает
pd.read_json('normal.json', lines=True) # ожидает NDJSON4. Кодировка
JSON должен быть UTF-8. Если ломается:
with open('data.json', encoding='cp1251') as f:
data = json.load(f)
df = pd.DataFrame(data)Связанные темы
FAQ
read_json или json.load?
read_json для плоских структур. json.load + DataFrame для сложной обработки.
json_normalize vs apply?
json_normalize быстрее и чище. apply — для custom логики.
Что такое NDJSON?
Newline-delimited JSON. Каждая строка = отдельный JSON. Популярно для логов и big data.
Как обработать массив вложенных объектов?
pd.json_normalize(data, record_path='array_field', meta=['parent_field']).
Тренируйте pandas — откройте тренажёр с 1500+ вопросами для собесов.