Как развернуть иерархический индекс в столбцах
У меня есть датафрейм с иерархическим индексом по оси 1 (колонки), который получен в результате операции groupby.agg
. Пример структуры данных представлен ниже:
USAF WBAN year month day s_PC s_CL s_CD s_CNT tempf
sum sum sum sum amax amin
0 702730 26451 1993 1 1 1 0 12 13 30.92 24.98
1 702730 26451 1993 1 2 0 0 13 13 32.00 24.98
2 702730 26451 1993 1 3 1 10 2 13 23.00 6.98
3 702730 26451 1993 1 4 1 0 12 13 10.04 3.92
4 702730 26451 1993 1 5 3 0 10 13 19.94 10.94
Я хочу преобразовать его в плоский формат, чтобы он выглядел следующим образом (имена колонок не критичны — я смогу переименовать их по мере необходимости):
USAF WBAN year month day s_PC s_CL s_CD s_CNT tempf_amax tempf_amin
0 702730 26451 1993 1 1 1 0 12 13 30.92 24.98
1 702730 26451 1993 1 2 0 0 13 13 32.00 24.98
2 702730 26451 1993 1 3 1 10 2 13 23.00 6.98
3 702730 26451 1993 1 4 1 0 12 13 10.04 3.92
4 702730 26451 1993 1 5 3 0 10 13 19.94 10.94
Как мне это сделать? (Я уже пробовал много методов, но, к сожалению, безуспешно.)
В качестве уточнения, вот заголовок датафрейма в виде словаря:
{('USAF', ''): {0: '702730',
1: '702730',
2: '702730',
3: '702730',
4: '702730'},
('WBAN', ''): {0: '26451', 1: '26451', 2: '26451', 3: '26451', 4: '26451'},
('day', ''): {0: 1, 1: 2, 2: 3, 3: 4, 4: 5},
('month', ''): {0: 1, 1: 1, 2: 1, 3: 1, 4: 1},
('s_CD', 'sum'): {0: 12.0, 1: 13.0, 2: 2.0, 3: 12.0, 4: 10.0},
('s_CL', 'sum'): {0: 0.0, 1: 0.0, 2: 10.0, 3: 0.0, 4: 0.0},
('s_CNT', 'sum'): {0: 13.0, 1: 13.0, 2: 13.0, 3: 13.0, 4: 13.0},
('s_PC', 'sum'): {0: 1.0, 1: 0.0, 2: 1.0, 3: 1.0, 4: 3.0},
('tempf', 'amax'): {0: 30.920000000000002,
1: 32.0,
2: 23.0,
3: 10.039999999999999,
4: 19.939999999999998},
('tempf', 'amin'): {0: 24.98,
1: 24.98,
2: 6.9799999999999969,
3: 3.9199999999999982,
4: 10.940000000000001},
('year', ''): {0: 1993, 1: 1993, 2: 1993, 3: 1993, 4: 1993}}
Как решить данную проблему?
5 ответ(ов)
Когда вы используете pd.DataFrame(df.to_records())
, происходит преобразование DataFrame с многоуровневым индексом в обычный DataFrame, где многоуровневый индекс становится столбцами, а индекс становится лишь последовательностью целых чисел. Это может быть полезно, если вам нужно упростить структуру данных для дальнейшего анализа или обработки.
Если вы хотите сохранить иерархию индексов, лучше воспользоваться методами, которые не приводят к потере этой информации, например, df.reset_index()
, который сбросит индекс и добавит его как обычные столбцы, сохраняя при этом структуру данных.
Если вы хотите избежать дублирования меток столбцов, как указывает ответ Энди Хайдена, вам нужно немного изменить код. Вот пример того, как это можно сделать:
In [34]: df
Out[34]:
USAF WBAN day month s_CD s_CL s_CNT s_PC tempf year
sum sum sum sum amax amin
0 702730 26451 1 1 12 0 13 1 30.92 24.98 1993
1 702730 26451 2 1 13 0 13 0 32.00 24.98 1993
2 702730 26451 3 1 2 10 13 1 23.00 6.98 1993
3 702730 26451 4 1 12 0 13 1 10.04 3.92 1993
4 702730 26451 5 1 10 0 13 3 19.94 10.94 1993
In [35]: mi = df.columns
In [36]: mi
Out[36]:
MultiIndex
[(USAF, ), (WBAN, ), (day, ), (month, ), (s_CD, sum), (s_CL, sum), (s_CNT, sum), (s_PC, sum), (tempf, amax), (tempf, amin), (year, )]
In [37]: mi.tolist()
Out[37]:
[('USAF', ''),
('WBAN', ''),
('day', ''),
('month', ''),
('s_CD', 'sum'),
('s_CL', 'sum'),
('s_CNT', 'sum'),
('s_PC', 'sum'),
('tempf', 'amax'),
('tempf', 'amin'),
('year', '')]
In [38]: ind = pd.Index([e[0] + e[1] for e in mi.tolist()])
In [39]: ind
Out[39]: Index([USAF, WBAN, day, month, s_CDsum, s_CLsum, s_CNTsum, s_PCsum, tempfamax, tempfamin, year], dtype=object)
In [40]: df.columns = ind
In [46]: df
Out[46]:
USAF WBAN day month s_CDsum s_CLsum s_CNTsum s_PCsum tempfamax tempfamin \
0 702730 26451 1 1 12 0 13 1 30.92 24.98
1 702730 26451 2 1 13 0 13 0 32.00 24.98
2 702730 26451 3 1 2 10 13 1 23.00 6.98
3 702730 26451 4 1 12 0 13 1 10.04 3.92
4 702730 26451 5 1 10 0 13 3 19.94 10.94
year
0 1993
1 1993
2 1993
3 1993
4 1993
В этом коде мы создаем новый индекс, объединяя названия столбцов и их уровни (например, s_CD
и sum
в s_CDsum
), что позволяет избежать дублирующихся меток.
Этот код будет объединять уровни многоуровневых колонок в DataFrame df
с помощью символа подчеркивания _
. Давайте разберем его по частям:
df.columns.values
- получает значения колонок DataFrame в виде массивов.for tup in df.columns.values
- перебирает каждую колонку, которая представлена как кортеж (если у вас многоуровневый индекс).'_'.join(tup)
- объединяет элементы кортежа в строку, используя символ подчеркивания как разделитель.rstrip('_')
- убирает подчеркивание в конце строки, если оно там есть.df.columns = [...]
- присваивает полученные строки новым именам колонок DataFrame.
После выполнения этого кода, имена колонок будут преобразованы в более простые строки, где уровни иерархии будут объединены символом подчеркивания.
Пример использования:
import pandas as pd
# Создаем многоуровневый DataFrame
arrays = [('A', 'A', 'B', 'B'), ('one', 'two', 'one', 'two')]
index = pd.MultiIndex.from_arrays(arrays, names=('first', 'second'))
df = pd.DataFrame(columns=index)
# Применяем преобразование имен колонок
df.columns = ['_'.join(tup).rstrip('_') for tup in df.columns.values]
print(df.columns)
Если у вас остались вопросы, не стесняйтесь задавать!
Да, действительно, существует простой способ объединить названия колонок в DataFrame, используя только методы pandas. Вот пример кода:
df.columns = df.columns.to_flat_index().str.join('_')
Этот код преобразует названия колонок в плоский индекс и объединяет их, добавляя символ подчеркивания между уровнями. В результате вы получите такие названия колонок:
USAF_ WBAN_ day_ month_ ... s_PC_sum tempf_amax tempf_amin year_
0 702730 26451 1 1 ... 1.0 30.92 24.98 1993
1 702730 26451 2 1 ... 0.0 32.00 24.98 1993
2 702730 26451 3 1 ... 1.0 23.00 6.98 1993
3 702730 26451 4 1 ... 1.0 10.04 3.92 1993
4 702730 26451 5 1 ... 3.0 19.94 10.94 1993
Обратите внимание, что для колонок, которые не относятся к MultiIndex, добавляется завершающее подчеркивание. Если вам это не критично, данный подход может вас устроить. В моем случае, где все колонки имели два уровня, такая команда позволила создать аккуратные названия.
Если вы хотите сохранить какую-либо информацию агрегирования из второго уровня многоуровневого индекса, вы можете попробовать следующий подход:
In [1]: new_cols = [''.join(t) for t in df.columns]
Out[1]:
['USAF',
'WBAN',
'day',
'month',
's_CDsum',
's_CLsum',
's_CNTsum',
's_PCsum',
'tempfamax',
'tempfamin',
'year']
In [2]: df.columns = new_cols
Этот код объединяет уровни столбцов в один уровень, сводя многоуровневый индекс к простым строковым названиям столбцов, что может упростить работу с данными.
Преобразование вывода GroupBy с многоуровневым индексом в Series обратно в DataFrame в Pandas
Преобразование списка словарей в DataFrame pandas
Объединение двух столбцов текста в DataFrame pandas
Получить список из колонки или строки DataFrame в pandas?
Выбор строки из pandas Series/DataFrame по целочисленному индексу