Использование циклирования через кадры данных и объекты [дубликат]

Вы можете использовать лямбда для предложения if: и выполнить условие или.

validates :description, presence: true, if: -> {current_step == steps.first || require_validation}
68
задан durden2.0 28 November 2012 в 19:34
поделиться

5 ответов

Pandas (и numpy) позволяют булевое индексирование , что будет намного более эффективным:

In [11]: df.loc[df['col1'] >= 1, 'col1']
Out[11]: 
1    1
2    2
Name: col1

In [12]: df[df['col1'] >= 1]
Out[12]: 
   col1  col2
1     1    11
2     2    12

In [13]: df[(df['col1'] >= 1) & (df['col1'] <=1 )]
Out[13]: 
   col1  col2
1     1    11

Если вы хотите написать вспомогательные функции для этого, рассмотрите что-то эти строки:

In [14]: def b(x, col, op, n): 
             return op(x[col],n)

In [15]: def f(x, *b):
             return x[(np.logical_and(*b))]

In [16]: b1 = b(df, 'col1', ge, 1)

In [17]: b2 = b(df, 'col1', le, 1)

In [18]: f(df, b1, b2)
Out[18]: 
   col1  col2
1     1    11

Обновление: pandas 0.13 имеет метод запроса для этих видов использования, предполагая, что имена столбцов являются действительными идентификаторами, следующие работы (и могут быть более эффективными для больших кадров, поскольку он использует numexpr за кулисами):

In [21]: df.query('col1 <= 1 & 1 <= col1')
Out[21]:
   col1  col2
1     1    11
127
ответ дан Andy Hayden 21 August 2018 в 11:21
поделиться
  • 1
    Ваше право, boolean более эффективно, поскольку оно не делает копию данных. Однако мой сценарий немного сложнее, чем ваш пример. Вход, который я получаю, представляет собой словарь, определяющий, какие фильтры применять. Мой пример мог бы сделать что-то вроде df[(ge(df['col1'], 1) & le(df['col1'], 1)]. Для меня проблема в том, что словарь с фильтрами может содержать много операторов, а объединение их вместе громоздко. Может быть, я могу добавить каждый промежуточный булевский массив в большой массив, а затем просто использовать map, чтобы применить к ним оператор and? – durden2.0 29 November 2012 в 05:56
  • 2
    @ durden2.0 Я добавил идею для вспомогательной функции, которая, я думаю, похожа на то, что вы ищете :) – Andy Hayden 29 November 2012 в 11:45
  • 3
    Это выглядит очень близко к тому, что я придумал! Спасибо за пример. Почему f() нужно взять *b вместо просто b? Этот пользователь f() все еще может использовать дополнительный параметр out для logical_and()? Это приводит к еще одному маленькому побочному вопросу. Каково преимущество производительности / компромиссов с передачей в массиве через out() по сравнению с использованием функции, возвращенной из logical_and()? Еще раз спасибо! – durden2.0 29 November 2012 в 16:30
  • 4
    Ничего, я не выглядел достаточно близко. *b необходимо, потому что вы передаете два массива b1 и b2, и вам нужно их распаковать при вызове logical_and. Однако другой вопрос все еще стоит. Есть ли преимущество в производительности для передачи в массиве с помощью параметра out до logical_and() или просто с использованием его «возвращаемого значения»? – durden2.0 29 November 2012 в 16:55
  • 5
    @ durden2.0 Пробовали ли вы тестирование (например, с помощью %timeit)? – Andy Hayden 29 November 2012 в 17:57

Условия цепочек создают длинные строки, которые не рекомендуется pep8. Использование метода .query вынуждает использовать строки, которые являются мощными, но непитоническими и не очень динамичными.

Как только каждый из фильтров находится на месте, один из подходов -

import numpy as np
import functools
def conjunction(*conditions):
    return functools.reduce(np.logical_and, conditions)

c_1 = data.col1 == True
c_2 = data.col2 < 64
c_3 = data.col3 != 4

data_filtered = data[conjunction(c1,c2,c3)]

np.logical работает и работает быстро, но не принимает более двух аргументов, которые обрабатываются по functools.reduce.

Обратите внимание, что это все еще имеет некоторые избыточности: a) краткое сокращение не происходит на глобальном уровне b) Каждое из отдельных условий выполняется на всех исходных данных. Тем не менее, я ожидаю, что это будет достаточно эффективно для многих приложений, и это очень читаемо.

12
ответ дан Gecko 21 August 2018 в 11:21
поделиться
  • 1
    Есть ли способ реализовать это для переменного количества условий? Я попытался добавить в список c_1, c_2, c_3, ... c_n, а затем передать data[conjunction(conditions_list)], но получить ошибку ValueError: Item wrong length 5 instead of 37.. Также попытался data[conjunction(*conditions_list)], но я получаю другое результат data[conjunction(c_1, c_2, c_3, ... c_n )], не уверен, что происходит. – user5359531 16 February 2017 в 04:04
  • 2
    Найден решение ошибки в другом месте. data[conjunction(*conditions_list)] работает после упаковки данных в список, а распаковывает список на месте – user5359531 16 February 2017 в 04:21
  • 3
    Я просто оставил комментарий по вышеуказанному ответу с гораздо более слабой версией, а затем заметил ваш ответ. Очень чисто, мне это очень нравится! – dwanderson 27 February 2017 в 23:09
4
ответ дан Gil Baggio 21 August 2018 в 11:21
поделиться

Почему бы не сделать это?

def filt_spec(df, col, val, op):
    import operator
    ops = {'eq': operator.eq, 'neq': operator.ne, 'gt': operator.gt, 'ge': operator.ge, 'lt': operator.lt, 'le': operator.le}
    return df[ops[op](df[col], val)]
pandas.DataFrame.filt_spec = filt_spec

Демонстрация:

df = pd.DataFrame({'a': [1,2,3,4,5], 'b':[5,4,3,2,1]})
df.filt_spec('a', 2, 'ge')

Результат:

   a  b
 1  2  4
 2  3  3
 3  4  2
 4  5  1

Вы можете видеть, что столбец 'a' был отфильтрован, где a> = 2.

Это немного быстрее (время ввода, а не производительность), чем цепочка операторов. Конечно, вы могли бы поставить импорт в верхнюю часть файла.

0
ответ дан Obol 21 August 2018 в 11:21
поделиться

Так как pandas 0.22 update доступны варианты сравнения:

  • gt (больше)
  • lt (меньше)
  • eq (равно)
  • ne (не равно)
  • ge (больше или равно)

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

# sample data
df = pd.DataFrame({'col1': [0, 1, 2,3,4,5], 'col2': [10, 11, 12,13,14,15]})

# get values from col1 greater than or equals to 1
df.loc[df['col1'].ge(1),'col1']

1    1
2    2
3    3
4    4
5    5

# where co11 values is better 0 and 2
df.loc[df['col1'].between(0,2)]

 col1 col2
0   0   10
1   1   11
2   2   12

# where col1 > 1
df.loc[df['col1'].gt(1)]

 col1 col2
2   2   12
3   3   13
4   4   14
5   5   15
2
ответ дан YOLO 21 August 2018 в 11:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: