パンダ:マルチレベルの列インデックスからレベルをドロップしますか?


242

マルチレベルの列インデックスがある場合:

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

そのインデックスの「a」レベルを削除するにはどうすればよいですか?

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

3
インデックスと列の両方に対してそれを行うDataFrameメソッドがあると便利です。インデックスレベルを削除または選択します。
セーレン

ソレン@チェックアウトstackoverflow.com/a/56080234/3198568をdroplevelWorksは、パラメータを使用して、マルチレベルのインデックスまたは列のどちらでも機能します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)
Ted Petrou

6
ドロップしようとしているインデックスが左(行)側ではなく、トップ(コラム)側にある場合は、「インデックス」を「列」に変更し、同じ方法を使用することができます:>>> df.index = df.index.droplevel(1)
Idodo

7
Pandaバージョン0.23.4では、df.columns.droplevel()は使用できなくなりました。
yoonghm 2018

8
@yoonghmそこにあります。おそらく、マルチインデックスを持たないカラムでそれを呼び出しているだけです
マットハリソン

1
私は3つのレベルの深さがあり、真ん中のレベルだけにドロップダウンしたいと思っていました。最低(レベル[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

この戦略は、下のレベルに2つの「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

最上位を削除すると、2つの列にインデックス「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)です。
エリックOレビゴット2018

2
一部の列に空のレベル値が含まれるという同様のニーズがありました。次を使用しました:[col[0] if col[1] == '' else col[1] for col in df.columns]
Logan

43

これを行う別の方法は、.xsメソッドを使用dfして、の断面に基づいて再割り当てすることです。df

>>> 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
これは、列レベル全体に単一のラベルがある場合にのみ機能します。
Ted Petrou 2017年

1
2番目のレベルをドロップする場合は機能しません。
セーレン

これは、同じレベルでスライスアンドドロップする場合に最適なソリューションです。あなたが第2レベル(と言うにスライスしたい場合b)、そのレベルをドロップすると、最初のレベルのままにする(a)、次のように動作します:df = df.xs('b', axis=1, level=1, drop_level=True)
ティファニーG.ウィルソン

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)
エリックOレビゴット2018

13

sum level = 1で使用する小さなトリック(level = 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()関数が機能しない理由がわからないため、この問題に苦労しました。いくつかを調べて、テーブルの「a」が列名で「b」、「c」がインデックスであることを確認してください。このようにしてください

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

1
これは望ましい出力をまったく再現しません。
Eric O Lebigot

これが投稿された日付に基づいて、ドロップレベルはお使いのバージョンのPandasに含まれていなかった可能性があります(2019年1月の安定版24.0に追加されました)
LinkBerest
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.