5

Как развернуть иерархический индекс в столбцах

13

У меня есть датафрейм с иерархическим индексом по оси 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 ответ(ов)

1

Когда вы используете pd.DataFrame(df.to_records()), происходит преобразование DataFrame с многоуровневым индексом в обычный DataFrame, где многоуровневый индекс становится столбцами, а индекс становится лишь последовательностью целых чисел. Это может быть полезно, если вам нужно упростить структуру данных для дальнейшего анализа или обработки.

Если вы хотите сохранить иерархию индексов, лучше воспользоваться методами, которые не приводят к потере этой информации, например, df.reset_index(), который сбросит индекс и добавит его как обычные столбцы, сохраняя при этом структуру данных.

0

Если вы хотите избежать дублирования меток столбцов, как указывает ответ Энди Хайдена, вам нужно немного изменить код. Вот пример того, как это можно сделать:

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), что позволяет избежать дублирующихся меток.

0

Этот код будет объединять уровни многоуровневых колонок в DataFrame df с помощью символа подчеркивания _. Давайте разберем его по частям:

  1. df.columns.values - получает значения колонок DataFrame в виде массивов.
  2. for tup in df.columns.values - перебирает каждую колонку, которая представлена как кортеж (если у вас многоуровневый индекс).
  3. '_'.join(tup) - объединяет элементы кортежа в строку, используя символ подчеркивания как разделитель.
  4. rstrip('_') - убирает подчеркивание в конце строки, если оно там есть.
  5. 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)

Если у вас остались вопросы, не стесняйтесь задавать!

0

Да, действительно, существует простой способ объединить названия колонок в 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, добавляется завершающее подчеркивание. Если вам это не критично, данный подход может вас устроить. В моем случае, где все колонки имели два уровня, такая команда позволила создать аккуратные названия.

0

Если вы хотите сохранить какую-либо информацию агрегирования из второго уровня многоуровневого индекса, вы можете попробовать следующий подход:

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

Этот код объединяет уровни столбцов в один уровень, сводя многоуровневый индекс к простым строковым названиям столбцов, что может упростить работу с данными.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь