Pandas: Eine Ebene aus einem mehrstufigen Spaltenindex löschen?


242

Wenn ich einen mehrstufigen Spaltenindex habe:

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

Wie kann ich die "a" -Ebene dieses Index löschen, sodass ich am Ende Folgendes habe:

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

3
Es wäre schön, eine DataFrame-Methode zu haben, die dies sowohl für den Index als auch für die Spalten erledigt. Entweder das Löschen oder Auswählen von Indexstufen.
Sören

@ Sören Check out stackoverflow.com/a/56080234/3198568 . droplevelworks kann über den Parameter entweder an mehrstufigen Indizes oder Spalten arbeiten axis.
Irene

Antworten:


306

Sie können verwenden 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
Es ist wahrscheinlich am besten, explizit zu sagen, welches Level fallen gelassen wird. Die Ebenen werden von oben beginnend mit 0 indiziert. >>> df.columns = df.columns.droplevel(0)
Ted Petrou

6
Wenn sich der Index, den Sie >>> df.index = df.index.droplevel(1)
löschen möchten,

7
In Panda Version 0.23.4 df.columns.droplevel()ist nicht mehr verfügbar.
Yoonghm

8
@yoonghm Es ist da, Sie rufen es wahrscheinlich nur für Spalten auf, die keinen Multi-Index haben
Matt Harrison

1
Ich hatte drei Ebenen tief und wollte nur auf die mittlere Ebene fallen. Ich fand, dass das Fallenlassen des niedrigsten (Stufe [2]) und des höchsten (Stufe [0]) am besten funktioniert. >>>df.columns = df.columns.droplevel(2) >>>df.columns = df.columns.droplevel(0)
Kyle C

65

Eine andere Möglichkeit, den Index zu löschen, besteht darin, ein Listenverständnis zu verwenden:

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

   b  c
0  1  2
1  3  4

Diese Strategie ist auch nützlich, wenn Sie die Namen beider Ebenen wie im folgenden Beispiel kombinieren möchten, in dem die unterste Ebene zwei Ys enthält:

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

Wenn Sie die oberste Ebene löschen, bleiben zwei Spalten mit dem Index 'y' übrig. Dies kann vermieden werden, indem die Namen mit dem Listenverständnis verbunden werden.

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

    A_x A_y B_y
0   1   2   8
1   3   4   9

Das ist ein Problem, das ich hatte, nachdem ich einen Groupby gemacht hatte, und es dauerte eine Weile, bis ich diese andere Frage gefunden hatte , die es löste. Ich habe diese Lösung hier an den speziellen Fall angepasst.


2
[col[1] for col in df.columns]ist direkter df.columns.get_level_values(1).
Eric O Lebigot

2
Hatte einen ähnlichen Bedarf, bei dem einige Spalten leere Pegelwerte hatten. Verwendet das folgende:[col[0] if col[1] == '' else col[1] for col in df.columns]
Logan

43

Eine andere Möglichkeit, dies zu tun, besteht darin, dfbasierend auf einem Querschnitt von dfmit der .xs- Methode eine Neuzuweisung vorzunehmen .

>>> 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
Dies funktioniert nur, wenn für eine gesamte Spaltenebene eine einzelne Beschriftung vorhanden ist.
Ted Petrou

1
Funktioniert nicht, wenn Sie die zweite Ebene löschen möchten.
Sören

Dies ist eine gute Lösung, wenn Sie für das gleiche Level in Scheiben schneiden und fallen lassen möchten. Wenn Sie auf der zweiten Ebene schneiden möchten (sagen wir b), dann diese Ebene fallen lassen und mit der ersten Ebene ( a) belassen werden , würde das Folgende funktionieren:df = df.xs('b', axis=1, level=1, drop_level=True)
Tiffany G. Wilson

27

Ab Pandas 0.24.0 können wir jetzt DataFrame.droplevel () verwenden :

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

Dies ist sehr nützlich, wenn Sie Ihre DataFrame-Methodenkette am Laufen halten möchten.


Dies ist die "reinste" Lösung, da ein neuer DataFrame zurückgegeben wird, anstatt ihn "an Ort und Stelle" ändern zu lassen.
EliadL

16

Sie können dies auch erreichen, indem Sie die Spalten umbenennen:

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

Dies beinhaltet einen manuellen Schritt, kann jedoch eine Option sein, insbesondere wenn Sie Ihren Datenrahmen eventuell umbenennen würden.


Dies ist im Wesentlichen die erste Antwort von Mint. Jetzt müssen Sie auch nicht mehr die Liste der Namen angeben (was im Allgemeinen mühsam ist), wie sie Ihnen von gegeben wird df.columns.get_level_values(1).
Eric O Lebigot

12

Ein kleiner Trick sum mit Level = 1 (Arbeit, wenn Level = 1 eindeutig ist)

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

Häufigere Lösung get_level_values

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

4

Ich habe mit diesem Problem zu kämpfen, da ich nicht weiß, warum meine droplevel () -Funktion nicht funktioniert. Arbeiten Sie mehrere durch und lernen Sie, dass 'a' in Ihrer Tabelle der Spaltenname und 'b', 'c' der Index ist. Tun Sie dies wird helfen

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

1
Dies gibt die gewünschte Ausgabe überhaupt nicht wieder.
Eric O Lebigot

Basierend auf dem Datum, an dem dies veröffentlicht wurde, war die Drop-Stufe möglicherweise nicht in Ihrer Version von Pandas enthalten (sie wurde der stabilen Version 24.0 im Januar 2019 hinzugefügt)
LinkBerest
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.