memilih dari panda multi-indeks

91

Saya memiliki bingkai data multi-indeks dengan kolom 'A' dan 'B'.

Apakah ada cara untuk memilih baris dengan memfilter pada satu kolom multi-indeks tanpa menyetel ulang indeks ke indeks satu kolom?

Sebagai contoh.

# has multi-index (A,B)
df
#can I do this? I know this doesn't work because the index is multi-index so I need to     specify a tuple

df.ix[df.A ==1]
peredam suara
sumber
kemungkinan duplikat dari Cara memperbarui subset dari DataFrame pandas MultiIndexed
Andy Hayden
Terkait: Pilih baris dalam pandas MultiIndex DataFrame (diskusi luas tentang topik yang sama oleh saya).
cs95

Jawaban:

136

Salah satu caranya adalah dengan menggunakan get_level_valuesmetode Indeks:

In [11]: df
Out[11]:
     0
A B
1 4  1
2 5  2
3 6  3

In [12]: df.iloc[df.index.get_level_values('A') == 1]
Out[12]:
     0
A B
1 4  1

Dalam 0.13 Anda akan dapat menggunakan xsdengan drop_levelargumen :

df.xs(1, level='A', drop_level=False) # axis=1 if columns

Catatan: jika ini adalah kolom MultiIndex daripada indeks, Anda dapat menggunakan teknik yang sama:

In [21]: df1 = df.T

In [22]: df1.iloc[:, df1.columns.get_level_values('A') == 1]
Out[22]:
A  1
B  4
0  1
Andy Hayden
sumber
53

Anda juga dapat menggunakan queryyang sangat mudah dibaca menurut saya dan langsung digunakan:

import pandas as pd

df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [10, 20, 50, 80], 'C': [6, 7, 8, 9]})
df = df.set_index(['A', 'B'])

      C
A B    
1 10  6
2 20  7
3 50  8
4 80  9

Untuk apa yang ada dalam pikiran Anda, Anda sekarang dapat melakukan:

df.query('A == 1')

      C
A B    
1 10  6

Anda juga dapat memiliki kueri yang lebih kompleks menggunakan and

df.query('A >= 1 and B >= 50')

      C
A B    
3 50  8
4 80  9

dan or

df.query('A == 1 or B >= 50')

      C
A B    
1 10  6
3 50  8
4 80  9

Anda juga dapat melakukan kueri pada tingkat indeks yang berbeda , misalnya

df.query('A == 1 or C >= 8')

akan kembali

      C
A B    
1 10  6
3 50  8
4 80  9

Jika Anda ingin menggunakan variabel di dalam kueri Anda@ , Anda dapat menggunakan :

b_threshold = 20
c_threshold = 8

df.query('B >= @b_threshold and C <= @c_threshold')

      C
A B    
2 20  7
3 50  8
Cleb
sumber
1
Jawaban bagus, memang jauh lebih mudah dibaca. Apakah Anda tahu apakah mungkin untuk menanyakan dua bidang pada tingkat indeks yang berbeda seperti:df.query('A == 1 or C >= 8')
obchardon
@obchardon: Tampaknya berfungsi dengan baik; Saya mengedit jawaban saya menggunakan contoh Anda.
Cleb
1
Saya memiliki waktu dan string sebagai multiindex yang membuat masalah dalam ekspresi string. Namun, df.query()berfungsi dengan baik dengan variabel jika mereka dirujuk dengan '@' di dalam ekspresi dalam kueri, misalnya df.query('A == @var) untuk variabel vardi lingkungan.
Solly
@Solly: Terima kasih, saya menambahkan ini ke jawabannya.
Cleb
Di mana multi-pengindeksan di sini?
Lamma
32

Anda dapat menggunakan DataFrame.xs():

In [36]: df = DataFrame(np.random.randn(10, 4))

In [37]: df.columns = [np.random.choice(['a', 'b'], size=4).tolist(), np.random.choice(['c', 'd'], size=4)]

In [38]: df.columns.names = ['A', 'B']

In [39]: df
Out[39]:
A      b             a
B      d      d      d      d
0 -1.406  0.548 -0.635  0.576
1 -0.212 -0.583  1.012 -1.377
2  0.951 -0.349 -0.477 -1.230
3  0.451 -0.168  0.949  0.545
4 -0.362 -0.855  1.676 -2.881
5  1.283  1.027  0.085 -1.282
6  0.583 -1.406  0.327 -0.146
7 -0.518 -0.480  0.139  0.851
8 -0.030 -0.630 -1.534  0.534
9  0.246 -1.558 -1.885 -1.543

In [40]: df.xs('a', level='A', axis=1)
Out[40]:
B      d      d
0 -0.635  0.576
1  1.012 -1.377
2 -0.477 -1.230
3  0.949  0.545
4  1.676 -2.881
5  0.085 -1.282
6  0.327 -0.146
7  0.139  0.851
8 -1.534  0.534
9 -1.885 -1.543

Jika Anda ingin mempertahankan Alevel ( drop_levelargumen kata kunci hanya tersedia mulai dari v0.13.0):

In [42]: df.xs('a', level='A', axis=1, drop_level=False)
Out[42]:
A      a
B      d      d
0 -0.635  0.576
1  1.012 -1.377
2 -0.477 -1.230
3  0.949  0.545
4  1.676 -2.881
5  0.085 -1.282
6  0.327 -0.146
7  0.139  0.851
8 -1.534  0.534
9 -1.885 -1.543
Phillip Cloud
sumber
1
Ha, saya baru saja memperbarui jawaban saya dengan itu, Catatan: hanya tersedia di 0.13.
Andy Hayden
Oh, senang mengetahuinya. Saya tidak pernah ingat kemudahan kecil mana yang ditambahkan di setiap versi.
Phillip Cloud
Lol, sebenarnya pertanyaan ini adalah penipuan dari salah satu yang menginspirasi kenyamanan itu! :)
Andy Hayden
13

Memahami cara mengakses pandas multi-indeks DataFrame dapat membantu Anda dengan semua jenis tugas seperti itu.

Salin tempel ini di kode Anda untuk menghasilkan contoh:

# hierarchical indices and columns
index = pd.MultiIndex.from_product([[2013, 2014], [1, 2]],
                                   names=['year', 'visit'])
columns = pd.MultiIndex.from_product([['Bob', 'Guido', 'Sue'], ['HR', 'Temp']],
                                     names=['subject', 'type'])

# mock some data
data = np.round(np.random.randn(4, 6), 1)
data[:, ::2] *= 10
data += 37

# create the DataFrame
health_data = pd.DataFrame(data, index=index, columns=columns)
health_data

Akan memberi Anda tabel seperti ini:

masukkan deskripsi gambar di sini

Akses standar menurut kolom

health_data['Bob']
type       HR   Temp
year visit      
2013    1   22.0    38.6
        2   52.0    38.3
2014    1   30.0    38.9
        2   31.0    37.3


health_data['Bob']['HR']
year  visit
2013  1        22.0
      2        52.0
2014  1        30.0
      2        31.0
Name: HR, dtype: float64

# filtering by column/subcolumn - your case:
health_data['Bob']['HR']==22
year  visit
2013  1         True
      2        False
2014  1        False
      2        False

health_data['Bob']['HR'][2013]    
visit
1    22.0
2    52.0
Name: HR, dtype: float64

health_data['Bob']['HR'][2013][1]
22.0

Akses berdasarkan baris

health_data.loc[2013]
subject Bob Guido   Sue
type    HR  Temp    HR  Temp    HR  Temp
visit                       
1   22.0    38.6    40.0    38.9    53.0    37.5
2   52.0    38.3    42.0    34.6    30.0    37.7

health_data.loc[2013,1] 
subject  type
Bob      HR      22.0
         Temp    38.6
Guido    HR      40.0
         Temp    38.9
Sue      HR      53.0
         Temp    37.5
Name: (2013, 1), dtype: float64

health_data.loc[2013,1]['Bob']
type
HR      22.0
Temp    38.6
Name: (2013, 1), dtype: float64

health_data.loc[2013,1]['Bob']['HR']
22.0

Mengiris multi-indeks

idx=pd.IndexSlice
health_data.loc[idx[:,1], idx[:,'HR']]
    subject Bob Guido   Sue
type    HR  HR  HR
year    visit           
2013    1   22.0    40.0    53.0
2014    1   30.0    52.0    45.0
Harvey
sumber
ini memberikan ValueError: cannot handle a non-unique multi-index!kesalahan
Coddy
5

Anda dapat menggunakan DataFrame.loc:

>>> df.loc[1]

Contoh

>>> print(df)
       result
A B C        
1 1 1       6
    2       9
  2 1       8
    2      11
2 1 1       7
    2      10
  2 1       9
    2      12

>>> print(df.loc[1])
     result
B C        
1 1       6
  2       9
2 1       8
  2      11

>>> print(df.loc[2, 1])
   result
C        
1       7
2      10
umn
sumber
Ini adalah yang terbaik dari pendekatan modern IMO, di mana df.loc [2, 1] ['result'] akan menangani multi-kolom
Michael
ini bekerja dengan sejumlah bilangan bulat untuk beberapa alasan. misalnyadf.loc[0], df.loc[1]....df.loc[n]
Coddy
2

Pilihan lainnya adalah:

filter1 = df.index.get_level_values('A') == 1
filter2 = df.index.get_level_values('B') == 4

df.iloc[filter1 & filter2]
Out[11]:
     0
A B
1 4  1
Gonzalo Goral
sumber