Panda: turunkan level dari indeks kolom multi-level?

242

Jika saya punya indeks kolom multi-level:

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

Bagaimana saya bisa menurunkan level "a" dari indeks itu, jadi saya berakhir dengan:

    b | c
- + --- + -
0 | 1 | 2
1 | 3 | 4
David Wolever
sumber
3
Akan menyenangkan untuk memiliki metode DataFrame yang melakukan itu untuk indeks dan kolom. Baik dari menjatuhkan atau memilih level indeks.
Sören
@ Sören Periksa stackoverflow.com/a/56080234/3198568 . droplevelbekerja dapat bekerja pada indeks atau kolom bertingkat baik melalui parameter axis.
irene

Jawaban:

306

Anda bisa menggunakan 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]
DSM
sumber
55
Mungkin lebih baik untuk secara eksplisit mengatakan level mana yang sedang dijatuhkan. Level diindeks 0 mulai dari atas. >>> df.columns = df.columns.droplevel(0)
Ted Petrou
6
Jika indeks yang ingin Anda turunkan berada di sisi kiri (baris) dan bukan sisi atas (kolom), Anda dapat mengubah "kolom" menjadi "indeks" dan menggunakan metode yang sama:>>> df.index = df.index.droplevel(1)
Idodo
7
Dalam versi Panda 0.23.4, df.columns.droplevel()tidak lagi tersedia.
yoonghm
8
@yoonghm Itu ada di sana, Anda mungkin hanya memanggilnya pada kolom yang tidak memiliki multi-indeks
matt harrison
1
Saya memiliki tiga level dalam dan ingin turun ke level menengah saja. Saya menemukan bahwa menjatuhkan yang terendah (level [2]) dan kemudian yang tertinggi (level [0]) bekerja paling baik. >>>df.columns = df.columns.droplevel(2) >>>df.columns = df.columns.droplevel(0)
Kyle C
65

Cara lain untuk menjatuhkan indeks adalah dengan menggunakan pemahaman daftar:

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

   b  c
0  1  2
1  3  4

Strategi ini juga berguna jika Anda ingin menggabungkan nama-nama dari kedua level seperti pada contoh di bawah ini di mana level bawah berisi dua '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

Menjatuhkan level atas akan meninggalkan dua kolom dengan indeks 'y'. Itu bisa dihindari dengan bergabung dengan nama-nama dengan daftar pemahaman.

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

    A_x A_y B_y
0   1   2   8
1   3   4   9

Itu masalah yang saya miliki setelah melakukan groupby dan butuh beberapa saat untuk menemukan pertanyaan lain yang menyelesaikannya. Saya menyesuaikan solusi itu dengan kasus spesifik di sini.

daun mint
sumber
2
[col[1] for col in df.columns]lebih langsung df.columns.get_level_values(1).
Eric O Lebigot
2
Punya kebutuhan serupa dimana beberapa kolom memiliki nilai level kosong. Digunakan sebagai berikut:[col[0] if col[1] == '' else col[1] for col in df.columns]
Logan
43

Cara lain untuk melakukan ini adalah dengan menetapkan kembali dfberdasarkan bagian melintang df, menggunakan metode .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
spacetyper
sumber
1
Ini hanya berfungsi setiap kali ada label tunggal untuk seluruh level kolom.
Ted Petrou
1
Tidak berfungsi saat Anda ingin menjatuhkan level kedua.
Sören
Ini adalah solusi yang bagus jika Anda ingin memotong dan menjatuhkan untuk level yang sama. Jika Anda ingin mengiris pada tingkat kedua (katakanlah b) lalu jatuhkan tingkat itu dan dibiarkan dengan tingkat pertama ( a), berikut ini akan berhasil:df = df.xs('b', axis=1, level=1, drop_level=True)
Tiffany G. Wilson
27

Pada Pandas 0.24.0 , sekarang kita dapat menggunakan 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

Ini sangat berguna jika Anda ingin menjaga rantai metode DataFrame Anda bergulir.

jxc
sumber
Ini adalah solusi "paling murni" dalam hal DataFrame baru dikembalikan daripada mengubahnya "di tempat".
EliadL
16

Anda juga bisa mencapainya dengan mengganti nama kolom:

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

Ini melibatkan langkah manual tetapi bisa menjadi pilihan terutama jika Anda akhirnya akan mengubah nama frame data Anda.

sedeh
sumber
Ini pada dasarnya adalah apa jawaban pertama Mint. Sekarang, tidak perlu menentukan daftar nama (yang biasanya membosankan), seperti yang diberikan kepada Anda oleh df.columns.get_level_values(1).
Eric O Lebigot
13

Trik kecil menggunakan sum level = 1 (berfungsi saat level = 1 semuanya unik)

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

Solusi yang lebih umum get_level_values

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

Saya telah bergumul dengan masalah ini karena saya tidak tahu mengapa fungsi droplevel () saya tidak berfungsi. Bekerja melalui beberapa dan belajar bahwa 'a' di tabel Anda adalah nama kolom dan 'b', 'c' adalah indeks. Apakah seperti ini akan membantu

df.columns.name = None
df.reset_index() #make index become label
dhFrank
sumber
1
Ini tidak mereproduksi output yang diinginkan sama sekali.
Eric O Lebigot
Berdasarkan tanggal posting ini, level drop mungkin belum dimasukkan dalam versi Pandas Anda (ditambahkan ke versi stabil, 24.0, pada Januari 2019)
LinkBerest