You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Pythonic方式基于条件DataFrame过滤Pandas DataFrame行?

问题描述

现有如下Pandas DataFrame:

id  f1     f2     f3     f4
1   8.327  9.905  8.133  0.785
2   3.549  0.452  7.798  5.797
3   0.011  0.238  1.291  7.593
4   0.325  0.792  4.643  4.3
5   7.093  7.312  3.641  9.88
6   2.88   7.834  5.727  6.984
7   5.554  1.649  4.018  0.623
8   2.501  2.941  9.323  0.565
9   1.032  6.961  3.905  8.116
10  9.68   7.922  7.015  7.542
11  8.096  4.344  1.153  5.244

需要通过另一个条件DataFrame过滤数据,找出满足所有条件的记录:

variable    interval
1   f1          (0,4)
2   f2          [1,3]
3   f3          (5,+np.inf)
4   f4          [0,10]

已知可以通过硬编码的方式实现:

df.query('f1>0 and f1<4 and f2>=1 and f2<=3 and f3>5 and f4>=0 and f4<=10')
# 或者
df.loc[df.f1.between(0,4,inclusive='neither')&df.f2.between(1,3)&df.f3.between(5,np.inf)&df.f4.between(0,10)]

但这种方式的缺点是当条件变更时需要修改代码,有没有更Pythonic的灵活处理方法?

解决方案

方法1:动态生成query语句

遍历条件DataFrame自动拼接查询字符串,实现条件与代码解耦,后续只需修改条件DataFrame即可:

import pandas as pd
import numpy as np

# 原始数据
df = pd.DataFrame({
    'id': range(1,12),
    'f1': [8.327,3.549,0.011,0.325,7.093,2.88,5.554,2.501,1.032,9.68,8.096],
    'f2': [9.905,0.452,0.238,0.792,7.312,7.834,1.649,2.941,6.961,7.922,4.344],
    'f3': [8.133,7.798,1.291,4.643,3.641,5.727,4.018,9.323,3.905,7.015,1.153],
    'f4': [0.785,5.797,7.593,4.3,9.88,6.984,0.623,0.565,8.116,7.542,5.244]
})

# 条件DataFrame
cond_df = pd.DataFrame({
    'variable': ['f1','f2','f3','f4'],
    'interval': ['(0,4)','[1,3]','(5,+np.inf)','[0,10]']
})

# 生成查询条件片段
query_parts = []
for _, row in cond_df.iterrows():
    var = row['variable']
    interval = row['interval']
    left_sym = interval[0]
    right_sym = interval[-1]
    nums = interval[1:-1].split(',')
    left_val = nums[0].strip()
    right_val = nums[1].strip()
    
    # 根据区间符号拼接比较条件
    query_parts.append(f"{var}>{left_val}" if left_sym == '(' else f"{var}>={left_val}")
    query_parts.append(f"{var}<{right_val}" if right_sym == ')' else f"{var}<={right_val}")

# 合并所有条件并执行查询
query_str = ' and '.join(query_parts)
result = df.query(query_str)
print(result)

方法2:动态生成between布尔掩码

利用Pandas向量化操作,循环生成每个变量的过滤掩码后合并,性能更优:

import pandas as pd
import numpy as np

# 初始化全True掩码
mask = pd.Series([True]*len(df), index=df.index)

for _, row in cond_df.iterrows():
    var = row['variable']
    interval = row['interval']
    left_sym = interval[0]
    right_sym = interval[-1]
    nums = interval[1:-1].split(',')
    
    # 处理无穷大值
    left_val = float(nums[0].strip()) if nums[0].strip() != '+np.inf' else -np.inf
    right_val = float(nums[1].strip()) if nums[1].strip() != '+np.inf' else np.inf
    
    # 确定区间包含方式
    if left_sym == '[' and right_sym == ']':
        inclusive = 'both'
    elif left_sym == '(' and right_sym == ')':
        inclusive = 'neither'
    elif left_sym == '[' and right_sym == ')':
        inclusive = 'left'
    else:
        inclusive = 'right'
    
    # 更新掩码
    mask &= df[var].between(left_val, right_val, inclusive=inclusive)

result = df[mask]
print(result)

方法3:使用pd.Interval对象直接判断

将条件转换为Pandas区间对象,通过成员判断生成过滤掩码:

import pandas as pd
import numpy as np

# 转换条件为区间字典
interval_dict = {}
for _, row in cond_df.iterrows():
    var = row['variable']
    interval_str = row['interval']
    left_sym = interval_str[0]
    right_sym = interval_str[-1]
    nums = interval_str[1:-1].split(',')
    
    left = float(nums[0].strip()) if nums[0].strip() != '+np.inf' else -np.inf
    right = float(nums[1].strip()) if nums[1].strip() != '+np.inf' else np.inf
    
    # 确定区间闭合方式
    if left_sym == '[' and right_sym == ']':
        closed = 'both'
    elif left_sym == '(' and right_sym == ')':
        closed = 'neither'
    elif left_sym == '[' and right_sym == ')':
        closed = 'left'
    else:
        closed = 'right'
    
    interval_dict[var] = pd.Interval(left, right, closed=closed)

# 生成掩码:所有变量都满足区间条件
mask = pd.concat(
    [df[var].apply(lambda x: x in interval_dict[var]) for var in interval_dict],
    axis=1
).all(axis=1)

result = df[mask]
print(result)

以上三种方法均实现了条件与过滤逻辑的解耦,后续修改条件只需更新cond_df,无需改动核心代码,符合Pythonic的灵活扩展原则。

内容的提问来源于stack exchange,提问作者Jason Bourne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 05:35:23