JSON и Python: практическая работа с данными в Pandas

Раздел: Сериализация -> 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'.
- обработка символьных данных python (обработка символьных данных в python)
- Python преобразование в строку (преобразование в строку в python)
- Python как проверить строку (проверка строки в python)

Расширенный пример 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 после чтения.

Работа с JSON файлами в Python - comments

En
Json файл python (python)