Функциональный подход к группированию столбцов фрейма данных в мультииндекс

#python #pandas #dataframe #multi-index

#питон #панды #фрейм данных #многоиндексный

Вопрос:

Существует ли более простой функциональный способ сгруппировать столбцы в мультииндекс?

 # Setup l = [...] l2,l3,l4 = do_things(l, [2,3,4]) d = {2:l2, 3:l3, 4:l4} # Or, l = l2 = l3 = l4 = list(range(20))  

Проблемы с моими подходами:

 # Cons: # * Complicated # * Requires multiple iterations over the dictionary to occur # in the same order. This is guaranteed as the dictionary is # unchanged but I'm not happy with the implicit dependency. df = pd.DataFrame  ( zip(*d.values())  , index=l  , columns=pd.MultiIndex.from_product([["group"], d.keys()])  ).rename_axis("x").reset_index().reset_index()  # Cons: # * Complicated # * Multiple assignments df = pd.DataFrame(d, index=l).rename_axis("x") df.columns = pd.MultiIndex.from_product([["group"],df.columns]) df = df.reset_index().reset_index()  

Я ищу что-то вроде:

 df =  ( pd.DataFrame(d, index=l)  . rename_axis("x")  . group_columns("group")  . reset_index().reset_index()  )  

Результат:

 index x group  2 3 4 0 0 2 0 0 0 1 1 2 0 0 0 2 2 2 0 0 0 3 3 2 0 0 0 4 4 1 0 0 0 5 5 2 0 0 0 6 6 1 0 0 0 7 7 2 0 0 0 8 8 4 0 1 1 9 9 4 0 1 1 10 10 4 0 1 1 11 11 0 0 1 1 12 12 1 0 1 1 13 13 1 0 1 1 14 14 3 1 2 2 15 15 1 1 2 2 16 16 1 1 2 3 17 17 1 1 2 3 18 18 4 1 2 3 19 19 3 1 2 3 20 20 4 1 2 3 21 21 4 1 2 3 22 22 4 1 2 3 23 23 4 1 2 3  

Комментарии:

1. Может быть, просто создать фрейм данных непосредственно из словаря и ? l df = pd.DataFrame({('index', ''): pd.RangeIndex(len(l)), ('x', ''): l} | {('group', k): v for k, v in d.items()}) ?

2. Это был бы хороший ответ. Я бы заменил первую запись «индекс» на reset_index(). Как вы думаете, союз диктантов понятнее, чем расширение**? Я оставлю его открытым, чтобы получить другие ответы.

3. Я не думаю, что в любом случае это имеет значение. Это было именно так, как я начал, потому что я не был совсем уверен, каким должен быть результат, пока вы не внесли свои правки.

Ответ №1:

Вероятно, проще всего просто переформатировать словарь и передать его в конструктор фрейма данных:

 # Sample Data size = 5 lst = np.arange(size)   10 d = {2: lst, 3: lst   size, 4: lst   (size * 2)}  df = pd.DataFrame(  # Add group level by changing keys to tuples  {('group', k): v for k, v in d.items()},  index=lst )  

Выход:

 group   2 3 4 10 10 15 20 11 11 16 21 12 12 17 22 13 13 18 23 14 14 19 24  

Обратите внимание, что кортежи автоматически интерпретируются как мультииндекс


За этим может следовать любая желаемая цепочка операций:

 df = pd.DataFrame(  {('group', k): v for k, v in d.items()},  index=lst ).rename_axis('x').reset_index().reset_index()  

df :

 index x group   2 3 4 0 0 10 10 15 20 1 1 11 11 16 21 2 2 12 12 17 22 3 3 13 13 18 23 4 4 14 14 19 24  

Также можно объединить шаги и напрямую сгенерировать полный кадр данных:

 df = pd.DataFrame({  ('index', ''): pd.RangeIndex(len(lst)),  ('x', ''): lst,  **{('group', k): v for k, v in d.items()} })  

df :

 index x group   2 3 4 0 0 10 10 15 20 1 1 11 11 16 21 2 2 12 12 17 22 3 3 13 13 18 23 4 4 14 14 19 24  

Естественно, можно использовать любую комбинацию понимания словаря и операций с пандами.