Cách lọc khung dữ liệu Pandas bằng cách sử dụng 'in' và 'không trong' như trong SQL


432

Làm cách nào tôi có thể đạt được các tương đương của SQL INNOT IN?

Tôi có một danh sách với các giá trị cần thiết. Đây là kịch bản:

df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = ['UK','China']

# pseudo-code:
df[df['countries'] not in countries]

Cách làm hiện tại của tôi là như sau:

df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = pd.DataFrame({'countries':['UK','China'], 'matched':True})

# IN
df.merge(countries,how='inner',on='countries')

# NOT IN
not_in = df.merge(countries,how='left',on='countries')
not_in = not_in[pd.isnull(not_in['matched'])]

Nhưng điều này có vẻ như là một loại bùn khủng khiếp. Bất cứ ai có thể cải thiện nó?


1
Tôi nghĩ rằng giải pháp của bạn là giải pháp tốt nhất. Bạn có thể bao gồm IN, NOT_IN của nhiều cột.
Bruce Jung

Bạn có muốn thử nghiệm trên một cột hoặc nhiều cột không?
smci

1
Liên quan (hiệu suất / nội bộ gấu trúc): Hiệu suất của Pandas pd.Series.isin với thiết lập so với mảng
jpp

Câu trả lời:


817

Bạn có thể sử dụng pd.Series.isin.

Để sử dụng "IN": something.isin(somewhere)

Hoặc cho "KHÔNG VÀO": ~something.isin(somewhere)

Như một ví dụ hoạt động:

>>> df
  countries
0        US
1        UK
2   Germany
3     China
>>> countries
['UK', 'China']
>>> df.countries.isin(countries)
0    False
1     True
2    False
3     True
Name: countries, dtype: bool
>>> df[df.countries.isin(countries)]
  countries
1        UK
3     China
>>> df[~df.countries.isin(countries)]
  countries
0        US
2   Germany

1
Chỉ là một FYI, @LondonRob có một DataFrame của anh ấy và của bạn là một Series. DataFrame isinđã được thêm vào .13.
TomAugspurger

Bất kỳ đề xuất cho làm thế nào để làm điều này với gấu trúc 0.12.0? Đây là phiên bản phát hành hiện tại. (Có lẽ tôi chỉ nên đợi 0.13?!)
LondonRob

Nếu bạn thực sự đang xử lý các mảng 1 chiều (như trong ví dụ của bạn) thì trên dòng đầu tiên của bạn sử dụng Sê-ri thay vì Khung dữ liệu, như @DSM được sử dụng: df = pd.Series({'countries':['US','UK','Germany','China']})
TomAugspurger

2
@TomAugspurger: như thường lệ, có lẽ tôi đang thiếu thứ gì đó. df, cả của tôi và của anh ấy, là một DataFrame. countrieslà một danh sách. df[~df.countries.isin(countries)]tạo ra a DataFrame, không phải a Seriesvà dường như hoạt động trở lại trong 0.11.0.dev-14a04dd.
DSM

6
Câu trả lời này gây nhầm lẫn bởi vì bạn tiếp tục sử dụng lại countriesbiến. Chà, OP làm điều đó, và đó là kế thừa, nhưng điều gì đó được thực hiện tồi tệ trước đây không biện minh cho việc làm nó tồi tệ bây giờ.
ifly6

63

Giải pháp thay thế sử dụng phương thức .query () :

In [5]: df.query("countries in @countries")
Out[5]:
  countries
1        UK
3     China

In [6]: df.query("countries not in @countries")
Out[6]:
  countries
0        US
2   Germany

10
@LondonRob querykhông còn thử nghiệm nữa.
Paul Rougieux

37

Làm cách nào để triển khai 'trong' và 'không trong' cho DataFrame của gấu trúc?

Pandas cung cấp hai phương thức: Series.isinDataFrame.isincho Series và DataFrames, tương ứng.


Lọc DataFrame dựa trên MỘT Cột (cũng áp dụng cho Sê-ri)

Kịch bản phổ biến nhất là áp dụng một isinđiều kiện trên một cột cụ thể để lọc các hàng trong DataFrame.

df = pd.DataFrame({'countries': ['US', 'UK', 'Germany', np.nan, 'China']})
df
  countries
0        US
1        UK
2   Germany
3     China

c1 = ['UK', 'China']             # list
c2 = {'Germany'}                 # set
c3 = pd.Series(['China', 'US'])  # Series
c4 = np.array(['US', 'UK'])      # array

Series.isinchấp nhận các loại khác nhau như đầu vào. Sau đây là tất cả các cách hợp lệ để có được những gì bạn muốn:

df['countries'].isin(c1)

0    False
1     True
2    False
3    False
4     True
Name: countries, dtype: bool

# `in` operation
df[df['countries'].isin(c1)]

  countries
1        UK
4     China

# `not in` operation
df[~df['countries'].isin(c1)]

  countries
0        US
2   Germany
3       NaN

# Filter with `set` (tuples work too)
df[df['countries'].isin(c2)]

  countries
2   Germany

# Filter with another Series
df[df['countries'].isin(c3)]

  countries
0        US
4     China

# Filter with array
df[df['countries'].isin(c4)]

  countries
0        US
1        UK

Lọc trên NHIỀU Cột

Đôi khi, bạn sẽ muốn áp dụng kiểm tra thành viên 'trong' với một số cụm từ tìm kiếm trên nhiều cột,

df2 = pd.DataFrame({
    'A': ['x', 'y', 'z', 'q'], 'B': ['w', 'a', np.nan, 'x'], 'C': np.arange(4)})
df2

   A    B  C
0  x    w  0
1  y    a  1
2  z  NaN  2
3  q    x  3

c1 = ['x', 'w', 'p']

Để áp dụng isinđiều kiện cho cả hai cột "A" và "B", hãy sử dụng DataFrame.isin:

df2[['A', 'B']].isin(c1)

      A      B
0   True   True
1  False  False
2  False  False
3  False   True

Từ đó, để giữ lại các hàng có ít nhất một cộtTrue , chúng ta có thể sử dụng anydọc theo trục đầu tiên:

df2[['A', 'B']].isin(c1).any(axis=1)

0     True
1    False
2    False
3     True
dtype: bool

df2[df2[['A', 'B']].isin(c1).any(axis=1)]

   A  B  C
0  x  w  0
3  q  x  3

Lưu ý rằng nếu bạn muốn tìm kiếm mọi cột, bạn chỉ cần bỏ qua bước chọn cột và thực hiện

df2.isin(c1).any(axis=1)

Tương tự, để giữ lại các hàng trong đó TẤT CẢ các cộtTrue , hãy sử dụng alltheo cách tương tự như trước đây.

df2[df2[['A', 'B']].isin(c1).all(axis=1)]

   A  B  C
0  x  w  0

Các đề cập đáng chú ý: numpy.isin,, querydanh sách hiểu (chuỗi dữ liệu)

Ngoài các phương pháp được mô tả ở trên, bạn cũng có thể sử dụng tương đương numpy: numpy.isin .

# `in` operation
df[np.isin(df['countries'], c1)]

  countries
1        UK
4     China

# `not in` operation
df[np.isin(df['countries'], c1, invert=True)]

  countries
0        US
2   Germany
3       NaN

Tại sao nó đáng để xem xét? Các hàm NumPy thường nhanh hơn một chút so với tương đương gấu trúc của chúng vì chi phí thấp hơn. Vì đây là một hoạt động theo nguyên tố không phụ thuộc vào căn chỉnh chỉ mục, nên có rất ít tình huống trong đó phương pháp này không phải là sự thay thế thích hợp cho gấu trúc 'isin .

Các thường trình gấu trúc thường lặp đi lặp lại khi làm việc với các chuỗi, bởi vì các thao tác chuỗi rất khó để vectorise. Có rất nhiều bằng chứng cho thấy rằng việc hiểu danh sách sẽ nhanh hơn ở đây. . Chúng tôi sử dụng một inkiểm tra ngay bây giờ.

c1_set = set(c1) # Using `in` with `sets` is a constant time operation... 
                 # This doesn't matter for pandas because the implementation differs.
# `in` operation
df[[x in c1_set for x in df['countries']]]

  countries
1        UK
4     China

# `not in` operation
df[[x not in c1_set for x in df['countries']]]

  countries
0        US
2   Germany
3       NaN

Tuy nhiên, việc chỉ định sẽ khó sử dụng hơn rất nhiều, vì vậy, đừng sử dụng nó trừ khi bạn biết bạn đang làm gì.

Cuối cùng, cũng DataFrame.querycâu trả lời trong câu trả lời này . FTexpr FTW!


Tôi thích nó, nhưng nếu tôi muốn so sánh một cột trong df3 đó là cột df1 thì sao? Nó sẽ trông như thế nào?
Arthur D. Howland

12

Tôi thường thực hiện lọc chung trên các hàng như thế này:

criterion = lambda row: row['countries'] not in countries
not_in = df[df.apply(criterion, axis=1)]

10
FYI, tốc độ này chậm hơn nhiều so với @DSM soln được vector hóa
Jeff

@Jeff Tôi mong đợi điều đó, nhưng đó là những gì tôi rơi vào khi tôi cần lọc trực tiếp một thứ không có sẵn trong gấu trúc. (Tôi sắp sửa nói "như .startwith hoặc khớp regex, nhưng chỉ phát hiện ra về Series.str có tất cả điều đó!)
Kos

7

Tôi muốn lọc ra các hàng dfbc có KINH DOANH_ID cũng nằm trong KINH DOANH_ID của dfProfilesBusIds

dfbc = dfbc[~dfbc['BUSINESS_ID'].isin(dfProfilesBusIds['BUSINESS_ID'])]

5
Bạn có thể phủ định isin (như được thực hiện trong câu trả lời được chấp nhận) thay vì so sánh với Sai
OneCricketeer

6

Đối chiếu các giải pháp có thể từ các câu trả lời:

Tại: df[df['A'].isin([3, 6])]

KHÔNG VÀO:

  1. df[-df["A"].isin([3, 6])]

  2. df[~df["A"].isin([3, 6])]

  3. df[df["A"].isin([3, 6]) == False]

  4. df[np.logical_not(df["A"].isin([3, 6]))]


3
Điều này chủ yếu lặp lại thông tin từ các câu trả lời khác. Sử dụng logical_notlà một tương đương vừa miệng của các ~nhà điều hành.
cs95

3
df = pd.DataFrame({'countries':['US','UK','Germany','China']})
countries = ['UK','China']

thực hiện trong :

df[df.countries.isin(countries)]

thực hiện không như ở các nước còn lại:

df[df.countries.isin([x for x in np.unique(df.countries) if x not in countries])]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.