Панди: падіння рівня з багаторівневого індексу стовпців?


242

Якщо у мене є багаторівневий індекс стовпців:

>>> cols = pd.MultiIndex.from_tuples([("a", "b"), ("a", "c")])
>>> pd.DataFrame([[1,2], [3,4]], columns=cols)
    а
   --- + -
    б | c
- + --- + -
0 | 1 | 2
1 | 3 | 4

Як я можу знизити рівень "a" цього індексу, щоб закінчити:

    б | c
- + --- + -
0 | 1 | 2
1 | 3 | 4

3
Було б непогано мати метод DataFrame, який робить це як для індексу, так і для стовпців. Чи то відмову чи вибір рівня індексу.
Sören

@ Sören Check out stackoverflow.com/a/56080234/3198568 . droplevelРоботи можуть працювати або через багаторівневі індекси, або на стовпці через параметр axis.
Ірен

Відповіді:


306

Ви можете використовувати MultiIndex.droplevel:

>>> cols = pd.MultiIndex.from_tuples([("a", "b"), ("a", "c")])
>>> df = pd.DataFrame([[1,2], [3,4]], columns=cols)
>>> df
   a   
   b  c
0  1  2
1  3  4

[2 rows x 2 columns]
>>> df.columns = df.columns.droplevel()
>>> df
   b  c
0  1  2
1  3  4

[2 rows x 2 columns]

55
Напевно, найкраще прямо сказати, який рівень знижується. Рівні 0-індексуються починаючи зверху. >>> df.columns = df.columns.droplevel(0)
Тед Петру

6
Якщо індекс, який ви намагаєтеся скинути, знаходиться зліва (рядок), а не верхній (стовпець) стороною, ви можете змінити "стовпці" на "індекс" і застосувати той самий метод:>>> df.index = df.index.droplevel(1)
Idodo

7
У версії Panda 0.23.4 df.columns.droplevel()більше не доступна.
йоонгм

8
@yoonghm Це там, ви, ймовірно, просто називаєте це колонками, які не мають мультиіндексу
матовий гарнізон

1
Я мав три рівні глибокі і хотів опуститися лише до середнього рівня. Я виявив, що найкраще працює падіння найнижчого (рівень [2]), а потім найвищого (рівень [0]). >>>df.columns = df.columns.droplevel(2) >>>df.columns = df.columns.droplevel(0)
Кайл C

65

Ще один спосіб скинути індекс - це використовувати розуміння списку:

df.columns = [col[1] for col in df.columns]

   b  c
0  1  2
1  3  4

Ця стратегія також корисна, якщо ви хочете поєднати імена з обох рівнів, як у прикладі нижче, де нижній рівень містить два 'y':

cols = pd.MultiIndex.from_tuples([("A", "x"), ("A", "y"), ("B", "y")])
df = pd.DataFrame([[1,2, 8 ], [3,4, 9]], columns=cols)

   A     B
   x  y  y
0  1  2  8
1  3  4  9

Якщо опустити верхній рівень, залишиться два стовпці з індексом 'y'. Цього можна уникнути, з'єднавши імена зі списком розуміння.

df.columns = ['_'.join(col) for col in df.columns]

    A_x A_y B_y
0   1   2   8
1   3   4   9

Це проблема, яку я мав після занять у групі, і знадобилося певний час, щоб знайти це інше питання, яке вирішило її. Я адаптував це рішення до конкретного випадку тут.


2
[col[1] for col in df.columns]пряміше df.columns.get_level_values(1).
Ерік О Лебігот

2
Була аналогічна потреба, де деякі колонки мали порожні значення рівня. Використовували наступне:[col[0] if col[1] == '' else col[1] for col in df.columns]
Логан

43

Інший спосіб зробити це - перепризначити dfна основі перерізу df, використовуючи метод .xs .

>>> df

    a
    b   c
0   1   2
1   3   4

>>> df = df.xs('a', axis=1, drop_level=True)

    # 'a' : key on which to get cross section
    # axis=1 : get cross section of column
    # drop_level=True : returns cross section without the multilevel index

>>> df

    b   c
0   1   2
1   3   4

1
Це працює лише коли є одна мітка для цілого рівня стовпця.
Тед Петру

1
Не працює, коли ви хочете опустити другий рівень.
Sören

Це приємне рішення, якщо ви хочете нарізати і опустити на той же рівень. Якби ви хотіли bскинути на другий рівень (скажімо ), тоді скиньте цей рівень і залиште його на першому рівні ( a), спрацювало б наступне:df = df.xs('b', axis=1, level=1, drop_level=True)
Тіффані Г. Вілсон

27

Станом на Pandas 0.24.0 , тепер ми можемо використовувати DataFrame.droplevel () :

cols = pd.MultiIndex.from_tuples([("a", "b"), ("a", "c")])
df = pd.DataFrame([[1,2], [3,4]], columns=cols)

df.droplevel(0, axis=1) 

#   b  c
#0  1  2
#1  3  4

Це дуже корисно, якщо ви хочете підтримувати ланцюжок методів DataFrame.


Це "найчистіше" рішення в тому, що новий DataFrame повертається, а не змінюється "на місці".
EliadL

16

Ви також можете досягти цього шляхом перейменування стовпців:

df.columns = ['a', 'b']

Це включає в себе крок вручну, але це може бути варіантом, особливо якщо ви зрештою перейменовуєте свій фрейм даних.


Це по суті те, що робить перша відповідь Монетного двору. Тепер також немає необхідності вказувати список імен (що взагалі нудно), як це вам дано df.columns.get_level_values(1).
Ерік О Лебігот

13

Невеликий трюк із використанням sum рівня = 1 (робота, коли рівень = 1 - все унікально)

df.sum(level=1,axis=1)
Out[202]: 
   b  c
0  1  2
1  3  4

Більш поширене рішення get_level_values

df.columns=df.columns.get_level_values(1)
df
Out[206]: 
   b  c
0  1  2
1  3  4

4

Я боровся з цією проблемою, оскільки не знаю, чому моя функція droplevel () не працює. Пропрацюйте декілька і дізнайтеся, що "а" у вашій таблиці - це ім'я стовпців, а "b", "c" - індекс. Робити це, як допоможе

df.columns.name = None
df.reset_index() #make index become label

1
Це взагалі не відтворює бажаний вихід.
Ерік О Лебігот

Виходячи з дати, яку вона опублікувала, рівень падіння, можливо, не був включений у вашу версію Pandas (її додано до стабільної версії, 24.0, січень 2019 року)
LinkBerest
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.