如何用更Pythonic的简洁方式多列筛选pandas DataFrame?
Pandas多列筛选的简洁实现方法
问题
使用pandas DataFrame处理数据时,按多列筛选是常见需求,常规语法能实现简单场景:
import pandas as pd # 创建示例DataFrame df = pd.DataFrame({ 'col1':['one','two','three','four', 'five'], 'col2':[1,2,3,4,5], 'col3':[0.3,0.4,0.5,0.6,0.7], 'col4':[0.4,0.5,0.6,0.7,0.8] }) # 常规多列筛选 print(df[(df['col1'] == 'one') & (df['col2'] == 1)])
但当筛选列数较多时,代码会变得冗长难读,比如:
data_raw[(data_raw['Metales'] == 'MoO3') | (data_raw['Metales_0'] == 'MoO3') | (data_raw['Metales_1'] == 'MoO3')| (data_raw['Metales_2'] == 'MoO3')]
有没有更简洁、Pythonic的实现方式?
解决方案
根据筛选条件的类型,可采用以下几种优化方式:
一、多列满足同一条件的场景
针对多个列需匹配同一值(如示例中多列匹配'MoO3'),可结合isin()与any()/all()批量处理:
1. 任意一列匹配(逻辑或 |)
指定目标列与匹配值,生成布尔矩阵后按行取任意为True的结果:
# 定义目标列和匹配值 target_cols = ['Metales', 'Metales_0', 'Metales_1', 'Metales_2'] target_val = 'MoO3' # 筛选任意一列等于target_val的行 filtered_df = data_raw[data_raw[target_cols].isin([target_val]).any(axis=1)]
2. 所有列都匹配(逻辑与 &)
若需所有指定列满足条件,将any(axis=1)替换为all(axis=1)即可:
filtered_df = data_raw[data_raw[target_cols].isin([target_val]).all(axis=1)]
二、多列满足不同条件的场景
若每列筛选规则不同(如col1=='one'且col2==1且col3>0.3),可选用以下两种方式:
1. 使用query()方法
采用类SQL的语法编写筛选条件,可读性大幅提升,支持直接引用变量:
# 直接编写条件 filtered_df = df.query("col1 == 'one' and col2 == 1 and col3 > 0.3") # 动态生成条件(适合批量场景) conditions = ["col1 == 'one'", "col2 == 1", "col3 > 0.3"] filtered_df = df.query(" and ".join(conditions))
2. 字典映射列与条件
将列名与对应条件函数/值存入字典,批量生成布尔筛选器后合并:
from functools import reduce import operator # 定义列到条件的映射 condition_map = { 'col1': lambda x: x == 'one', 'col2': lambda x: x == 1, 'col3': lambda x: x > 0.3 } # 生成所有布尔序列并按逻辑与合并 filters = [condition_map[col](df[col]) for col in condition_map] filtered_df = df[reduce(operator.and_, filters)]
三、混合场景(部分列同条件+部分列不同条件)
可将上述方法结合使用,比如先筛选任意Metales列匹配MoO3,再叠加col2>2的条件:
target_cols = ['Metales', 'Metales_0', 'Metales_1', 'Metales_2'] filtered_df = data_raw[ (data_raw[target_cols].isin(['MoO3']).any(axis=1)) & (data_raw['col2'] > 2) ]
内容的提问来源于stack exchange,提问作者David Siret Marquès
相关产品推荐
相关产品推荐

