JSON и Python: практическая работа с данными в Pandas
Работа с JSON файлами в Python: сериализация данных Pandas
Основной подход: методы Pandas to_json и read_json
Для табличных данных, представленных в виде DataFrame или Series, наиболее эффективным решением является использование встроенных методов библиотеки Pandas. Эти методы оптимизированы для работы с двумерными структурами и предоставляют широкий контроль над форматом выходного файла.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'Имя': ['Анна', 'Иван', 'Мария'],
'Возраст': [25, 30, 28],
'Город': ['Москва', 'Санкт-Петербург', 'Казань']
})
# Сохранение в JSON
df.to_json('data.csv', orient='records', force_ascii=False)
# Чтение из JSON
df_loaded = pd.read_json('data.csv', orient='records')
print(df_loaded)
обработка больших данных python (обработка больших данных в python)
Имя Возраст Город
0 Анна 25 Москва
1 Иван 30 Санкт-Петербург
2 Мария 28 Казань
очистка данных python (очистка данных в python)
Пояснение: метод to_json по умолчанию использует ориентацию 'columns'. Для сохранения каждой строки как отдельного объекта применяется orient='records'. Параметр force_ascii=False сохраняет кириллицу без экранирования. При чтении ориентация должна совпадать. Если этого не сделать, данные могут быть интерпретированы неверно.
Как загрузить JSON с глубокой вложенностью в Pandas?
Вложенные структуры (вложенные объекты, списки) не могут быть напрямую прочитаны с помощью read_json, если они не приведены к плоскому виду. Решение состоит в использовании модуля json для загрузки и функции pd.json_normalize.
import json
import pandas as pd
json_str = '''{
"users": [
{"name": "Иван", "details": {"age": 30, "city": "Москва"}},
{"name": "Мария", "details": {"age": 28, "city": "Казань"}}
]
}'''
data = json.loads(json_str)
normalized = pd.json_normalize(data, record_path='users')
print(normalized)
Python подготовка данных (подготовка данных в python)
name details.age details.city
0 Иван 30 Москва
1 Мария 28 Казань
работа с dataframe python (работа с dataframe в python)
Типичная ошибка и её решение
Игнорирование параметра record_path приводит к тому, что функция рассматривает весь JSON как одну запись. Для доступа к вложенным данным следует явно указать путь к массиву объектов. Если вложенность более глубокая, используют meta для извлечения значений из вышележащих уровней.
Как настроить формат выходного JSON при сохранении DataFrame?
Параметр orient определяет, как именно будет записан DataFrame. Доступны следующие значения: 'columns', 'records', 'index', 'values', 'table', 'split'. Выбор зависит от последующей цели использования файла.
df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
print('orient=records:')
print(df.to_json(orient='records'))
print()
print('orient=index:')
print(df.to_json(orient='index'))
print()
print('orient=table:')
print(df.to_json(orient='table'))
Python работа с большими данными (работа с большими данными в python)
orient=records:
[{"A":1,"B":3},{"A":2,"B":4}]
orient=index:
{"0":{"A":1,"B":3},"1":{"A":2,"B":4}}
orient=table:
{"schema":{"fields":[{"name":"index","type":"integer"},{"name":"A","type":"integer"},{"name":"B","type":"integer"}],"primaryKey":["index"],"pandas_version":"1.4.0"},"data":[{"index":0,"A":1,"B":3},{"index":1,"A":2,"B":4}]}
структурированные данные python (структурированные данные в python)
Проблема и её решение
Если при чтении указана неверная ориентация, Pandas может прочитать данные как столбцы там, где ожидались строки, или наоборот. Следует всегда проверять orient в момент записи и чтения.
Как обработать большой JSON файл, не помещающийся в оперативную память?
Для работы с файлами, размер которых превышает доступную память, применяют построчное чтение (JSON Lines) или использование библиотеки ijson для потокового парсинга.
# Запись в формате JSON Lines (каждая строка отдельный объект)
df.to_json('big_data.json', orient='records', lines=True)
# Чтение с использованием chunksize
chunk_iter = pd.read_json('big_data.json', lines=True, chunksize=100)
for chunk in chunk_iter:
# обработка части данных
print(chunk.shape)
генерация данных python (генерация данных в python)
Возможные ошибки
Если файл не является JSON Lines (каждая строка валидный JSON, но весь файл не является массивом), read_json с lines=True не сможет его прочитать. Также необходимо установить библиотеку ijson для чтения глубоко вложенных структур без загрузки всего файла.
Как правильно сериализовать пропущенные значения и даты в JSON?
Параметры na и date_format управляют представлением NaN/NaT и datetime в выходном файле.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'дата': pd.date_range('2023-01-01', periods=3),
'значение': [1.0, np.nan, 3.0]
})
print('Без настроек:')
print(df.to_json(orient='records'))
print('С настройками:')
print(df.to_json(orient='records', date_format='iso', na='null'))
Python код символа (код символа в python)
Без настроек:
[{"дата":"2023-01-01T00:00:00.000Z","значение":1.0},{"дата":"2023-01-02T00:00:00.000Z","значение":null},{"дата":"2023-01-03T00:00:00.000Z","значение":3.0}]
С настройками:
[{"дата":"2023-01-01","значение":1.0},{"дата":"2023-01-02","значение":null},{"дата":"2023-01-03","значение":3.0}]
Распространённая трудность
По умолчанию NaN может превращаться в null или вырезаться в зависимости от версии Pandas. Для явного управления используется аргумент na ('null', 'string', 'NaN' и др.). Даты по умолчанию преобразуются в миллисекунды с эпохи, что нечитаемо. Рекомендуется устанавливать date_format='iso'.
Общие ошибки при работе с JSON в Pandas
- Проблемы с кодировкой: при записи кириллицы без
force_ascii=Falseсимволы преобразуются в escape-последовательности. Решение - явно указыватьforce_ascii=False. - Неверное определение типов: при чтении чисел с большой точностью они могут интерпретироваться как строки. Рекомендуется использовать параметр
dtypeвread_json. - Проблема с индексами: если при сохранении не указана ориентация, индекс может быть восстановлен неверно. Для точного восстановления применяют
orient='index'илиorient='table'.
Расширенный пример 1: Чтение сложного вложенного JSON с разделением на несколько DataFrame
import json
import pandas as pd
# Исходный JSON с двумя уровнями вложенности
complex_json = '''{
"store": {
"name": "Магазин у дома",
"products": [
{"id": 1, "title": "Молоко", "price": 80},
{"id": 2, "title": "Хлеб", "price": 30}
],
"employees": [
{"name": "Петр", "position": "продавец"},
{"name": "Елена", "position": "кассир"}
]
}
}'''
data = json.loads(complex_json)
# Нормализация разных уровней
store_info = pd.json_normalize(data, record_path=['store', 'products'],
meta=[['store', 'name']])
employees = pd.json_normalize(data, record_path=['store', 'employees'])
print('Товары:')
print(store_info)
print('\nСотрудники:')
print(employees)
Товары:
id title price store.name
0 1 Молоко 80 Магазин у дома
1 2 Хлеб 30 Магазин у дома
Сотрудники:
name position
0 Петр продавец
1 Елена кассир
Расширенный пример 2: Запись и чтение DataFrame с ориентацией 'split' (включает схему)
import pandas as pd
df = pd.DataFrame({
'city': ['Москва', 'СПб'],
'population': [12655000, 5384000]
})
# Запись с полной метаинформацией
df.to_json('city_split.json', orient='split')
# Чтение с той же ориентацией
df_restored = pd.read_json('city_split.json', orient='split')
print(df_restored)
city population
0 Москва 12655000
1 СПб 5384000
Ориентация 'split' сохраняет столбцы, данные и индекс отдельными ключами. Это удобно для точного восстановления структуры, но файл становится менее читаемым.
Расширенный пример 3: Потоковая запись и чтение JSON Lines (NDJSON) для больших данных
import pandas as pd
import numpy as np
# Создаём большой DataFrame (100 тысяч строк)
n = 100000
df_large = pd.DataFrame({
'id': np.arange(n),
'value': np.random.randn(n)
})
# Сохраняем в JSON Lines (каждая строка отдельный объект)
df_large.to_json('large.json', orient='records', lines=True)
# Читаем порциями по 20000 строк
chunks = []
for chunk in pd.read_json('large.json', lines=True, chunksize=20000):
# выполняем агрегацию на чанке
mean_val = chunk['value'].mean()
chunks.append(mean_val)
print('Средние значения по порциям:')
print(chunks)
Средние значения по порциям: [0.002331, -0.001567, 0.000112, -0.001943, 0.000871]
При использовании chunksize возвращается итератор. Это позволяет обрабатывать файлы любого размера без загрузки целиком.
Расширенный пример 4: Кастомная сериализация типов (например, Period)
import pandas as pd
import json
# Создаём DataFrame с Period индексом
idx = pd.period_range('2020-Q1', periods=3, freq='Q')
df = pd.DataFrame({'sales': [100, 150, 200]}, index=idx)
# Стандартный JSON не может сериализовать Period -> будет ошибка
# Используем ориентацию 'table' и параметр date_format
df.to_json('period_test.json', orient='table', date_format='iso')
# При чтении Period не восстанавливается автоматически
# Поэтому читаем как простой индекс и конвертируем вручную
df_loaded = pd.read_json('period_test.json', orient='table')
print('Тип индекса после чтения:', df_loaded.index.dtype)
Тип индекса после чтения: object
Для полного восстановления Period индекса необходимо использовать собственный конвертер или библиотеку pandas.io.json с пользовательским кодировщиком.
Расширенный пример 5: Использование параметра dtype при чтении JSON для контроля типов
import pandas as pd
import numpy as np
# Создаём файл, где возраст записан как целое число
json_str = '[{"name":"Анна","age":"25"},{"name":"Иван","age":"30"}]'
with open('example.json', 'w', encoding='utf-8') as f:
f.write(json_str)
# По умолчанию age будет строкой
df_default = pd.read_json('example.json')
print('Типы по умолчанию:')
print(df_default.dtypes)
# Явно указываем dtype
df_typed = pd.read_json('example.json', dtype={'age': np.int32})
print('\nТипы с указанием:')
print(df_typed.dtypes)
Типы по умолчанию: name object age object dtype: object Типы с указанием: name object age int32 dtype: object
Примечание: Параметр dtype в read_json работает только если все значения поля могут быть приведены к указанному типу. В противном случае возникнет ошибка. Для смешанных данных лучше использовать convert_dtypes после чтения.