วิธีการเลือกแถวจาก DataFrame ตามค่าคอลัมน์?


1956

จะเลือกแถวจากDataFrameค่าในคอลัมน์ใน Python Pandas ได้อย่างไร?

ใน SQL ฉันจะใช้:

SELECT *
FROM table
WHERE colume_name = some_value

ฉันพยายามดูเอกสารของแพนด้า แต่ไม่พบคำตอบในทันที



6
นี่เป็นการเปรียบเทียบกับ SQL: pandas.pydata.org/pandas-docs/stable/comparison_with_sql.html ซึ่งคุณสามารถเรียกใช้ pandas เป็น SQL ได้
i_thamary

คำตอบ:


3766

ในการเลือกแถวที่ค่าคอลัมน์เท่ากับสเกลาร์some_valueให้ใช้==:

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

ในการเลือกแถวที่มีค่าคอลัมน์อยู่ใน iterable some_valuesให้ใช้isin:

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

รวมหลายเงื่อนไขเข้ากับ&:

df.loc[(df['column_name'] >= A) & (df['column_name'] <= B)]

หมายเหตุวงเล็บ เนื่องจาก ธกฎสำคัญประกอบ , &ผูกแน่นกว่าและ<= >=ดังนั้นวงเล็บในตัวอย่างสุดท้ายจึงมีความจำเป็น โดยไม่ต้องใส่วงเล็บ

df['column_name'] >= A & df['column_name'] <= B

แยกเป็น

df['column_name'] >= (A & df['column_name']) <= B

ซึ่งส่งผลให้ค่าความจริงของซีรีส์เป็นข้อผิดพลาดที่ไม่ชัดเจน


ในการเลือกแถวที่ค่าคอลัมน์ไม่เท่ากัน some_valueใช้!=:

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

isinผลตอบแทนบูลีนซีรีส์เพื่อที่จะเลือกแถวที่มีค่าไม่ได้ในการsome_valuesคัดค้านซีรีส์บูลโดยใช้~:

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

ตัวอย่างเช่น,

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'])

อัตราผลตอบแทน

     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

หากคุณมีหลายค่าที่คุณต้องการรวมให้ใส่ไว้ในรายการ (หรือโดยทั่วไปสามารถทำซ้ำได้) และใช้isin:

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

อัตราผลตอบแทน

     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

อย่างไรก็ตามโปรดทราบว่าหากคุณต้องการทำเช่นนี้หลายครั้งจะมีประสิทธิภาพมากกว่าในการสร้างดัชนีเป็นอันดับแรกจากนั้นใช้df.loc:

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

อัตราผลตอบแทน

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

หรือเพื่อรวมหลายค่าจากการใช้ดัชนีdf.index.isin:

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

อัตราผลตอบแทน

       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

19
อันที่จริงแล้ว df [df ['colume_name'] == some_value] ก็ใช้ได้เช่นกัน แต่ความพยายามครั้งแรกของฉัน, df.where (df ['colume_name'] == some_value) ไม่ทำงาน ... ไม่แน่ใจว่าทำไม ...
szli

13
เมื่อคุณใช้df.where(condition)สภาพจะต้องมีรูปร่างเหมือนdfกัน
unutbu

3
เชื่อมโยงเหล่านั้นอาจจะมีประโยชน์มากในการจำนวนมากของคุณ: pandas.pydata.org/pandas-docs/stable/indexing.html gregreda.com/2013/10/26/working-with-pandas-dataframes
tremendows

8
FYI: หากคุณต้องการเลือกแถวตามป้ายกำกับสอง (หรือมากกว่า) (ทั้งที่ต้องการทั้งสองอย่างหรืออย่างใดอย่างหนึ่ง) ดูstackoverflow.com/questions/31756340/…
เชน

7
เนื่องจากdf[df['column_name'] == some_value]งานเราต้องเพิ่ม.locที่นี่ทำไม
qqqwww

311

มีหลายวิธีในการเลือกแถวจากกรอบข้อมูลแพนด้า:

  1. การจัดทำดัชนีบูลีน ( df[df['col'] == value])
  2. การจัดทำดัชนีตำแหน่ง ( df.iloc[...])
  3. การจัดทำดัชนีป้ายกำกับ ( df.xs(...))
  4. df.query(...) API

ด้านล่างฉันจะแสดงตัวอย่างของแต่ละข้อพร้อมคำแนะนำว่าควรใช้เทคนิคบางอย่างเมื่อใด สมมติว่าเกณฑ์ของเราคือคอลัมน์'A'=='foo'

(หมายเหตุเกี่ยวกับประสิทธิภาพ: สำหรับแต่ละประเภทฐานเราสามารถทำให้สิ่งต่าง ๆ เรียบง่ายโดยใช้ pandas API หรือเราสามารถร่วมนอก API มักจะเป็นnumpyและเร่งสิ่งต่าง ๆ ได้)


การตั้งค่า
สิ่งแรกที่เราต้องมีคือการระบุเงื่อนไขที่จะทำหน้าที่เป็นเกณฑ์ในการเลือกแถว เราจะเริ่มด้วยเคสของ OP column_name == some_valueและรวมเคสที่ใช้งานทั่วไปอื่น ๆ

การกู้ยืมจาก @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})

1. การจัดทำดัชนีบูลีน

... การจัดทำดัชนีบูลีนต้องค้นหาค่าที่แท้จริงของแต่ละแถวของ'A'คอลัมน์ให้เท่ากัน'foo'จากนั้นใช้ค่าความจริงเหล่านั้นเพื่อระบุแถวที่จะเก็บ โดยทั่วไปแล้วเราจะตั้งชื่อชุดนี้ซึ่งมีค่าความจริงmaskมากมาย เราจะทำที่นี่เช่นกัน

mask = df['A'] == '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

นี่เป็นวิธีที่ง่ายที่สุดวิธีหนึ่งในการทำภารกิจนี้ให้สำเร็จและหากประสิทธิภาพหรือความไม่เข้าใจเป็นปัญหานี่ควรเป็นวิธีที่คุณเลือก maskแต่ถ้าผลการดำเนินงานเป็นกังวลแล้วคุณอาจต้องการที่จะต้องพิจารณาทางเลือกของการสร้าง


2. การจัดทำดัชนีตำแหน่ง

การจัดทำดัชนีตำแหน่ง ( df.iloc[...]) มีกรณีการใช้งาน แต่นี่ไม่ใช่หนึ่งในนั้น ในการระบุตำแหน่งที่จะหั่นเราต้องทำการวิเคราะห์บูลีนแบบเดียวกับที่เราทำข้างต้น นี่ทำให้เราดำเนินการขั้นตอนพิเศษหนึ่งขั้นเพื่อให้งานเดียวกันสำเร็จ

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. การจัดทำดัชนีฉลาก

การจัดทำดัชนีฉลากอาจมีประโยชน์มาก แต่ในกรณีนี้เรากำลังทำงานอีกครั้งโดยไม่มีประโยชน์

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. df.query()API

pd.DataFrame.queryเป็นวิธีที่หรูหรา / ใช้งานง่ายมากในการทำงานนี้ แต่มักจะช้ากว่า อย่างไรก็ตามหากคุณใส่ใจกับการกำหนดเวลาด้านล่างสำหรับข้อมูลขนาดใหญ่แบบสอบถามจะมีประสิทธิภาพมาก มากกว่าวิธีมาตรฐานและขนาดใกล้เคียงกันเป็นคำแนะนำที่ดีที่สุดของฉัน

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

การตั้งค่าของฉันคือการใช้ Boolean mask

Boolean maskการปรับปรุงที่เกิดขึ้นจริงสามารถทำได้โดยการปรับเปลี่ยนวิธีการที่เราสร้างของเรา

maskทางเลือก 1
ใช้numpyอาเรย์พื้นฐานและสละค่าใช้จ่ายในการสร้างอีกpd.Series

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

ฉันจะแสดงการทดสอบเวลาที่สมบูรณ์มากขึ้นในตอนท้าย แต่เพียงแค่ดูที่การเพิ่มประสิทธิภาพที่เราได้รับโดยใช้กรอบข้อมูลตัวอย่าง อันดับแรกเรามาดูความแตกต่างในการสร้าง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)

การประเมินmaskกับnumpyอาร์เรย์เป็น ~ 30 ครั้งได้เร็วขึ้น นี่เป็นส่วนหนึ่งเนื่องจากการnumpyประเมินผลมักจะเร็วกว่า ส่วนหนึ่งเป็นเพราะการขาดค่าใช้จ่ายที่จำเป็นในการสร้างดัชนีและpd.Seriesวัตถุที่สอดคล้องกัน

ต่อไปเราจะดูเวลาสำหรับการแบ่งส่วนหนึ่งmaskกับอีกชุด

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)

ประสิทธิภาพที่เพิ่มขึ้นนั้นไม่ได้เด่นชัดเท่าที่ควร เราจะดูว่าการทดสอบนี้มีประสิทธิภาพมากกว่าหรือไม่


maskทางเลือก 2
เราสามารถสร้างกรอบข้อมูลใหม่ได้เช่นกัน มีข้อแม้ที่ยิ่งใหญ่เมื่อทำการสร้างดาต้าเฟรมใหม่ - คุณต้องดูแลdtypesเมื่อทำเช่นนั้น!

แทนที่จะdf[mask]ทำเช่นนี้เราจะทำ

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

หากกรอบข้อมูลเป็นประเภทผสมซึ่งเป็นตัวอย่างของเราแล้วเมื่อเราได้รับdf.valuesอาร์เรย์ที่เกิดเป็นและดังนั้นคอลัมน์ทั้งหมดของกรอบข้อมูลใหม่จะเป็นdtype object dtype objectดังนั้นจึงจำเป็นต้องมีastype(df.dtypes)และฆ่าประสิทธิภาพที่อาจเกิดขึ้นได้

%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)

อย่างไรก็ตามถ้า data frame นั้นไม่ใช่ชนิดแบบผสมนี่เป็นวิธีที่มีประโยชน์มากในการทำ

ป.ร. ให้ไว้

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)

กับ

%%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)

เราลดเวลาลงครึ่งหนึ่ง


maskทางเลือก 3
@unutbu ยังแสดงให้เราเห็นถึงวิธีการใช้pd.Series.isinในการพิจารณาองค์ประกอบแต่ละอย่างของdf['A']การอยู่ในชุดของค่า 'foo'ประเมินนี้ถึงสิ่งเดียวกันถ้าชุดของค่านิยมของเราคือชุดของค่าหนึ่งคือ แต่ยังรวมถึงการรวมชุดของค่าที่ใหญ่กว่าถ้าจำเป็น ปรากฎว่านี่ยังค่อนข้างเร็วแม้ว่ามันจะเป็นคำตอบทั่วไป การสูญเสียที่แท้จริงเพียงอย่างเดียวคือการหยั่งรู้สำหรับผู้ที่ไม่คุ้นเคยกับแนวคิด

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

อย่างไรก็ตามก่อนหน้านี้เราสามารถใช้numpyเพื่อปรับปรุงประสิทธิภาพการทำงานโดยไม่ต้องเสียสละอะไรเลย เราจะใช้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

ช่วงเวลา
ฉันจะรวมแนวคิดอื่น ๆ ที่กล่าวถึงในโพสต์อื่น ๆ ไว้ด้วยเพื่อการอ้างอิง
รหัสด้านล่าง

แต่ละคอลัมน์ในตารางนี้แสดงถึงกรอบข้อมูลความยาวที่แตกต่างกันซึ่งเราทดสอบแต่ละฟังก์ชั่น 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

คุณจะสังเกตเห็นว่าเวลาที่เร็วที่สุดจะถูกแชร์ระหว่างmask_with_valuesและmask_with_in1d

res.T.plot(loglog=True)

ป้อนคำอธิบายรูปภาพที่นี่

ฟังก์ชั่น

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]

การทดสอบ

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)

ช่วงเวลา
พิเศษดูกรณีพิเศษเมื่อเรามีวัตถุที่ไม่ใช่วัตถุเดียวdtypeสำหรับกรอบข้อมูลทั้งหมด รหัสด้านล่าง

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

ปรากฎว่าการสร้างใหม่ไม่คุ้มกับที่ผ่านมาสองสามร้อยแถว

spec.T.plot(loglog=True)

ป้อนคำอธิบายรูปภาพที่นี่

ฟังก์ชั่น

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
)

การทดสอบ

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)

6
คำตอบที่ยอดเยี่ยม! 2 คำถามแม้ว่าฉัน) จะ.iloc(numpy.where(..))เปรียบเทียบในโครงการนี้อย่างไร ii) คุณคาดหวังว่าอันดับจะเหมือนกันเมื่อใช้หลายเงื่อนไขหรือไม่
posdef

3
สำหรับการทำงานของpd.Series.isinโปรดทราบว่ามันไม่ใช้np.in1dภายใต้ประทุนในสถานการณ์เฉพาะที่ใช้ใน Khash คนอื่น ๆ และโดยปริยายใช้การค้าออกระหว่างค่าใช้จ่ายของคร่ำเครียดกับการปฏิบัติงานในสถานการณ์ที่เฉพาะเจาะจง คำตอบนี้มีรายละเอียดเพิ่มเติม
jpp

1
ที่ 9 หน้าจอนี่เป็นวิธีที่มากเกินไปสำหรับผู้ใช้ใหม่หรือผู้ใช้ระดับกลาง คุณสามารถและควรสรุป tl; dr ในย่อหน้าแรกด้วยตนเอง
smci

@piRSquared ขูดหินปูนที่สำคัญคุณจะทราบ @piRSquared ไปยังโพสต์ประสบการณ์ของคุณเกี่ยวกับวิธีการที่ดีที่เกิดขึ้นจริง [{P|EXP}TIME] - และ[{C|P|EXP}SPACE]- ค่าใช้จ่ายของการใช้รูปแบบดังกล่าวข้างต้นที่นำเสนอของบล็อกไวยากรณ์ (การประมวลผลด้านบนลง dataframes ทั้งหมดในครั้งเดียว) เติบโตคือเมื่อ ปรับสัดส่วนเป็นบาง~1E6, ~1E9, ~1E12แถวหรือไม่ ขอบคุณที่แสดงให้เราเห็นภาพรวมทั้งหมดครับ การอ่านค่ามาตรฐานเชิงปริมาณด้วย[min, Avg, MAX, StDev]ยินดีต้อนรับเสมอเนื่องจากทั้งสองค่าminและMAXมาพร้อมกับการMean/StDevผ่อนปรนของแบทช์
user3666197

คำตอบที่ยอดเยี่ยม! แบบสอบถามแก้ปัญหาของฉัน!
Pavlos Ponos

281

TL; DR

หมีแพนด้าเทียบเท่า

select * from table where column_name = some_value

คือ

table[table.column_name == some_value]

หลายเงื่อนไข:

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

หรือ

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

ตัวอย่างรหัส

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

ในรหัสข้างต้นมันเป็นสายdf[df.foo == 222]ที่ให้แถวตามค่าคอลัมน์222ในกรณีนี้

เงื่อนไขหลายข้อยังเป็นไปได้:

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

แต่ ณ จุดนั้นฉันขอแนะนำให้ใช้ฟังก์ชั่นการสืบค้นเนื่องจากมันให้รายละเอียดน้อยกว่าและให้ผลลัพธ์แบบเดียวกัน:

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

5
queryเป็นคำตอบเดียวที่นี่ที่เข้ากันได้กับวิธีการผูกมัด ดูเหมือนว่ามันเป็นหมีแพนด้าอนาล็อกfilterใน dplyr
Berk U.

3
สวัสดีในตัวอย่างที่สามของคุณ (หลายคอลัมน์) ฉันคิดว่าคุณจำเป็นต้องใช้วงเล็บเหลี่ยมที่[ไม่ได้ล้อมรอบ(ด้านนอก
user2739472

2
ที่ผมคิดแรกที่|เป็นและ แต่แน่นอนมันเป็นหรือผู้ประกอบการ ...
O-9

สำหรับหลายเงื่อนไขโดยใช้ AND คุณสามารถทำได้df[condition1][condition2]
Ritwik

1
ออกจากที่นี่ในกรณีที่เป็นประโยชน์กับใครบางคน: จากการค้นหา 0.25 รายการสามารถใช้กับชื่อคอลัมน์ที่มีช่องว่างในชื่อโดยใส่ชื่อไว้ใน backticks:df.query('`my col` == 124')
cs95

65

ฉันพบว่าไวยากรณ์ของคำตอบก่อนหน้านี้ซ้ำซ้อนและจดจำยาก Pandas แนะนำquery()วิธีการใน v0.13 และฉันชอบมันมาก สำหรับคำถามของคุณคุณสามารถทำได้df.query('col == val')

ทำซ้ำจาก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

นอกจากนี้คุณยังสามารถเข้าถึงตัวแปรในสภาพแวดล้อมโดยการ@เพิ่ม

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

1
คุณต้องnumexprติดตั้งแพ็คเกจเท่านั้น
ลด

4
ในกรณีของฉันฉันต้องการใบเสนอราคาเพราะ val เป็นสตริง df.query ('col == "val"')
smerlung

28

ความยืดหยุ่นที่มากขึ้นเมื่อใช้.queryกับpandas >= 0.25.0:

คำตอบที่อัปเดตในเดือนสิงหาคม 2019

เนื่องจากpandas >= 0.25.0เราสามารถใช้queryวิธีการกรองดาต้าเฟรมด้วยเมธอดแพนด้าและชื่อคอลัมน์ที่มีช่องว่าง โดยปกติช่องว่างในชื่อคอลัมน์จะให้ข้อผิดพลาด แต่ตอนนี้เราสามารถแก้ไขได้โดยใช้ backtick (`) ดูGitHub :

# Example dataframe
df = pd.DataFrame({'Sender email':['ex@example.com', "reply@shop.com", "buy@shop.com"]})

     Sender email
0  ex@example.com
1  reply@shop.com
2    buy@shop.com

ใช้.queryกับวิธีการstr.endswith:

df.query('`Sender email`.str.endswith("@shop.com")')

เอาท์พุต

     Sender email
1  reply@shop.com
2    buy@shop.com

นอกจากนี้เรายังสามารถใช้ตัวแปรท้องถิ่นโดยนำหน้าด้วย@คำค้นหาของเรา:

domain = 'shop.com'
df.query('`Sender email`.str.endswith(@domain)')

เอาท์พุต

     Sender email
1  reply@shop.com
2    buy@shop.com

26

ผลได้เร็วขึ้นสามารถทำได้โดยใช้numpy.where

ตัวอย่างเช่นด้วยการตั้งค่า 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

การเปรียบเทียบเวลา:

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

24

นี่คือตัวอย่างง่ายๆ

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

17

สำหรับการเลือกคอลัมน์ที่เฉพาะเจาะจงจากหลายคอลัมน์สำหรับค่าที่กำหนดในนุ่น:

select col_name1, col_name2 from table where column_name = some_value.

ตัวเลือก:

df.loc[df['column_name'] == some_value][[col_name1, col_name2]]

หรือ

df.query['column_name' == 'some_value'][[col_name1, col_name2]]

16

หากต้องการต่อท้ายคำถามที่มีชื่อเสียงนี้ (แม้ว่าจะสายเกินไป): คุณสามารถทำdf.groupby('column_name').get_group('column_desired_value').reset_index()กรอบข้อมูลใหม่ด้วยคอลัมน์ที่ระบุซึ่งมีค่าเฉพาะ เช่น

import pandas as pd
df = pd.DataFrame({'A': 'foo bar foo bar foo bar foo foo'.split(),
                   'B': 'one one two three two two one three'.split()})
print("Original dataframe:")
print(df)

b_is_two_dataframe = pd.DataFrame(df.groupby('B').get_group('two').reset_index()).drop('index', axis = 1) 
#NOTE: the final drop is to remove the extra index column returned by groupby object
print('Sub dataframe where B is two:')
print(b_is_two_dataframe)

เรียกใช้สิ่งนี้ให้:

Original dataframe:
     A      B
0  foo    one
1  bar    one
2  foo    two
3  bar  three
4  foo    two
5  bar    two
6  foo    one
7  foo  three
Sub dataframe where B is two:
     A    B
0  foo  two
1  foo  two
2  bar  two

คำตอบที่ดี เพียงแค่ต้องการเพิ่มที่สอง (pd.DataFrame) ซ้ำซ้อนเพราะget_group()จะส่งคืน dataframe โดยอัตโนมัติ นอกจากนี้คุณก็สามารถพูดว่า "ลดลง = true" reset_index()เป็นพารามิเตอร์ของ กล่าวอีกนัยหนึ่งก็สามารถย่อให้สั้นลงเป็น: b_is_two_dataframe = df.groupby('B').get_group('two').reset_index(drop=True)
Mountain Scott

7

คุณยังสามารถใช้. นำไปใช้:

df.apply(lambda row: row[df['B'].isin(['one','three'])])

ใช้งานได้จริงกับแถว (เช่นใช้ฟังก์ชันกับแต่ละแถว)

ผลลัพธ์คือ

   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

ผลลัพธ์นั้นเหมือนกับการใช้โดย @unutbu

df[[df['B'].isin(['one','three'])]]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.