基于多条件筛选移除Pandas DataFrame中不符合要求的分组
筛选满足三类样本条件的Pandas分组
需求说明
需要对包含Group和Sample_Number列的Pandas DataFrame进行分组筛选,仅保留同时满足以下三个条件的分组:
- 包含且仅包含1个样本编号11
- 至少包含1个21-29范围内的样本编号
- 至少包含1个31-39范围内的样本编号
不满足任一条件的分组需整体移除。
示例数据
示例DataFrame
| Group | Sample_Number |
|---|---|
| Z007 | 11 |
| Z007 | 21 |
| Z007 | 22 |
| Z007 | 23 |
| Z007 | 31 |
| Z007 | 32 |
| Z008 | 11 |
| Z008 | 31 |
| Z008 | 32 |
| Z008 | 33 |
| Z009 | 11 |
| Z009 | 21 |
| Z009 | 22 |
| Z009 | 23 |
| Z010 | 21 |
| Z010 | 22 |
| Z010 | 23 |
| Z010 | 24 |
| Z010 | 31 |
| Z010 | 32 |
| Z010 | 33 |
| Z010 | 34 |
创建示例DataFrame的代码
import pandas as pd df = pd.DataFrame( [ ['Z007', 11], ['Z007', 21], ['Z007', 22], ['Z007', 23], ['Z007', 31], ['Z007', 32], ['Z008', 11], ['Z008', 31], ['Z008', 32], ['Z008', 33], ['Z009', 11], ['Z009', 21], ['Z009', 22], ['Z009', 23], ['Z010', 21], ['Z010', 22], ['Z010', 23], ['Z010', 24], ['Z010', 31], ['Z010', 32], ['Z010', 33], ['Z010', 34] ], columns=['Group', 'Sample_Number'] )
其中Z008无21-29样本、Z009无31-39样本、Z010无样本11,均需移除,最终仅保留Z007分组。
解决方案
方法一:Pandas原生分组聚合(高效推荐)
利用groupby结合聚合函数一次性计算每个分组的条件满足情况,再筛选有效分组:
# 计算每个分组的三个条件指标 group_stats = df.groupby('Group').agg( # 检查11是否恰好出现1次 has_exact_11=('Sample_Number', lambda x: x.value_counts().get(11, 0) == 1), # 检查是否存在21-29范围内的样本 has_21_29=('Sample_Number', lambda x: ((x >= 21) & (x <= 29)).any()), # 检查是否存在31-39范围内的样本 has_31_39=('Sample_Number', lambda x: ((x >= 31) & (x <= 39)).any()) ) # 筛选出三个条件都满足的分组 valid_groups = group_stats[ group_stats['has_exact_11'] & group_stats['has_21_29'] & group_stats['has_31_39'] ].index # 过滤原DataFrame,仅保留有效分组 filtered_df = df[df['Group'].isin(valid_groups)]
方法二:基于原逻辑扩展(循环遍历分组)
在你已实现的11计数检查基础上,补充另外两个范围的检查:
invalid_groups = [] for group in df['Group'].unique(): samples = df[df['Group'] == group]['Sample_Number'].tolist() # 条件1:11出现次数不等于1 cond1 = samples.count(11) != 1 # 条件2:无21-29区间的样本 cond2 = not any(21 <= s <= 29 for s in samples) # 条件3:无31-39区间的样本 cond3 = not any(31 <= s <= 39 for s in samples) # 任一条件不满足则标记为无效分组 if cond1 or cond2 or cond3: invalid_groups.append(group) # 过滤掉无效分组 filtered_df = df[~df['Group'].isin(invalid_groups)]
两种方法最终都会得到仅包含Z007分组的结果。
内容的提问来源于stack exchange,提问作者Prasad
相关产品推荐
相关产品推荐

