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

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]

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.


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

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.


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.


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

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

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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.