Pilih baris di pandas MultiIndex DataFrame

147

Apa cara pandas paling umum untuk memilih / memfilter baris dataframe yang indeksnya adalah MultiIndex ?

  • Mengiris berdasarkan satu nilai / label
  • Mengiris berdasarkan beberapa label dari satu atau lebih level
  • Pemfilteran pada kondisi dan ekspresi boolean
  • Metode mana yang dapat diterapkan dalam keadaan apa

Asumsi untuk kesederhanaan:

  1. input dataframe tidak memiliki kunci indeks duplikat
  2. input dataframe dibawah ini hanya memiliki dua level. (Sebagian besar solusi yang ditampilkan di sini digeneralisasikan ke level N)

Contoh masukan:

mux = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    list('tuvwtuvwtuvwtuvw')
], names=['one', 'two'])

df = pd.DataFrame({'col': np.arange(len(mux))}, mux)

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    u      5
    v      6
    w      7
    t      8
c   u      9
    v     10
d   w     11
    t     12
    u     13
    v     14
    w     15

Pertanyaan 1: Memilih Satu Item

Bagaimana cara memilih baris yang memiliki "a" di tingkat "satu"?

         col
one two     
a   t      0
    u      1
    v      2
    w      3

Selain itu, bagaimana saya bisa menurunkan level "satu" pada output?

     col
two     
t      0
u      1
v      2
w      3

Pertanyaan 1b
Bagaimana cara saya memotong semua baris dengan nilai "t" pada level "dua"?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

Pertanyaan 2: Memilih Beberapa Nilai dalam Suatu Tingkat

Bagaimana cara memilih baris yang sesuai dengan item "b" dan "d" di level "satu"?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

Pertanyaan 2b
Bagaimana cara mendapatkan semua nilai yang sesuai dengan "t" dan "w" di level "dua"?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

Pertanyaan 3: Mengiris Penampang Tunggal (x, y)

Bagaimana cara mengambil penampang, yaitu, satu baris yang memiliki nilai tertentu untuk indeks df? Secara khusus, bagaimana cara mengambil penampang ('c', 'u'), yang diberikan oleh

         col
one two     
c   u      9

Pertanyaan 4: Mengiris Beberapa Penampang Silang [(a, b), (c, d), ...]

Bagaimana cara memilih dua baris yang sesuai dengan ('c', 'u'), dan ('a', 'w')?

         col
one two     
c   u      9
a   w      3

Pertanyaan 5: Satu Item Diiris per Level

Bagaimana saya bisa mengambil semua baris yang sesuai dengan "a" di tingkat "satu" atau "t" di tingkat "dua"?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12

Pertanyaan 6: Pemotongan Sewenang-wenang

Bagaimana cara saya memotong penampang melintang tertentu? Untuk "a" dan "b", saya ingin memilih semua baris dengan sub-level "u" ​​dan "v", dan untuk "d", saya ingin memilih baris dengan sub-level "w".

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

Pertanyaan 7 akan menggunakan penyiapan unik yang terdiri dari tingkat numerik:

np.random.seed(0)
mux2 = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    np.random.choice(10, size=16)
], names=['one', 'two'])

df2 = pd.DataFrame({'col': np.arange(len(mux2))}, mux2)

         col
one two     
a   5      0
    0      1
    3      2
    3      3
b   7      4
    9      5
    3      6
    5      7
    2      8
c   4      9
    7     10
d   6     11
    8     12
    8     13
    1     14
    6     15

Pertanyaan 7: Memfilter menurut pertidaksamaan numerik pada setiap level multiindeks

Bagaimana cara mendapatkan semua baris yang nilai pada level "dua" lebih besar dari 5?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

Catatan: Posting ini tidak akan membahas cara membuat MultiIndex, cara melakukan operasi penugasan, atau diskusi terkait performa (ini adalah topik terpisah untuk lain waktu).

cs95
sumber

Jawaban:

166

MultiIndex / Pengindeksan Lanjutan

Catatan
Posting ini akan disusun dengan cara berikut:

  1. Pertanyaan-pertanyaan yang diajukan dalam OP akan dibahas satu per satu
  2. Untuk setiap pertanyaan, satu atau lebih metode yang dapat diterapkan untuk memecahkan masalah ini dan mendapatkan hasil yang diharapkan akan didemonstrasikan.

Catatan (seperti ini) akan disertakan bagi pembaca yang tertarik mempelajari tentang fungsionalitas tambahan, detail implementasi, dan info sepintas lainnya untuk topik yang sedang dibahas. Catatan ini telah disusun dengan menjelajahi dokumen dan mengungkap berbagai fitur yang tidak jelas, dan dari pengalaman saya sendiri (yang memang terbatas).

Semua contoh kode telah dibuat dan diuji pada pandas v0.23.4, python3.7 . Jika ada sesuatu yang tidak jelas, atau tidak benar secara faktual, atau jika Anda tidak menemukan solusi yang sesuai untuk kasus penggunaan Anda, jangan ragu untuk menyarankan pengeditan, meminta klarifikasi di komentar, atau membuka pertanyaan baru, .... sebagaimana berlaku .

Berikut adalah pengantar beberapa idiom umum (untuk selanjutnya disebut sebagai Empat Idiom) yang akan sering kita kunjungi kembali

  1. DataFrame.loc- Solusi umum untuk pemilihan berdasarkan label (+ pd.IndexSliceuntuk aplikasi yang lebih kompleks yang melibatkan irisan)

  2. DataFrame.xs - Ekstrak penampang tertentu dari Seri / DataFrame.

  3. DataFrame.query- Tentukan operasi pemotongan dan / atau pemfilteran secara dinamis (misalnya, sebagai ekspresi yang dievaluasi secara dinamis. Lebih dapat diterapkan pada beberapa skenario daripada yang lain. Lihat juga bagian dokumen ini untuk melakukan kueri di MultiIndex.

  4. Pengindeksan Boolean dengan mask yang dibuat menggunakan MultiIndex.get_level_values(sering kali berhubungan dengan Index.isin, terutama saat memfilter dengan beberapa nilai). Ini juga cukup berguna dalam beberapa situasi.

Akan bermanfaat untuk melihat berbagai masalah pemotongan dan pemfilteran dalam kaitannya dengan Empat Idiom untuk mendapatkan pemahaman yang lebih baik tentang apa yang dapat diterapkan pada situasi tertentu. Sangat penting untuk dipahami bahwa tidak semua idiom akan bekerja sama dengan baik (jika ada) dalam setiap keadaan. Jika idiom belum dicantumkan sebagai solusi potensial untuk masalah di bawah ini, itu berarti idiom tidak dapat diterapkan pada masalah itu secara efektif.


pertanyaan 1

Bagaimana cara memilih baris yang memiliki "a" di tingkat "satu"?

         col
one two     
a   t      0
    u      1
    v      2
    w      3

Anda dapat menggunakan loc, sebagai solusi tujuan umum yang berlaku untuk sebagian besar situasi:

df.loc[['a']]

Pada titik ini, jika Anda mendapatkan

TypeError: Expected tuple, got str

Itu berarti Anda menggunakan panda versi lama. Pertimbangkan untuk meningkatkan! Jika tidak, gunakan df.loc[('a', slice(None)), :].

Alternatifnya, Anda dapat menggunakan di xssini, karena kami mengekstraksi satu penampang lintang. Perhatikan argumen levelsdan axis(default yang masuk akal dapat diasumsikan di sini).

df.xs('a', level=0, axis=0, drop_level=False)
# df.xs('a', drop_level=False)

Di sini, drop_level=Falseargumen diperlukan untuk mencegah xspenurunan level "satu" dalam hasil (level yang kita potong).

Namun opsi lain di sini adalah menggunakan query:

df.query("one == 'a'")

Jika indeks tidak memiliki nama, Anda perlu mengubah string kueri Anda menjadi "ilevel_0 == 'a'".

Terakhir, menggunakan get_level_values:

df[df.index.get_level_values('one') == 'a']
# If your levels are unnamed, or if you need to select by position (not label),
# df[df.index.get_level_values(0) == 'a']

Selain itu, bagaimana saya bisa menurunkan level "satu" pada output?

     col
two     
t      0
u      1
v      2
w      3

Ini dapat dengan mudah dilakukan dengan menggunakan keduanya

df.loc['a'] # Notice the single string argument instead the list.

Atau,

df.xs('a', level=0, axis=0, drop_level=True)
# df.xs('a')

Perhatikan bahwa kita dapat menghilangkan drop_levelargumen (diasumsikan secara Truedefault).

Catatan
Anda mungkin memperhatikan bahwa DataFrame yang difilter mungkin masih memiliki semua level, bahkan jika mereka tidak muncul saat mencetak DataFrame. Sebagai contoh,

v = df.loc[['a']]
print(v)
         col
one two     
a   t      0
    u      1
    v      2
    w      3

print(v.index)
MultiIndex(levels=[['a', 'b', 'c', 'd'], ['t', 'u', 'v', 'w']],
           labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
           names=['one', 'two'])

Anda dapat menghilangkan level ini menggunakan MultiIndex.remove_unused_levels:

v.index = v.index.remove_unused_levels()

print(v.index)
MultiIndex(levels=[['a'], ['t', 'u', 'v', 'w']],
           labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
           names=['one', 'two'])

Pertanyaan 1b

Bagaimana cara saya memotong semua baris dengan nilai "t" pada level "dua"?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

Secara intuitif, Anda menginginkan sesuatu yang melibatkan slice():

df.loc[(slice(None), 't'), :]

It Just Works! ™ Tapi itu kikuk. Kami dapat memfasilitasi sintaks pemotongan yang lebih alami menggunakan pd.IndexSliceAPI di sini.

idx = pd.IndexSlice
df.loc[idx[:, 't'], :]

Ini jauh lebih bersih.

Catatan
Mengapa potongan trailing :melintasi kolom diperlukan? Ini karena, locdapat digunakan untuk memilih dan mengiris sepanjang kedua sumbu ( axis=0atau axis=1). Tanpa secara eksplisit menjelaskan pada sumbu mana pemotongan harus dilakukan, operasi menjadi ambigu. Lihat kotak merah besar di dokumentasi tentang mengiris .

Jika Anda ingin menghilangkan bayangan ambiguitas, locterima axis parameter:

df.loc(axis=0)[pd.IndexSlice[:, 't']]

Tanpa axisparameter (yaitu, hanya dengan melakukan df.loc[pd.IndexSlice[:, 't']]), pemotongan diasumsikan berada pada kolom, dan a KeyErrorakan dimunculkan dalam keadaan ini.

Ini didokumentasikan di pemotong . Untuk tujuan posting ini, bagaimanapun, kami akan secara eksplisit menentukan semua sumbu.

Dengan xs, itu

df.xs('t', axis=0, level=1, drop_level=False)

Dengan query, itu

df.query("two == 't'")
# Or, if the first level has no name, 
# df.query("ilevel_1 == 't'") 

Dan akhirnya, dengan get_level_values, Anda dapat melakukannya

df[df.index.get_level_values('two') == 't']
# Or, to perform selection by position/integer,
# df[df.index.get_level_values(1) == 't']

Semua untuk efek yang sama.


Pertanyaan 2

Bagaimana cara memilih baris yang sesuai dengan item "b" dan "d" di level "satu"?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

Menggunakan loc, ini dilakukan dengan cara yang sama dengan menentukan daftar.

df.loc[['b', 'd']]

Untuk mengatasi masalah memilih "b" dan "d" di atas, Anda juga dapat menggunakan query:

items = ['b', 'd']
df.query("one in @items")
# df.query("one == @items", parser='pandas')
# df.query("one in ['b', 'd']")
# df.query("one == ['b', 'd']", parser='pandas')

Catatan
Ya, parser default adalah 'pandas', tetapi penting untuk menyoroti sintaks ini bukan python konvensional. Parser Pandas menghasilkan pohon parse yang sedikit berbeda dari ekspresi. Ini dilakukan untuk membuat beberapa operasi lebih intuitif untuk ditentukan. Untuk informasi lebih lanjut, silakan baca posting saya tentang Evaluasi Ekspresi Dinamis di pandas menggunakan pd.eval () .

Dan, dengan get_level_values+ Index.isin:

df[df.index.get_level_values("one").isin(['b', 'd'])]

Pertanyaan 2b

Bagaimana saya mendapatkan semua nilai yang sesuai dengan "t" dan "w" di level "dua"?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

Dengan loc, ini hanya mungkin dalam hubungannya dengan pd.IndexSlice.

df.loc[pd.IndexSlice[:, ['t', 'w']], :] 

Usus besar pertama :di pd.IndexSlice[:, ['t', 'w']]sarana untuk mengiris di tingkat pertama. Saat kedalaman level yang ditanyakan meningkat, Anda perlu menentukan lebih banyak irisan, satu per level yang dipotong. Namun, Anda tidak perlu menentukan lebih banyak level selain yang sedang diiris.

Dengan query, ini

items = ['t', 'w']
df.query("two in @items")
# df.query("two == @items", parser='pandas') 
# df.query("two in ['t', 'w']")
# df.query("two == ['t', 'w']", parser='pandas')

Dengan get_level_valuesdan Index.isin(mirip dengan di atas):

df[df.index.get_level_values('two').isin(['t', 'w'])]

Pertanyaan 3

Bagaimana cara mengambil penampang, yaitu, satu baris yang memiliki nilai tertentu untuk indeks df? Secara khusus, bagaimana cara mengambil penampang ('c', 'u'), yang diberikan oleh

         col
one two     
c   u      9

Gunakan locdengan menentukan tuple kunci:

df.loc[('c', 'u'), :]

Atau,

df.loc[pd.IndexSlice[('c', 'u')]]

Catatan
Pada titik ini, Anda mungkin mengalami PerformanceWarningyang terlihat seperti ini:

PerformanceWarning: indexing past lexsort depth may impact performance.

Ini hanya berarti indeks Anda tidak diurutkan. panda bergantung pada indeks yang diurutkan (dalam hal ini, secara leksikografis, karena kita berurusan dengan nilai string) untuk pencarian dan pengambilan yang optimal. Perbaikan cepat adalah mengurutkan DataFrame Anda terlebih dahulu menggunakan DataFrame.sort_index. Ini terutama diinginkan dari sudut pandang kinerja jika Anda berencana melakukan beberapa kueri seperti itu secara bersamaan:

df_sort = df.sort_index()
df_sort.loc[('c', 'u')]

Anda juga dapat menggunakan MultiIndex.is_lexsorted()untuk memeriksa apakah indeks diurutkan atau tidak. Fungsi ini mengembalikan Trueatau Falsesesuai. Anda dapat memanggil fungsi ini untuk menentukan apakah langkah pengurutan tambahan diperlukan atau tidak.

Dengan xs, ini lagi-lagi hanya meneruskan satu tupel sebagai argumen pertama, dengan semua argumen lain disetel ke default yang sesuai:

df.xs(('c', 'u'))

Dengan query, hal-hal menjadi agak kikuk:

df.query("one == 'c' and two == 'u'")

Anda sekarang dapat melihat bahwa ini akan relatif sulit untuk digeneralisasikan. Tapi masih oke untuk masalah khusus ini.

Dengan akses yang mencakup beberapa level, get_level_valuesmasih dapat digunakan, tetapi tidak disarankan:

m1 = (df.index.get_level_values('one') == 'c')
m2 = (df.index.get_level_values('two') == 'u')
df[m1 & m2]

Pertanyaan 4

Bagaimana cara memilih dua baris yang sesuai dengan ('c', 'u'), dan ('a', 'w')?

         col
one two     
c   u      9
a   w      3

Dengan loc, ini masih sesederhana:

df.loc[[('c', 'u'), ('a', 'w')]]
# df.loc[pd.IndexSlice[[('c', 'u'), ('a', 'w')]]]

Dengan query, Anda perlu membuat string kueri secara dinamis dengan melakukan iterasi pada lintas bagian dan level Anda:

cses = [('c', 'u'), ('a', 'w')]
levels = ['one', 'two']
# This is a useful check to make in advance.
assert all(len(levels) == len(cs) for cs in cses) 

query = '(' + ') or ('.join([
    ' and '.join([f"({l} == {repr(c)})" for l, c in zip(levels, cs)]) 
    for cs in cses
]) + ')'

print(query)
# ((one == 'c') and (two == 'u')) or ((one == 'a') and (two == 'w'))

df.query(query)

100% JANGAN MEREKOMENDASIKAN! Tapi itu mungkin.


Pertanyaan 5

Bagaimana saya bisa mengambil semua baris yang sesuai dengan "a" di tingkat "satu" atau "t" di tingkat "dua"?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12

Ini sebenarnya sangat sulit dilakukan dengan loctetap memastikan kebenaran dan tetap menjaga kejelasan kode. df.loc[pd.IndexSlice['a', 't']]tidak benar, itu diartikan sebagai df.loc[pd.IndexSlice[('a', 't')]](yaitu, memilih penampang lintang). Anda mungkin memikirkan solusi pd.concatuntuk menangani setiap label secara terpisah:

pd.concat([
    df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])

         col
one two     
a   t      0
    u      1
    v      2
    w      3
    t      0   # Does this look right to you? No, it isn't!
b   t      4
    t      8
d   t     12

Tapi Anda akan melihat salah satu baris digandakan. Ini karena baris tersebut memenuhi kedua kondisi pemotongan, dan muncul dua kali. Anda harus melakukannya

v = pd.concat([
        df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])
v[~v.index.duplicated()]

Tetapi jika DataFrame Anda secara inheren berisi indeks duplikat (yang Anda inginkan), ini tidak akan mempertahankannya. Gunakan dengan sangat hati-hati .

Dengan query, ini sangat sederhana:

df.query("one == 'a' or two == 't'")

Dengan get_level_values, ini masih sederhana, tetapi tidak seelegan:

m1 = (df.index.get_level_values('one') == 'a')
m2 = (df.index.get_level_values('two') == 't')
df[m1 | m2] 

Pertanyaan 6

Bagaimana cara saya memotong penampang melintang tertentu? Untuk "a" dan "b", saya ingin memilih semua baris dengan sub-level "u" ​​dan "v", dan untuk "d", saya ingin memilih baris dengan sub-level "w".

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

Ini adalah kasus khusus yang saya tambahkan untuk membantu memahami penerapan Empat Idiom — ini adalah satu kasus di mana tidak satupun dari mereka akan bekerja secara efektif, karena pemotongannya sangat spesifik, dan tidak mengikuti pola nyata apa pun.

Biasanya, masalah pemotongan seperti ini memerlukan pengalihan daftar kunci secara eksplisit ke loc. Salah satu cara untuk melakukannya adalah dengan:

keys = [('a', 'u'), ('a', 'v'), ('b', 'u'), ('b', 'v'), ('d', 'w')]
df.loc[keys, :]

Jika Anda ingin menyimpan beberapa pengetikan, Anda akan mengenali bahwa terdapat pola pemotongan "a", "b" dan sublevelnya, sehingga kita dapat memisahkan tugas pemotongan menjadi dua bagian dan concathasilnya:

pd.concat([
     df.loc[(('a', 'b'), ('u', 'v')), :], 
     df.loc[('d', 'w'), :]
   ], axis=0)

Spesifikasi pemotongan untuk "a" dan "b" sedikit lebih bersih (('a', 'b'), ('u', 'v'))karena sub-level yang sama yang diindeks juga sama untuk setiap level.


Pertanyaan 7

Bagaimana cara mendapatkan semua baris yang nilai pada level "dua" lebih besar dari 5?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

Ini bisa dilakukan dengan query,

df2.query("two > 5")

Dan get_level_values.

df2[df2.index.get_level_values('two') > 5]

Catatan
Mirip dengan contoh ini, kita dapat memfilter berdasarkan kondisi sembarang apa pun menggunakan konstruksi ini. Secara umum, penting untuk diingat bahwa locdan xssecara khusus untuk pengindeksan berbasis label, sementara querydan get_level_valuesberguna untuk membangun masker bersyarat umum untuk pemfilteran.


Pertanyaan Bonus

Bagaimana jika saya perlu memotong MultiIndex kolom ?

Sebenarnya, sebagian besar solusi di sini juga berlaku untuk kolom, dengan sedikit perubahan. Mempertimbangkan:

np.random.seed(0)
mux3 = pd.MultiIndex.from_product([
        list('ABCD'), list('efgh')
], names=['one','two'])

df3 = pd.DataFrame(np.random.choice(10, (3, len(mux))), columns=mux3)
print(df3)

one  A           B           C           D         
two  e  f  g  h  e  f  g  h  e  f  g  h  e  f  g  h
0    5  0  3  3  7  9  3  5  2  4  7  6  8  8  1  6
1    7  7  8  1  5  9  8  9  4  3  0  3  5  0  2  3
2    8  1  3  3  3  7  0  1  9  9  0  4  7  3  2  7

Ini adalah perubahan berikut yang perlu Anda lakukan pada Empat Idiom agar dapat bekerja dengan kolom.

  1. Untuk mengiris loc, gunakan

    df3.loc[:, ....] # Notice how we slice across the index with `:`. 

    atau,

    df3.loc[:, pd.IndexSlice[...]]
  2. Untuk menggunakan yang xssesuai, cukup berikan argumen axis=1.

  3. Anda dapat mengakses nilai level kolom secara langsung menggunakan df.columns.get_level_values. Anda kemudian perlu melakukan sesuatu seperti

    df.loc[:, {condition}] 

    Dimana {condition}mewakili beberapa kondisi yang dibangun dengan menggunakan columns.get_level_values.

  4. Untuk menggunakan query, satu-satunya pilihan Anda adalah mengubah urutan, kueri pada indeks, dan mengubah urutan lagi:

    df3.T.query(...).T

    Tidak disarankan, gunakan salah satu dari 3 opsi lainnya.

cs95
sumber
6

Baru-baru ini saya menemukan kasus penggunaan di mana saya memiliki kerangka data multi-indeks 3+ level di mana saya tidak dapat membuat solusi di atas menghasilkan hasil yang saya cari. Sangat mungkin bahwa solusi di atas tentu saja berfungsi untuk kasus penggunaan saya, dan saya mencoba beberapa, namun saya tidak dapat membuatnya berfungsi dengan waktu yang saya miliki.

Saya jauh dari ahli, tetapi saya menemukan solusi yang tidak tercantum dalam jawaban komprehensif di atas. Saya tidak memberikan jaminan bahwa solusinya optimal.

Ini adalah cara berbeda untuk mendapatkan hasil yang sedikit berbeda dengan Pertanyaan # 6 di atas. (dan kemungkinan pertanyaan lain juga)

Secara khusus saya mencari:

  1. Cara untuk memilih dua nilai + dari satu tingkat indeks dan satu nilai dari tingkat indeks lain, dan
  2. Sebuah cara untuk meninggalkan nilai indeks dari operasi sebelumnya dalam output dataframe.

Sebagai kunci pas monyet di roda gigi (betapapun bisa diperbaiki):

  1. Indeks tidak disebutkan namanya.

Pada dataframe mainan di bawah ini:

    index = pd.MultiIndex.from_product([['a','b'],
                               ['stock1','stock2','stock3'],
                               ['price','volume','velocity']])

    df = pd.DataFrame([1,2,3,4,5,6,7,8,9,
                      10,11,12,13,14,15,16,17,18], 
                       index)

                        0
    a stock1 price      1
             volume     2
             velocity   3
      stock2 price      4
             volume     5
             velocity   6
      stock3 price      7
             volume     8
             velocity   9
    b stock1 price     10
             volume    11
             velocity  12
      stock2 price     13
             volume    14
             velocity  15
      stock3 price     16
             volume    17
             velocity  18

Menggunakan pekerjaan di bawah ini, tentu saja:

    df.xs(('stock1', 'velocity'), level=(1,2))

        0
    a   3
    b  12

Tetapi saya menginginkan hasil yang berbeda, jadi metode saya untuk mendapatkan hasil itu adalah:

   df.iloc[df.index.isin(['stock1'], level=1) & 
           df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
    b stock1 velocity  12

Dan jika saya menginginkan dua nilai + dari satu level dan satu (atau 2+) nilai dari level lain:

    df.iloc[df.index.isin(['stock1','stock3'], level=1) & 
            df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
      stock3 velocity   9
    b stock1 velocity  12
      stock3 velocity  18

Metode di atas mungkin agak kikuk, namun menurut saya metode ini memenuhi kebutuhan saya dan sebagai bonus, lebih mudah bagi saya untuk memahami dan membaca.

ra
sumber
2
Bagus, tidak tahu tentang levelargumen untuk Index.isin!
cs95