Как я могу объединить n-количество логических индексов для фильтрации Pandas DataFrame?

Логические индексы Pandas обычно сочетаются с логические операторы:

vdf = (df1['status'] == 'DENIED') | (df1['status'] == 'VOIDED') | (df1['void?'] == True)

Я обрабатываю различные таблицы DF. В таблице может быть ноль или много столбцов, которые я хочу отфильтровать. Когда я говорю «фильтровать», я имею в виду удаление строк, где условие истинно. Если транзакция аннулирована, я хочу отказаться от нее. Если транзакция соответствует определенной категории, я хочу ее удалить.

Как я могу комбинировать n-логические индексы?

table = [('2019-01-01', 10.00, False, 'CAPTURED'),
         ('2019-01-04', 10.00, False, 'CAPTURED'),
         ('2019-01-05', 10.00, False, 'DENIED'),
         ('2019-01-06', 10.00, True, 'VOIDED'),
cols = ['date', 'amount', 'void?', 'status']
df1 = pd.DataFrame.from_records(table, columns=cols)

filter_headers = ['void?', 'status']
status_vals = ['VOIDED', 'DENIED']

try:
    if filter_headers:
        vdfs = []
        for fcol in filter_headers:
            if df1[fcol].dtype == 'bool':
                vdfs.append(df1[fcol] == True)
            elif df1[fcol].dtype == 'object':
                vdfs.append(df1[fcol].isin(status_vals))
            else:
                print("Unhandled type.")
        # Obviously wrong...
        df2 = df1[~sum(vdfs)]
    else:
        df2 = df1
except Exception as e:
    print("(%s) Filter Headers produced no results." % e)
    pass

1
0
43
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если я правильно понял, чего вы хотите добиться, DataFrame.loc — это то, что вы ищете. Он выбирает строки с индексом True:

bindex = [not v and s not in status_vals for v, s in zip(df1['void?'], df1['status'])]
df2 = df1.loc[bindex]

bindex — это список логических значений, длина которых равна количеству строк в вашем фрейме данных. Является False, если df1['void?'] есть True и df1['status'] не находится внутри status_val. Эти две строки заменяют весь ваш блок tryexcept.
Используя законы де Моргана, bindex также можно переписать как:

bindex = [not (v or s in status_vals) for v, s in zip(df1['void?'], df1['status'])]

Используя образец данных, который вы опубликовали, результат df2:

         date  amount  void?    status
0  2019-01-01    10.0  False  CAPTURED
1  2019-01-04    10.0  False  CAPTURED
Ответ принят как подходящий

Вместо sum вы можете использовать np.any с осью = 0, например:

import numpy as np
# mostly all your code except this line df2 = df1[~sum(vdfs)] that you replace by
df2 = df1[~np.any(vdfs, axis=0)]

В вашем примере результат для df2 тогда

         date  amount  void?    status
0  2019-01-01    10.0  False  CAPTURED
1  2019-01-04    10.0  False  CAPTURED

Другие вопросы по теме