【问题标题】:How to automatically group conditions together in python?如何在python中自动将条件组合在一起?
【发布时间】:2018-11-28 12:50:12
【问题描述】:

我正在尝试在 python 中自动将条件组合在一起。困难在于,如果有多个条件,比如 100 个条件,手动“与”所有这些条件会很乏味。如何使用循环来实现这一点?

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

【问题讨论】:

    标签: python pandas numpy logical-operators


    【解决方案1】:

    需要注意的几点:

    • 您可以使用列表或字典来存储可变数量的变量。
    • 您的布尔系列函数用作 NumPy 数组;因此,您可以组合一系列系列并使用np.ndarray.all(或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)
    

    性能基准测试

    性能将非常依赖于数据,您还应该按照@Kopytok's solution 尝试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
    

    【讨论】:

    • 为什么不简单地将条件存储在列表中而不是字典中?
    • 第二种情况你不能用np.logical_and.reduce(conditions)吗?我认为它会比 concat 更快?
    • @ALollz,对于大量数组,我看到np.array(conditions).all(0) 更快。但我不确定细微差别是否重要。
    【解决方案2】:

    您可以通过创建条件列表并使用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)
    

    【讨论】:

    • 好的,看起来这是非常数据依赖。我匹配你的,你可能会匹配我的。猜猜 OP 应该两者都试试。
    • 是的,我的结果和你的一样
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-14
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 2021-07-11
    • 2021-12-03
    相关资源
    最近更新 更多