2025, Oct 04 05:15
Как превратить столбец словарей в длинный датафрейм с id и schedule_name в pandas
Пошаговое решение в pandas: преобразуем столбец словарей в «длинный» датафрейм с колонками id и schedule_name. Выравнивание ключей, stack, reset_index.
Преобразование вложенного JSON в аккуратную, готовую к анализу таблицу — задача, которая встречается регулярно. Частая ситуация: в столбце pandas хранится набор словарей, где ключи — идентификаторы, а значения — понятные человеку подписи. Цель — превратить каждую пару ключ–значение из всех строк в опрятный датафрейм из двух столбцов: id и schedule_name. Корректно выполнить это по всему столбцу, а не только для одной строки, — именно то, на чём многие спотыкаются.
С чего начинаем
Предположим, в одном из столбцов датафрейма лежат словари с привязками расписаний по строкам. В общих чертах это выглядит так:
tbl['schedules']
0  {'3263524': 'Group 1 CORE DAYS', '3263525': 'Group 1 CORE NIGHTS', '3263526': 'Group 1 EDUCATION', '3263527': 'Group 1 ROUNDING'}
1  {'3263524': 'Group 1 CORE DAYS', '3881368': 'VS Days', '3881370': 'VS Education Shift A', '3881455': 'VS Education Shift B'}
Искомый «длинный» датафрейм содержит по одной строке на каждую пару из любого словаря:
id        schedule_name
3263524   Group 1 CORE DAYS
3263525   Group 1 CORE NIGHTS
3263526   Group 1 EDUCATION
3263527   Group 1 ROUNDING
3881368   VS Days
3881370   VS Education Shift A
3881455   VS Education Shift B
Наивная попытка, которая не срабатывает
Легко поддаться желанию передать один из словарей в from_dict, но так мы обрабатываем лишь одну строку и всё равно не получаем нужные имена столбцов и индекс:
sched_map = pd.DataFrame.from_dict(tbl['schedules'].iloc[0], orient='index')Такой подход игнорирует остальные строки и к тому же требует дополнительных шагов, чтобы привести названия столбцов и индекс к нужному виду.
Что здесь на самом деле происходит
Чистое решение начинается с выравнивания всех ключей словарей по строкам как по столбцам. Превращение серии словарей в «широкий» датафрейм делает именно это: каждый уникальный ключ становится отдельным столбцом, а там, где ключ отсутствует, подставляется NaN. Затем stack переводит данные в «длинный» формат, и каждая пара ключ–значение превращается в отдельную строку. Опускание уровня индекса в колонку раскрывает ключи словаря как обычные данные. Переименование двух столбцов завершает форму, а удаление дублей сводит повторяющиеся пары.
Решение
Вся логика укладывается в такой конвейер на чистом pandas:
flat_schedules = (
    pd.DataFrame(tbl['schedules'].tolist())
      .stack().reset_index(level=1)
      .set_axis(['id', 'schedule_name'], axis=1)
      .drop_duplicates(ignore_index=True)
)Результат:
id         schedule_name
3263524    Group 1 CORE DAYS
3263525    Group 1 CORE NIGHTS
3263526    Group 1 EDUCATION
3263527    Group 1 ROUNDING
3881368    VS Days
3881370    VS Education Shift A
3881455    VS Education Shift B
Почему это работает, шаг за шагом
Первый шаг, DataFrame(tbl['schedules'].tolist()), формирует «широкую» таблицу, выравнивая ключи по столбцам. Эффект хорошо виден, если взглянуть на промежуточный результат:
3263524              3263525            3263526  \
0  Group 1 CORE DAYS  Group 1 CORE NIGHTS  Group 1 EDUCATION   
1  Group 1 CORE DAYS                  NaN                NaN   
            3263527  3881368               3881370               3881455  
0  Group 1 ROUNDING      NaN                   NaN                   NaN  
1               NaN  VS Days  VS Education Shift A  VS Education Shift B  
Вызов stack() переворачивает эту широкую матрицу в длинный ряд индекс–значение, где каждая строка соответствует одной паре ключ–значение, включая пары из всех исходных строк:
0  3263524       Group 1 CORE DAYS
   3263525     Group 1 CORE NIGHTS
   3263526       Group 1 EDUCATION
   3263527        Group 1 ROUNDING
1  3263524       Group 1 CORE DAYS
   3881368                 VS Days
   3881370    VS Education Shift A
   3881455    VS Education Shift B
reset_index(level=1) переносит ключи словаря из составного индекса в обычный столбец. set_axis(['id', 'schedule_name'], axis=1) задаёт названия двух столбцов. drop_duplicates(ignore_index=True) убирает повторяющиеся пары и перенумеровывает строки с нуля.
Зачем важны эти детали
При загрузке вложенного JSON сразу приводите его к аккуратной и предсказуемой схеме — так вы избежите проблем дальше по конвейеру. Правильное выравнивание ключей по строкам до поворота предотвращает тихую потерю данных и странные случаи при объединениях, фильтрации или агрегациях. Компактный конвейер, переводящий столбец словарей в чистую «длинную» таблицу, проще понимать, тестировать и переиспользовать.
Итоги
Используйте двухэтапное преобразование формы: сначала расширьте данные, выровняв ключи словарей по столбцам, затем сожмите их с помощью stack, получив по строке на каждую пару ключ–значение. Завершите, сделав ключи отдельным столбцом, присвоив осмысленные названия колонкам и устранив дубликаты. Такая последовательность даёт надёжное соответствие id и schedule_name, которое без опаски можно подключать к остальному пайплайну на pandas.