如何对pandas布尔索引列表执行按位与/或运算筛选DataFrame行
问题背景
- 业务场景:持有包含多列标志位(flag)的pandas DataFrame,部分配置场景下某些flag列会因对应硬件单元未部署而不存在
- 核心需求:获取所有符合条件的现存行的有效索引,将有效布尔判断条件存入列表后,无需硬编码列名,即可批量完成按位与(所有条件同时满足)、按位或(任意条件满足)运算,适配列动态缺失的场景
- 原示例代码存在笔误:收集flag2、flag3、flag4对应的掩码时,错误重复append了item1,需要先修正为append对应列生成的掩码
实现方案
首先修正有效掩码列表的收集逻辑:
import pandas as pd df = pd.DataFrame.from_dict({'datetime': {0: '07/06/2022 12:09', 1: '07/06/2022 12:09', 2: '07/06/2022 12:09', 3: '07/06/2022 12:09', 4: '07/06/2022 12:09', 5: '07/06/2022 12:09', 6: '07/06/2022 12:09', 7: '07/06/2022 12:09', 8: '07/06/2022 12:09', 9: '07/06/2022 12:09', 10: '07/06/2022 12:09', 11: '07/06/2022 12:09', 12: '07/06/2022 12:09', 13: '07/06/2022 12:09'}, 'flag1': {0: False, 1: False, 2: False, 3: True, 4: True, 5: True, 6: True, 7: True, 8: True, 9: True, 10: False, 11: False, 12: False, 13: False}, 'flag2': {0: False, 1: False, 2: True, 3: True, 4: True, 5: True, 6: True, 7: True, 8: False, 9: False, 10: False, 11: False, 12: False, 13: False}, 'flag3': {0: False, 1: False, 2: False, 3: True, 4: True, 5: True, 6: True, 7: False, 8: False, 9: False, 10: False, 11: False, 12: False, 13: False}, 'flag4': {0: False, 1: False, 2: False, 3: True, 4: True, 5: True, 6: True, 7: True, 8: True, 9: True, 10: False, 11: False, 12: False, 13: False}, 'value1': {0: 179.012, 1: 179.012, 2: 179.012, 3: 179.012, 4: 179.012, 5: 179.012, 6: 179.012, 7: 179.012, 8: 179.012, 9: 179.012, 10: 179.012, 11: 179.012, 12: 179.012, 13: 179.012}, 'value2': {0: -101.39, 1: -101.39, 2: -101.41, 3: -101.39, 4: -101.43, 5: -101.43, 6: -101.43, 7: -101.46, 8: -101.4, 9: -101.39, 10: -101.39, 11: -101.43, 12: -101.43, 13: -101.38}, 'state': {0: 'IDLE', 1: 'ON', 2: 'ON', 3: 'ON', 4: 'ACTIVE', 5: 'ACTIVE', 6: 'ACTIVE', 7: 'ACTIVE', 8: 'ACTIVE', 9: 'ACTIVE', 10: 'ACTIVE', 11: 'ACTIVE', 12: 'IDLE', 13: 'IDLE'}}) validrx = [] if 'flag1' in df.columns: item1 = (df['flag1'] == True) if item1.any(): validrx.append(item1) if 'flag2' in df.columns: item2 = (df['flag2'] == True) if item2.any(): validrx.append(item2) # 修正原笔误 if 'flag3' in df.columns: item3 = (df['flag3'] == True) if item3.any(): validrx.append(item3) # 修正原笔误 if 'flag4' in df.columns: item4 = (df['flag4'] == True) if item4.any(): validrx.append(item4) # 修正原笔误
方案1:基于pandas内置聚合方法(可读性高,推荐)
核心思路是将列表内所有布尔Series按列拼接后,逐行做逻辑聚合,自动适配列表长度,不需要硬编码列名。
- 所有条件同时为True(AND逻辑,等价于硬编码的
item1 & item2 & item3 & item4)
# 先处理无有效掩码的边界情况,按需选择返回空df或全量df if not validrx: whenAllAreTrueAtTheSameTime = df.iloc[0:0] # 返回保留列结构的空df else: and_mask = pd.concat(validrx, axis=1).all(axis=1) whenAllAreTrueAtTheSameTime = df[and_mask]
- 任意条件为True(OR逻辑,等价于硬编码的
item1 | item2 | item3 | item4)
if not validrx: whenAnyareTrueAtTheSameTime = df.iloc[0:0] # 无有效掩码时返回空df,可按需调整 else: or_mask = pd.concat(validrx, axis=1).any(axis=1) whenAnyareTrueAtTheSameTime = df[or_mask]
方案2:基于reduce批量运算(性能更高,适合超大数据集)
借助functools.reduce对列表内的掩码逐次做按位运算,不需要做DataFrame拼接,性能更好。
- AND逻辑实现
from functools import reduce if not validrx: whenAllAreTrueAtTheSameTime = df.iloc[0:0] else: and_mask = reduce(lambda a, b: a & b, validrx) whenAllAreTrueAtTheSameTime = df[and_mask]
- OR逻辑实现
if not validrx: whenAnyareTrueAtTheSameTime = df.iloc[0:0] else: or_mask = reduce(lambda a, b: a | b, validrx) whenAnyareTrueAtTheSameTime = df[or_mask]
注意:两种方案都要求validrx内的布尔Series和原df索引完全对齐,从df直接取列生成掩码的写法天然满足这个要求,不需要额外处理索引对齐问题。
内容的提问来源于stack exchange,提问作者AAmes
相关产品推荐
相关产品推荐

