Вы можете использовать лямбда для предложения if:
и выполнить условие или.
validates :description, presence: true, if: -> {current_step == steps.first || require_validation}
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
Условия цепочек создают длинные строки, которые не рекомендуется 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) Каждое из отдельных условий выполняется на всех исходных данных. Тем не менее, я ожидаю, что это будет достаточно эффективно для многих приложений, и это очень читаемо.
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
data[conjunction(*conditions_list)]
работает после упаковки данных в список, а распаковывает список на месте
– user5359531
16 February 2017 в 04: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.
Это немного быстрее (время ввода, а не производительность), чем цепочка операторов. Конечно, вы могли бы поставить импорт в верхнюю часть файла.
Так как pandas 0.22 update доступны варианты сравнения:
и многое другое. Эти функции возвращают логический массив. Посмотрим, как мы можем их использовать:
# 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
df[(ge(df['col1'], 1) & le(df['col1'], 1)]
. Для меня проблема в том, что словарь с фильтрами может содержать много операторов, а объединение их вместе громоздко. Может быть, я могу добавить каждый промежуточный булевский массив в большой массив, а затем просто использоватьmap
, чтобы применить к ним операторand
? – durden2.0 29 November 2012 в 05:56f()
нужно взять*b
вместо простоb
? Этот пользовательf()
все еще может использовать дополнительный параметрout
дляlogical_and()
? Это приводит к еще одному маленькому побочному вопросу. Каково преимущество производительности / компромиссов с передачей в массиве черезout()
по сравнению с использованием функции, возвращенной изlogical_and()
? Еще раз спасибо! – durden2.0 29 November 2012 в 16:30*b
необходимо, потому что вы передаете два массиваb1
иb2
, и вам нужно их распаковать при вызовеlogical_and
. Однако другой вопрос все еще стоит. Есть ли преимущество в производительности для передачи в массиве с помощью параметраout
доlogical_and()
или просто с использованием его «возвращаемого значения»? – durden2.0 29 November 2012 в 16:55%timeit
)? – Andy Hayden 29 November 2012 в 17:57