如何在 python 中自动将条件组合在一起?

How to automatically group conditions together in python?

我正在尝试在 python 中自动将条件组合在一起。难点在于,如果有多个条件,比如100个条件,手工"AND"会很乏味。我如何使用循环来实现这一目标?

import pandas as pd
s1 = pd.Series([1,2,3,4,5,6])
s2 = pd.Series([5,6,7,8,9,10])
s3 = pd.Series([11,12,5,7,8,2])
df = pd.DataFrame({'A': s1,'B': s2,'C': s3})

condition1 = df['A'] > 3
condition2 = df['B'] > 6
condition3 = df['C'] > 5
# AND Operation ->>> Can be achieved with a loop?
select = condition1 & condition2 & condition3

您可以通过创建条件列表并使用 reduce:

来实现它
from functools import reduce

conditions = [
    df['A'] > 3,
    df['B'] > 6,
    df['C'] > 5,
]

total_condition = reduce(lambda x, y: x & y, conditions)

测试用例:

d = pd.DataFrame(np.random.randint(1, 5, (700000, 3)), columns=["a", "b", "c"])

conditions = [
    d["a"] > 2,
    d["c"] > 1,
    d["b"] > 2,
]*100

使用reduce

from functools import reduce

%timeit reduce(lambda x, y: x & y, conditions)
> 547 ms ± 14.6 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

使用 np.concat + df.all():

%timeit pd.concat(conditions, axis=1).all(1)
> 4.19 s ± 367 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

注意几点:

  • 您可以使用列表或字典来存储可变数量的变量。
  • 您的布尔级数作为 NumPy 数组;因此,您可以组合一系列系列并使用 np.ndarray.all (or pd.DataFrame.all) 来计算它们的交集。

您可以将布尔系列列表与 NumPy 或 Pandas:

conditions = [df['A'] > 3,
              df['B'] > 6,
              df['C'] > 5]

# all equivalent
select = pd.concat(conditions, axis=1).all(axis=1)
select = np.logical_and.reduce(conditions)
select = np.array(conditions).all(axis=0)

print(select)

array([False, False, False,  True,  True, False], dtype=bool)

同样地,如果你想命名你的布尔过滤器,你可以使用字典:

conditions = {1: df['A'] > 3,
              2: df['B'] > 6,
              3: df['C'] > 5}

select = np.array(list(conditions.values())).all(axis=0)

性能基准测试

性能将非常依赖于数据,您还应该按照 尝试 reduce 并使用您的数据检查性能。

df = pd.concat([df]*1000)

conditions = [df['A'] > 3,
              df['B'] > 6,
              df['C'] > 5]

conditions = conditions*100

%timeit reduce(lambda x, y: x & y, conditions)     # 104 ms per loop
%timeit np.logical_and.reduce(conditions)          # 104 ms per loop
%timeit np.array(conditions).all(axis=0)           # 99.4 ms per loop
%timeit pd.concat(conditions, axis=1).all(axis=1)  # 34.6 ms per loop