Pertanyaan Pilih baris dari DataFrame berdasarkan nilai dalam kolom di panda


Bagaimana cara memilih baris dari DataFrame berdasarkan nilai di beberapa kolom di panda?
Di SQL saya akan menggunakan:

select * from table where colume_name = some_value. 

Saya mencoba melihat dokumentasi panda tetapi tidak segera menemukan jawabannya.


821
2018-06-12 17:42


asal


Jawaban:


Untuk memilih baris yang nilai kolomnya sama dengan skalar, some_value, gunakan ==:

df.loc[df['column_name'] == some_value]

Untuk memilih baris yang nilai kolomnya dalam iterable, some_values, gunakan isin:

df.loc[df['column_name'].isin(some_values)]

Gabungkan beberapa kondisi dengan &:

df.loc[(df['column_name'] == some_value) & df['other_column'].isin(some_values)]

Untuk memilih baris yang nilai kolomnya tidak sama  some_value, gunakan !=:

df.loc[df['column_name'] != some_value]

isin mengembalikan Seri boolean, jadi untuk memilih baris yang nilainya tidak di some_values, meniadakan Seri boolean menggunakan ~:

df.loc[~df['column_name'].isin(some_values)]

Sebagai contoh,

import pandas as pd
import numpy as np
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split(),
                   'C': np.arange(8), 'D': np.arange(8) * 2})
print(df)
#      A      B  C   D
# 0  foo    one  0   0
# 1  bar    one  1   2
# 2  foo    two  2   4
# 3  bar  three  3   6
# 4  foo    two  4   8
# 5  bar    two  5  10
# 6  foo    one  6  12
# 7  foo  three  7  14

print(df.loc[df['A'] == 'foo'])

hasil

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Jika Anda memiliki beberapa nilai yang ingin Anda sertakan, letakkan mereka dalam daftar (atau lebih umum, setiap iterable) dan gunakan isin:

print(df.loc[df['B'].isin(['one','three'])])

hasil

     A      B  C   D
0  foo    one  0   0
1  bar    one  1   2
3  bar  three  3   6
6  foo    one  6  12
7  foo  three  7  14

Perhatikan, bagaimanapun, bahwa jika Anda ingin melakukan ini berkali-kali, itu lebih efisien buat indeks terlebih dahulu, lalu gunakan df.loc:

df = df.set_index(['B'])
print(df.loc['one'])

hasil

       A  C   D
B              
one  foo  0   0
one  bar  1   2
one  foo  6  12

atau, untuk memasukkan beberapa nilai dari penggunaan indeks df.index.isin:

df.loc[df.index.isin(['one','two'])]

hasil

       A  C   D
B              
one  foo  0   0
one  bar  1   2
two  foo  2   4
two  foo  4   8
two  bar  5  10
one  foo  6  12

1646
2018-06-12 17:44



tl; dr

Panda setara dengan

select * from table where column_name = some_value

aku s

table[table.column_name == some_value]

Beberapa kondisi:

table[(table.column_name == some_value) | (table.column_name2 == some_value2)]

atau

table.query('column_name == some_value | column_name2 == some_value2')

Contoh kode

import pandas as pd

# Create data set
d = {'foo':[100, 111, 222], 
     'bar':[333, 444, 555]}
df = pd.DataFrame(d)

# Full dataframe:
df

# Shows:
#    bar   foo 
# 0  333   100
# 1  444   111
# 2  555   222

# Output only the row(s) in df where foo is 222:
df[df.foo == 222]

# Shows:
#    bar  foo
# 2  555  222

Dalam kode di atas itu adalah garis df[df.foo == 222] yang memberikan baris berdasarkan nilai kolom, 222 pada kasus ini.

Beberapa kondisi juga mungkin:

df[(df.foo == 222) | (df.bar == 444)]
#    bar  foo
# 1  444  111
# 2  555  222

Tetapi pada saat itu saya akan merekomendasikan menggunakan pertanyaan berfungsi, karena kurang verbose dan menghasilkan hasil yang sama:

df.query('foo == 222 | bar == 444')

134
2017-07-08 15:17



Ada beberapa cara dasar untuk memilih baris dari pandas dataframe.

  1. Pengindeksan Boolean
  2. Pengindeksan posisi
  3. Pengindeksan label
  4. API

Untuk setiap jenis dasar, kita dapat menjaga hal-hal sederhana dengan membatasi diri kita sendiri ke API panda atau kita dapat menjelajah di luar API, biasanya menjadi numpy, dan mempercepat segalanya.

Saya akan menunjukkan kepada Anda contoh masing-masing dan membimbing Anda kapan harus menggunakan teknik tertentu.


Mempersiapkan
Hal pertama yang kami perlukan adalah mengidentifikasi kondisi yang akan bertindak sebagai kriteria kami untuk memilih baris. OP menawarkan column_name == some_value. Kami akan mulai di sana dan memasukkan beberapa kasus penggunaan umum lainnya.

Meminjam dari @unutbu:

import pandas as pd, numpy as np

df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split(),
                   'C': np.arange(8), 'D': np.arange(8) * 2})

Asumsikan kriteria kami adalah kolom 'A' = 'foo'

1
Boolean pengindeksan membutuhkan menemukan nilai kebenaran dari setiap baris 'A' kolom sama dengan 'foo', kemudian menggunakan nilai-nilai kebenaran tersebut untuk mengidentifikasi baris mana yang harus disimpan. Biasanya, kami beri nama seri ini, sebuah array nilai kebenaran, mask. Kami akan melakukannya di sini juga.

mask = df['A'] == 'foo'

Kami kemudian dapat menggunakan masker ini untuk mengiris atau mengindeks dataframe

df[mask]

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Ini adalah salah satu cara paling sederhana untuk menyelesaikan tugas ini dan jika kinerja atau intuisi bukan masalah, ini harus menjadi metode pilihan Anda. Namun, jika kinerja menjadi perhatian, Anda mungkin ingin mempertimbangkan cara alternatif untuk membuat mask.


2
Posisi pengindeksan memiliki kasus penggunaannya, tetapi ini bukan salah satunya. Untuk mengidentifikasi ke mana harus mengiris, pertama-tama kita harus melakukan analisis boolean yang sama seperti yang kita lakukan di atas. Ini membuat kita melakukan satu langkah tambahan untuk menyelesaikan tugas yang sama.

mask = df['A'] == 'foo'
pos = np.flatnonzero(mask)
df.iloc[pos]

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

3
Label pengindeksan bisa sangat berguna, tetapi dalam kasus ini, kita sekali lagi melakukan lebih banyak pekerjaan tanpa manfaat

df.set_index('A', append=True, drop=False).xs('foo', level=1)

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

4.
pd.DataFrame.query adalah cara yang sangat elegan / intuitif untuk melakukan tugas ini. Namun seringkali lebih lambat. Namun, jika Anda memperhatikan timing di bawah ini, untuk data yang besar, permintaan sangat efisien. Lebih dari pendekatan standar dan besarnya sama sebagai saran terbaik saya.

df.query('A == "foo"')

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Preferensi saya adalah menggunakan Boolean  mask 

Perbaikan yang sebenarnya dapat dilakukan dengan memodifikasi cara kami membuatnya Boolean  mask.

mask alternatif 1
Gunakan yang mendasarinya numpy larik dan lepaskan overhead membuat yang lain pd.Series 

mask = df['A'].values == 'foo'

Saya akan menunjukkan tes waktu yang lebih lengkap di bagian akhir, tetapi lihat saja perolehan kinerja yang kami peroleh dengan menggunakan bingkai data sampel. Pertama kita melihat perbedaan dalam menciptakan mask

%timeit mask = df['A'].values == 'foo'
%timeit mask = df['A'] == 'foo'

5.84 µs ± 195 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
166 µs ± 4.45 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Mengevaluasi mask dengan numpy array ~ 30 kali lebih cepat. Ini sebagian karena numpy evaluasi seringkali lebih cepat. Ini juga sebagian disebabkan oleh kurangnya overhead yang diperlukan untuk membangun indeks dan yang sesuai pd.Series obyek.

Selanjutnya kita akan melihat waktu untuk mengiris dengan satu mask versus yang lain.

mask = df['A'].values == 'foo'
%timeit df[mask]
mask = df['A'] == 'foo'
%timeit df[mask]

219 µs ± 12.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
239 µs ± 7.03 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Keuntungan kinerja tidak diucapkan. Kita akan melihat apakah ini bertahan lebih dari pengujian yang lebih kuat.


mask alternatif 2
Kita bisa merekonstruksi dataframe juga. Ada peringatan besar ketika merekonstruksi dataframe — Anda harus memperhatikan dtypes saat melakukannya!

Dari pada df[mask] kami akan melakukan ini

pd.DataFrame(df.values[mask], df.index[mask], df.columns).astype(df.dtypes)

Jika dataframe adalah tipe campuran, yang merupakan contoh kita, maka ketika kita mendapatkannya df.values array yang dihasilkan adalah dari dtype  object dan akibatnya, semua kolom dari dataframe baru akan menjadi dtype  object. Sehingga membutuhkan astype(df.dtypes) dan membunuh setiap perolehan kinerja potensial.

%timeit df[m]
%timeit pd.DataFrame(df.values[mask], df.index[mask], df.columns).astype(df.dtypes)

216 µs ± 10.4 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
1.43 ms ± 39.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Namun, jika dataframe bukan tipe campuran, ini adalah cara yang sangat berguna untuk melakukannya.

Diberikan

np.random.seed([3,1415])
d1 = pd.DataFrame(np.random.randint(10, size=(10, 5)), columns=list('ABCDE'))

d1

   A  B  C  D  E
0  0  2  7  3  8
1  7  0  6  8  6
2  0  2  0  4  9
3  7  3  2  4  3
4  3  6  7  7  4
5  5  3  7  5  9
6  8  7  6  4  7
7  6  2  6  6  5
8  2  8  7  5  8
9  4  7  6  1  5    

%%timeit
mask = d1['A'].values == 7
d1[mask]

179 µs ± 8.73 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Melawan

%%timeit
mask = d1['A'].values == 7
pd.DataFrame(d1.values[mask], d1.index[mask], d1.columns)

87 µs ± 5.12 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Kami memotong waktu menjadi dua.


mask alternatif 3
@unutbu juga menunjukkan cara menggunakannya pd.Series.isin untuk memperhitungkan setiap elemen df['A'] berada di satu set nilai. Ini mengevaluasi ke hal yang sama jika set nilai kami adalah satu set nilai, yaitu 'foo'. Tetapi juga menggeneralisasikan untuk memasukkan set nilai yang lebih besar jika diperlukan. Ternyata, ini masih cukup cepat meskipun itu adalah solusi yang lebih umum. Satu-satunya kerugian yang nyata ada pada intuisi bagi mereka yang tidak akrab dengan konsep tersebut.

mask = df['A'].isin(['foo'])
df[mask]

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Namun, seperti sebelumnya, kita bisa memanfaatkannya numpy untuk meningkatkan kinerja sambil mengorbankan hampir tidak ada. Kami akan gunakan np.in1d

mask = np.in1d(df['A'].values, ['foo'])
df[mask]

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Pengaturan waktu
Saya akan memasukkan konsep lain yang disebutkan di posting lain juga sebagai referensi.
Kode Di Bawah 

Setiap Kolom dalam tabel ini mewakili dataframe panjang yang berbeda di mana kita menguji setiap fungsi. Setiap kolom menunjukkan waktu relatif yang diambil, dengan fungsi tercepat diberikan indeks dasar 1.0.

res.div(res.min())

                         10        30        100       300       1000      3000      10000     30000
mask_standard         2.156872  1.850663  2.034149  2.166312  2.164541  3.090372  2.981326  3.131151
mask_standard_loc     1.879035  1.782366  1.988823  2.338112  2.361391  3.036131  2.998112  2.990103
mask_with_values      1.010166  1.000000  1.005113  1.026363  1.028698  1.293741  1.007824  1.016919
mask_with_values_loc  1.196843  1.300228  1.000000  1.000000  1.038989  1.219233  1.037020  1.000000
query                 4.997304  4.765554  5.934096  4.500559  2.997924  2.397013  1.680447  1.398190
xs_label              4.124597  4.272363  5.596152  4.295331  4.676591  5.710680  6.032809  8.950255
mask_with_isin        1.674055  1.679935  1.847972  1.724183  1.345111  1.405231  1.253554  1.264760
mask_with_in1d        1.000000  1.083807  1.220493  1.101929  1.000000  1.000000  1.000000  1.144175

Anda akan melihat bahwa waktu tercepat tampaknya dibagi antara mask_with_values dan mask_with_in1d

res.T.plot(loglog=True)

enter image description here

Fungsi 

def mask_standard(df):
    mask = df['A'] == 'foo'
    return df[mask]

def mask_standard_loc(df):
    mask = df['A'] == 'foo'
    return df.loc[mask]

def mask_with_values(df):
    mask = df['A'].values == 'foo'
    return df[mask]

def mask_with_values_loc(df):
    mask = df['A'].values == 'foo'
    return df.loc[mask]

def query(df):
    return df.query('A == "foo"')

def xs_label(df):
    return df.set_index('A', append=True, drop=False).xs('foo', level=-1)

def mask_with_isin(df):
    mask = df['A'].isin(['foo'])
    return df[mask]

def mask_with_in1d(df):
    mask = np.in1d(df['A'].values, ['foo'])
    return df[mask]

Pengujian 

res = pd.DataFrame(
    index=[
        'mask_standard', 'mask_standard_loc', 'mask_with_values', 'mask_with_values_loc',
        'query', 'xs_label', 'mask_with_isin', 'mask_with_in1d'
    ],
    columns=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    dtype=float
)

for j in res.columns:
    d = pd.concat([df] * j, ignore_index=True)
    for i in res.index:a
        stmt = '{}(d)'.format(i)
        setp = 'from __main__ import d, {}'.format(i)
        res.at[i, j] = timeit(stmt, setp, number=50)

Waktu Khusus
Melihat kasus khusus ketika kita memiliki satu-non-objek dtypeuntuk seluruh dataframe. Kode Di Bawah 

spec.div(spec.min())

                     10        30        100       300       1000      3000      10000     30000
mask_with_values  1.009030  1.000000  1.194276  1.000000  1.236892  1.095343  1.000000  1.000000
mask_with_in1d    1.104638  1.094524  1.156930  1.072094  1.000000  1.000000  1.040043  1.027100
reconstruct       1.000000  1.142838  1.000000  1.355440  1.650270  2.222181  2.294913  3.406735

Ternyata, rekonstruksi tidak layak melewati beberapa ratus baris.

spec.T.plot(loglog=True)

enter image description here

Fungsi 

np.random.seed([3,1415])
d1 = pd.DataFrame(np.random.randint(10, size=(10, 5)), columns=list('ABCDE'))

def mask_with_values(df):
    mask = df['A'].values == 'foo'
    return df[mask]

def mask_with_in1d(df):
    mask = np.in1d(df['A'].values, ['foo'])
    return df[mask]

def reconstruct(df):
    v = df.values
    mask = np.in1d(df['A'].values, ['foo'])
    return pd.DataFrame(v[mask], df.index[mask], df.columns)

spec = pd.DataFrame(
    index=['mask_with_values', 'mask_with_in1d', 'reconstruct'],
    columns=[10, 30, 100, 300, 1000, 3000, 10000, 30000],
    dtype=float
)

Pengujian 

for j in spec.columns:
    d = pd.concat([df] * j, ignore_index=True)
    for i in spec.index:
        stmt = '{}(d)'.format(i)
        setp = 'from __main__ import d, {}'.format(i)
        spec.at[i, j] = timeit(stmt, setp, number=50)

76
2017-09-11 22:14



Saya menemukan sintaks dari jawaban sebelumnya menjadi berlebihan dan sulit untuk diingat. Panda memperkenalkan query() metode di v0.13 dan saya lebih memilihnya. Untuk pertanyaan Anda, Anda bisa melakukannya df.query('col == val')

Direproduksi dari http://pandas.pydata.org/pandas-docs/version/0.17.0/indexing.html#indexing-query

In [167]: n = 10

In [168]: df = pd.DataFrame(np.random.rand(n, 3), columns=list('abc'))

In [169]: df
Out[169]: 
          a         b         c
0  0.687704  0.582314  0.281645
1  0.250846  0.610021  0.420121
2  0.624328  0.401816  0.932146
3  0.011763  0.022921  0.244186
4  0.590198  0.325680  0.890392
5  0.598892  0.296424  0.007312
6  0.634625  0.803069  0.123872
7  0.924168  0.325076  0.303746
8  0.116822  0.364564  0.454607
9  0.986142  0.751953  0.561512

# pure python
In [170]: df[(df.a < df.b) & (df.b < df.c)]
Out[170]: 
          a         b         c
3  0.011763  0.022921  0.244186
8  0.116822  0.364564  0.454607

# query
In [171]: df.query('(a < b) & (b < c)')
Out[171]: 
          a         b         c
3  0.011763  0.022921  0.244186
8  0.116822  0.364564  0.454607

Anda juga dapat mengakses variabel di lingkungan dengan menambahkan @.

exclude = ('red', 'orange')
df.query('color not in @exclude')

41
2018-02-09 01:36



Hasil yang lebih cepat dapat dicapai dengan menggunakan numpy.where.

Misalnya, dengan pengaturan unubtu -

In [76]: df.iloc[np.where(df.A.values=='foo')]
Out[76]: 
     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Perbandingan waktu:

In [68]: %timeit df.iloc[np.where(df.A.values=='foo')]  # fastest
1000 loops, best of 3: 380 µs per loop

In [69]: %timeit df.loc[df['A'] == 'foo']
1000 loops, best of 3: 745 µs per loop

In [71]: %timeit df.loc[df['A'].isin(['foo'])]
1000 loops, best of 3: 562 µs per loop

In [72]: %timeit df[df.A=='foo']
1000 loops, best of 3: 796 µs per loop

In [74]: %timeit df.query('(A=="foo")')  # slowest
1000 loops, best of 3: 1.71 ms per loop

11
2017-07-05 16:34



Berikut ini contoh sederhana

from pandas import DataFrame

# Create data set
d = {'Revenue':[100,111,222], 
     'Cost':[333,444,555]}
df = DataFrame(d)


# mask = Return True when the value in column "Revenue" is equal to 111
mask = df['Revenue'] == 111

print mask

# Result:
# 0    False
# 1     True
# 2    False
# Name: Revenue, dtype: bool


# Select * FROM df WHERE Revenue = 111
df[mask]

# Result:
#    Cost    Revenue
# 1  444     111

10
2018-06-13 11:49



Saya baru saja mencoba mengedit ini, tetapi saya tidak masuk, jadi saya tidak yakin di mana suntingan saya pergi. Saya mencoba menggabungkan beberapa pilihan. Jadi saya pikir jawaban yang lebih baik adalah:

Untuk satu nilai, yang paling mudah (dapat dibaca manusia) mungkin adalah:

df.loc[df['column_name'] == some_value]

Untuk daftar nilai yang juga dapat Anda gunakan:

df.loc[df['column_name'].isin(some_values)]

Sebagai contoh,

import pandas as pd
import numpy as np
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
               'B': 'one one two three two two one three'.split(),
               'C': np.arange(8), 'D': np.arange(8) * 2})
print(df)
#      A      B  C   D
# 0  foo    one  0   0
# 1  bar    one  1   2
# 2  foo    two  2   4
# 3  bar  three  3   6
# 4  foo    two  4   8
# 5  bar    two  5  10
# 6  foo    one  6  12
# 7  foo  three  7  14

print(df.loc[df['A'] == 'foo'])

hasil

     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Jika Anda memiliki beberapa kriteria yang ingin Anda pilih, Anda dapat menempatkannya dalam daftar dan menggunakan 'isin':

print(df.loc[df['B'].isin(['one','three'])])

hasil

      A      B  C   D
0  foo    one  0   0
1  bar    one  1   2
3  bar  three  3   6
6  foo    one  6  12
7  foo  three  7  14

Perhatikan, bagaimanapun, bahwa jika Anda ingin melakukan ini berkali-kali, lebih efisien untuk membuat indeks A pertama, dan kemudian gunakan df.loc:

df = df.set_index(['A'])
print(df.loc['foo'])

hasil

  A      B  C   D
foo    one  0   0
foo    two  2   4
foo    two  4   8
foo    one  6  12
foo  three  7  14

7
2018-01-25 23:27



df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split(),
                   'C': np.arange(8), 'D': np.arange(8) * 2})
df[df['A']=='foo']

OUTPUT:
   A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

3
2018-03-06 06:02