pandas: строки фильтра DataFrame с цепочкой операторов

Большинство операций в pandas можно выполнить с помощью цепочки операторов ( groupby , aggregate , apply и т. Д.), Но единственный способ, которым я нашел, чтобы фильтровать строки, – это обычная индексация скобок

 df_filtered = df[df['column'] == value] 

Это непривлекательно, поскольку для этого требуется присвоить переменную df переменной, чтобы она могла фильтровать ее значения. Есть ли что-то более похожее на следующее?

 df_filtered = df.mask(lambda x: x['column'] == value) 

Я не совсем уверен, чего вы хотите, и ваша последняя строка кода тоже не помогает, но в любом случае:

Фильтрация «цепочка» осуществляется путем «привязки» критериев в логическом индексе.

 In [96]: df Out[96]: ABCD a 1 4 9 1 b 4 5 0 2 c 5 5 1 0 d 1 3 9 6 In [99]: df[(df.A == 1) & (df.D == 6)] Out[99]: ABCD d 1 3 9 6 

Если вы хотите связать методы, вы можете добавить свой собственный метод маски и использовать его.

 In [90]: def mask(df, key, value): ....: return df[df[key] == value] ....: In [92]: pandas.DataFrame.mask = mask In [93]: df = pandas.DataFrame(np.random.randint(0, 10, (4,4)), index=list('abcd'), columns=list('ABCD')) In [95]: df.ix['d','A'] = df.ix['a', 'A'] In [96]: df Out[96]: ABCD a 1 4 9 1 b 4 5 0 2 c 5 5 1 0 d 1 3 9 6 In [97]: df.mask('A', 1) Out[97]: ABCD a 1 4 9 1 d 1 3 9 6 In [98]: df.mask('A', 1).mask('D', 6) Out[98]: ABCD d 1 3 9 6 

Фильтры могут быть скованы с помощью запроса Pandas:

 df = pd.DataFrame( np.random.randn(30,3), columns = ['a','b','c']) df_filtered = df.query('a>0').query('0 

Фильтры также могут быть объединены в один запрос:

 df_filtered = df.query('a>0 and 0 

Ответ от @lodagro велик. Я бы расширил его, обобщая функцию маски как:

 def mask(df, f): return df[f(df)] 

Затем вы можете делать такие вещи, как:

 df.mask(lambda x: x[0] < 0).mask(lambda x: x[1] > 0) 

Я предлагаю это для дополнительных примеров. Это тот же ответ, что и https://stackoverflow.com/a/28159296/

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

pandas.DataFrame.query
query был сделан именно для этой цели. Рассмотрим блок данных df

 import pandas as pd import numpy as np np.random.seed([3,1415]) df = pd.DataFrame( np.random.randint(10, size=(10, 5)), columns=list('ABCDE') ) df ABCDE 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 

Давайте используем query для фильтрации всех строк, где D > B

 df.query('D > B') ABCDE 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 7 6 2 6 6 5 

Что мы цеп

 df.query('D > B').query('C > B') # equivalent to # df.query('D > B and C > B') # but defeats the purpose of demonstrating chaining ABCDE 0 0 2 7 3 8 1 7 0 6 8 6 4 3 6 7 7 4 5 5 3 7 5 9 7 6 2 6 6 5 

Начиная с версии 0.18.1 метод .loc принимает вызываемый для выбора. Вместе с lambda-функциями вы можете создавать очень гибкие сетчатые фильтры:

 import numpy as np import pandas as pd df = pd.DataFrame(np.random.randint(0,100,size=(100, 4)), columns=list('ABCD')) df.loc[lambda df: df.A == 80] # equivalent to df[df.A == 80] but chainable df.sort_values('A').loc[lambda df: df.A > 80].loc[lambda df: df.B > df.A] 

Если все, что вы делаете, это фильтрация, вы также можете опустить .loc .

У меня был тот же вопрос, за исключением того, что я хотел совместить критерии с условием ИЛИ. Формат, заданный Wouter Overmeire, объединяет критерии в условие AND, так что оба должны быть удовлетворены:

 In [96]: df Out[96]: ABCD a 1 4 9 1 b 4 5 0 2 c 5 5 1 0 d 1 3 9 6 In [99]: df[(df.A == 1) & (df.D == 6)] Out[99]: ABCD d 1 3 9 6 

Но я обнаружил, что если вы завершаете каждое условие в (... == True) и присоединяете критерии к трубе, критерии объединяются в условии ИЛИ, удовлетворяются всякий раз, когда любое из них истинно:

 df[((df.A==1) == True) | ((df.D==6) == True)] 

Мой ответ подобен другим. Если вы не хотите создавать новую функцию, вы можете использовать то, что уже определили для вас панды. Используйте метод трубы.

 df.pipe(lambda d: d[d['column'] == value]) 

Если вы хотите применить все обычные логические маски, а также маску общего назначения, вы можете вставить следующее в файл, а затем просто назначить их следующим образом:

 pd.DataFrame = apply_masks() 

Применение:

 A = pd.DataFrame(np.random.randn(4, 4), columns=["A", "B", "C", "D"]) A.le_mask("A", 0.7).ge_mask("B", 0.2)... (May be repeated as necessary 

Это немного взломанно, но это может сделать вещи немного более чистыми, если вы постоянно рубите и меняете наборы данных в соответствии с фильтрами. Существует также фильтр общего назначения, адаптированный из Daniel Velkov выше в функции gen_mask, которую вы можете использовать с lambda-функциями или, при желании, иначе.

Файл для сохранения (я использую masks.py):

 import pandas as pd def eq_mask(df, key, value): return df[df[key] == value] def ge_mask(df, key, value): return df[df[key] >= value] def gt_mask(df, key, value): return df[df[key] > value] def le_mask(df, key, value): return df[df[key] <= value] def lt_mask(df, key, value): return df[df[key] < value] def ne_mask(df, key, value): return df[df[key] != value] def gen_mask(df, f): return df[f(df)] def apply_masks(): pd.DataFrame.eq_mask = eq_mask pd.DataFrame.ge_mask = ge_mask pd.DataFrame.gt_mask = gt_mask pd.DataFrame.le_mask = le_mask pd.DataFrame.lt_mask = lt_mask pd.DataFrame.ne_mask = ne_mask pd.DataFrame.gen_mask = gen_mask return pd.DataFrame if __name__ == '__main__': pass 

Просто хочу добавить демонстрацию, используя loc для фильтрации не только по строкам, но также по столбцам и некоторым достоинствам в цепочке.

Код ниже может фильтровать строки по значению.

 df_filtered = df.loc[df['column'] == value] 

Изменяя его немного, вы также можете фильтровать столбцы.

 df_filtered = df.loc[df['column'] == value, ['year', 'column']] 

Итак, почему мы хотим цепной метод? Ответ заключается в том, что его легко читать, если у вас много операций. Например,

 res = df\ .loc[df['station']=='USA', ['TEMP', 'RF']]\ .groupby('year')\ .agg(np.nanmean) 

Это решение более хакерское с точки зрения реализации, но я считаю его более чистым с точки зрения использования, и это, безусловно, более общее, чем предлагаемые другие.

https://github.com/toobaz/generic_utils/blob/master/generic_utils/pandas/where.py

Вам не нужно загружать все репо: сохранение файла и выполнение

 from where import where as W 

должно быть достаточно. Затем вы используете его следующим образом:

 df = pd.DataFrame([[1, 2, True], [3, 4, False], [5, 7, True]], index=range(3), columns=['a', 'b', 'c']) # On specific column: print(df.loc[W['a'] > 2]) print(df.loc[-W['a'] == W['b']]) print(df.loc[~W['c']]) # On entire - or subset of a - DataFrame: print(df.loc[W.sum(axis=1) > 3]) print(df.loc[W[['a', 'b']].diff(axis=1)['b'] > 1]) 

Немного менее глупый пример использования:

 data = pd.read_csv('ugly_db.csv').loc[~(W == '$null$').any(axis=1)] 

Кстати: даже в том случае, когда вы просто используете логические столбцы,

 df.loc[W['cond1']].loc[W['cond2']] 

может быть намного более эффективным, чем

 df.loc[W['cond1'] & W['cond2']] 

потому что он вычисляет cond2 только там, где cond1 является True .

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ: Я впервые дал этот ответ в другом месте, потому что я этого не видел.

pandas предоставляет два варианта ответа Wouter Overmeire, которые не требуют каких-либо переопределений. Один из них – .loc[.] С вызываемым, как в

 df_filtered = df.loc[lambda x: x['column'] == value] 

другой – .pipe() , как в

 df_filtered = df.pipe(lambda x: x['column'] == value) 

Если вы DataFrame.xs() свои столбцы для поиска в качестве индексов, вы можете использовать DataFrame.xs() чтобы взять поперечное сечение. Это не так много, как ответы на query , но может быть полезно в некоторых ситуациях.

 import pandas as pd import numpy as np np.random.seed([3,1415]) df = pd.DataFrame( np.random.randint(3, size=(10, 5)), columns=list('ABCDE') ) df # Out[55]: # ABCDE # 0 0 2 2 2 2 # 1 1 1 2 0 2 # 2 0 2 0 0 2 # 3 0 2 2 0 1 # 4 0 1 1 2 0 # 5 0 0 0 1 2 # 6 1 0 1 1 1 # 7 0 0 2 0 2 # 8 2 2 2 2 2 # 9 1 2 0 2 1 df.set_index(['A', 'D']).xs([0, 2]).reset_index() # Out[57]: # ADBCE # 0 0 2 2 2 2 # 1 0 2 1 1 0 

Вы также можете использовать библиотеку numpy для логических операций. Это довольно быстро.

 df[np.logical_and(df['A'] == 1 ,df['B'] == 6)] 

Это непривлекательно, поскольку для этого требуется присвоить переменную df переменной, чтобы она могла фильтровать ее значения.

 df[df["column_name"] != 5].groupby("other_column_name") 

похоже, работает: вы также можете связать оператор [] . Возможно, они добавили его с тех пор, как вы задали вопрос.

  • Определить метод вне определения classа?
  • Python - создать список с номерами между двумя значениями?
  • Как установить текущий рабочий каталог?
  • Как найти дубликаты в списке и создать с ними другой список?
  • Выбор строки серии pandas / dataframe по целочисленному индексу
  • Получение PATH для python после установки MacPorts
  • Конкатенация строк без оператора «+»
  • Где я могу разместить плагины для Gimp 2.8 на Windows?
  • Невозможно загрузить файлы с использованием рассола и нескольких модhive
  • Как преобразовать этот список словарей в файл csv?
  • Как установить тайм-аут на метод recv сокета python?
  • Interesting Posts

    SSH Обратный тоннель

    Как документ Word может быть создан на C #?

    Восстановление EFS из резервных файлов реестра?

    Как распечатать PDF на сетевом принтере по умолчанию с помощью команды оболочки GhostScript (gswin32c.exe)

    Команда OS X Terminal для изменения цветовых тем

    Восстановление разрешений реестра Windows по умолчанию для раздела служб

    Зачем мне нужно использовать тип ** для указания типа *?

    Камера в Android, как получить лучший размер, размер предварительного просмотра, размер изображения, размер изображения, искаженное изображение

    Как настроить высоту страницы на высоту содержимого?

    Остановка и воспроизведение Android MediaPlayer

    Как отобразить оверлей индикатора прогресса / HUD на iPhone?

    Невозможно разобрать hibernate.cfg.xml в автономном режиме

    Как узнать, поддерживает ли мой BIOS UEFI?

    Как переименовывать файлы с недопустимым кодированием или навалом-заменить неверные кодированные символы?

    mutate_each / summaryise_each в dplyr: как я могу выбрать определенные столбцы и дать новые имена мутированным столбцам?

    Давайте будем гением компьютера.