Pandas - создает многоиндексные столбцы во время переименования

1

Я пытаюсь найти простой способ переименовать индекс плоского столбца в иерархический набор столбцов с несколькими индексами. Я сталкивался в одном направлении, но, похоже, это немного глупо, - есть ли лучший способ сделать это в Пандах?

#!/usr/bin/env python
import pandas as pd
import numpy as np

flat_df = pd.DataFrame(np.random.randint(0,100,size=(4, 4)), columns=list('ACBD'))

print flat_df

#      A   C   B   D
#  0  27  67  35  36
#  1  80  42  93  20
#  2  64   9  18  83
#  3  85  69  60  84


nested_columns = {'A': ('One', 'a'),
                  'C': ('One', 'c'),
                  'B': ('Two', 'b'),
                  'D': ('Two', 'd'),
                  }

tuples = sorted(nested_columns.values(), key=lambda x: x[1]) # Sort by second value
nested_df = flat_df.sort_index(axis=1) # Sort dataframe by column name
nested_df.columns = pd.MultiIndex.from_tuples(tuples)
nested_df = nested_df.sort_index(level=0, axis=1) # Sort to group first level

print nested_df

#    One     Two    
#      a   c   b   d
#  0  27  67  35  36
#  1  80  42  93  20
#  2  64   9  18  83
#  3  85  69  60  84

Кажется немного хрупким, чтобы сортировать как иерархическую спецификацию столбца, так и блок данных и предполагать, что они выстраиваются в линию. Также сортировка три раза кажется смешной. Альтернативой, которую я бы предпочел, было бы нечто вроде nested_df = flat_df.rename(columns=nested_columns), но кажется, что rename не может перейти от индексации плоских столбцов к столбцам multiindex. Я что-то пропустил?

Изменение: реализовано, что это сломается, если кортежи, отсортированные по второму значению, не будут сортироваться так же, как имена плоских столбцов. Определенно неправильный подход.

Edit2: В ответ на @wen ответ:

nested_df = flat_df.rename(columns=nested_columns)
print nested_df
#    (One, a)  (One, c)  (Two, b)  (Two, d)
# 0        18         0        51        48
# 1        69        68        78        24
# 2         2        20        99        46
# 3         1        80        11        11

Edit3:

Основываясь на ответе @ScottBoston, вот работающее решение, в котором учитываются плоские столбцы, не упомянутые во вложенных столбцах:

#!/usr/bin/env python
import pandas as pd
import numpy as np

flat_df = pd.DataFrame(np.random.randint(0,100,size=(4, 5)), columns=list('ACBDE'))

print flat_df
#     A   C   B   D   E
# 0  27  68   4  98  16
# 1   0   9   9  72  68
# 2  91  17  19  54  99
# 3  14  96  54  79  28

nested_columns = {'A': ('One', 'e'),
                  'C': ('One', 'h'),
                  'B': ('Two', 'f'),
                  'D': ('Two', 'g'),
                  }

nested_df = flat_df.rename(columns=nested_columns)
nested_df.columns = [c if isinstance(c, tuple) else ('', c) for c in nested_df.columns]
nested_df.columns = pd.MultiIndex.from_tuples(nested_df.columns)

print nested_df
#   One     Two        
#     e   h   f   g   E
# 0  27  68   4  98  16
# 1   0   9   9  72  68
# 2  91  17  19  54  99
# 3  14  96  54  79  28
  • 0
    Приятно обновить до решения.
Теги:
pandas
multi-index

2 ответа

1
Лучший ответ

Вы можете попробовать:

df.columns = pd.MultiIndex.from_tuples(df.rename(columns = nested_columns).columns)
df 

Выход:

  One     Two    
    a   c   b   d
0  27  67  35  36
1  80  42  93  20
2  64   9  18  83
3  85  69  60  84
  • 1
    Это очень близко к идеальному ответу! Единственная проблема возникает из-за того, что не все столбцы являются частью tuple из df.rename , но я всегда могу предварительно обработать столбцы после переименования, чтобы убедиться, что они все кортежи.
  • 1
    Например, если в исходной задаче все остальное не flat_df = pd.DataFrame(np.random.randint(0,100,size=(4, 5)), columns=list('ACBDE')) , я использовал flat_df = pd.DataFrame(np.random.randint(0,100,size=(4, 5)), columns=list('ACBDE')) , это решение ломается.
1

IIUC, rename

flat_df.rename(columns=nested_columns)
Out[224]: 
  One     Two    
    a   c   b   d
0  36  19  53  46
1  17  85  63  36
2  40  80  75  86
3  31  83  75  16

обновленный

flat_df.columns.map(nested_columns.get)
Out[15]: 
MultiIndex(levels=[['One', 'Two'], ['a', 'b', 'c', 'd']],
           labels=[[0, 0, 1, 1], [0, 2, 1, 3]])
  • 1
    Хм ... Я получаю кортежи как заголовки вместо pd.MultiIndex, когда я пытаюсь это сделать.
  • 0
    @ScottBoston ммм, какая у вас версия для панд
Показать ещё 7 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню