Эффективный способ фильтрации нескольких столбцов по нескольким условиям

#python #pandas #dataframe #filter

Вопрос:

У меня есть фрейм данных, который выглядит примерно так:

 pd.DataFrame({
    'A Code': ['123', '234', '345', '234'],
    'B Code': ['345', '123', '234', '123'],
    'X Code': ['987', '765', '765', '876'],
    'Y Code': ['765', '876', '987', '765'], 
    'H Code': ['AB', 'CD', 'EF', 'AB']
})

    A Code  B Code  X Code  Y Code  H Code
0     123     345     987     765     AB
1     234     123     765     876     CD
2     345     234     765     987     EF
3     234     123     876     765     GH

 

И я хочу найти строки , где A Code или B Code есть 123 и X Code или Y Code есть 765 , или где H Code есть EF или GH .

Я использовал следующее условие:

 (
    ((df[df['A Code'] == '123']) | (df[df['B Code'] == '123'])) 
    amp;
    ((df[df['X Code'] == '765']) | (df[df['Y Code'] == '765']))
)
|
(df[df['H Code'] == 'EF'])
 

что работает, но становится очень долгим и грязным.

Есть ли более эффективный способ сделать это?

Ответ №1:

Попробуйте использовать any

 mask = (
        (df[['A Code', 'B Code']] == '123').any(1)
        amp; (df[['X Code', 'Y Code']] == '765').any(1)
       ) | (df['H Code'].isin(['EF', 'GH']))

print(df[mask])
 

Ответ №2:

Вы можете использовать .query()

 df.query("((`A Code` == '123' or `B Code` == '123') and (`X Code` == '765' or `Y Code` == '765')) or `H Code` in ['EF', 'GH']")
 

Если значения являются параметрами, вы можете ссылаться на них с помощью @ синтаксиса:

 a = '123'
df.query("`A Code` == @a")
 

Ответ №3:

Вот другой способ, используя Серию для простых совпадений (и отдельную isin для последнего столбца). Это может оказаться проще написать, когда количество условий увеличивается:

 # define single conditions
s = pd.Series(['123','123','765','765'],
              index=df.columns[:-1])

df[(df[['A Code', 'B Code']].eq(s).any(1)
   amp;df[['X Code', 'Y Code']].eq(s).any(1)
   )|df['H Code'].isin(['EF', 'GH'])
  ]
 

Ответ №4:

Вы можете попробовать любой из приведенных ниже методов, как вам больше нравится.

 import pandas as pd
import time

data = pd.DataFrame({
'A Code': ['123', '234', '345', '234'],
'B Code': ['345', '123', '234', '123'],
'X Code': ['987', '765', '765', '876'],
'Y Code': ['765', '876', '987', '765'], 
'H Code': ['AB', 'CD', 'EF', 'AB']})
 

Вы можете проверить следующие три метода-

Способ1-

 a_code_filter = ['123']
b_code_filter = ['123']
x_code_filter = ['765']
y_code_filter = ['765']
h_code_filter = ['EF']

idx_ab = (data['A Code'].isin(a_code_filter)) | (data['B Code'].isin(b_code_filter))
idx_xy = (data['X Code'].isin(x_code_filter)) | (data['Y Code'].isin(y_code_filter))
idx_h = (data['H Code'].isin(h_code_filter))

idx = (idx_ab) amp; (idx_xy) | (idx_h)
    
method1_data = data[idx]
 

Способ2-

  method2_data = data[
    ((data['A Code']=='123') | (data['B Code']=='123')) amp; ((data['X Code']=='765') | (data['Y Code']=='765')) 
   | (data['H Code']=='EF')
 ]
    
 

Способ3-

  method3_data = data.query("(`A Code`=='123' or `B Code`=='123') amp; (`X Code`=='765' or `Y Code`=='765') | (`H Code`=='EF')")
 

Комментарии:

1. Сравнение методов 1 и 2 неверно. В методе 1 вы измеряете только индексирование, в методе 2 создание маски индексирование. Также query() производительность зависит от размера кадра данных. Это должен быть самый быстрый метод для фрейма данных с более чем 5k-10k строками.

2. Спасибо @AlexanderVolkovsky за разъяснение. Сегодня узнал кое-что новое 🙂 . Соответствующим образом изменил пост.