python - Python分组;仅在满足条件时保留
问题描述
假设您有一个数据集,其中包含零件、项目、报价、价格和isSelected
.
对于每个零件、项目和报价,如果有isSelected
,则只保留那一行,但如果没有isSelected
,则保留该零件、项目和报价组合的所有行。
请参见下面的示例。
数据集:
部分 | 项目 | 引用 | 价格 | 被选中 |
---|---|---|---|---|
1 | 一个 | 1 | 5.0 | 不 |
1 | 一个 | 1 | 2.2 | 是的 |
5 | C | 2 | 6.6 | 不 |
5 | C | 2 | 1.2 | 是的 |
3 | 乙 | 3 | 5.5 | 不 |
3 | 乙 | 3 | 4.6 | 不 |
期望的结果:
部分 | 项目 | 引用 | 价格 | 被选中 |
---|---|---|---|---|
1 | 一个 | 1 | 2.2 | 是的 |
5 | C | 2 | 1.2 | 是的 |
3 | 乙 | 3 | 5.5 | 不 |
3 | 乙 | 3 | 4.6 | 不 |
解决方案
这种一般的任务类别可以通过遍历由 a或的操作GroupBy
产生的对象来解决。.groupby
Series
DataFrame
在这种特殊情况下,您还可以使用GroupBy.apply
方法,该方法对每个组执行计算并将结果连接在一起。
GroupBy
该类的文档在这里。
我将首先介绍循环版本,因为对于尚未熟悉计算的“DataFrame 风格”的程序员来说,它可能更易于使用。但是,我建议.apply
尽可能使用该版本。处理大型数据集时速度会更快,并且可能会消耗更少的内存。它也被认为是更“惯用”的风格,它将迫使您学习如何将代码分解为单独的函数。
使用循环
很多人没有意识到DataFrame.groupby
(GroupBy
对象)的结果可以被迭代。此处记录了此特定功能。
除此之外,逻辑由一个简单的if
语句、一些 Pandas 子集和concat
函数组成。
完整示例:
import io
import pandas as pd
data = pd.read_csv(io.StringIO('''
Part,Project,Quote,Price,isSelected
1,A,1,5.0,No
1,A,1,2.2,Yes
5,C,2,6.6,No
5,C,2,1.2,Yes
3,B,3,5.5,No
3,B,3,4.6,No
'''))
group_results = []
for _, group in data.groupby(['Part', 'Project', 'Quote']):
is_selected = group['isSelected'] == 'Yes'
if is_selected.any():
# Select the rows where 'isSelected' is True, and
# then select the first row from that output.
# Using [0] instead of 0 ensures that the result
# is still a DataFrame, and that it does not get
# "squeezed" down to a Series.
group_result = group.loc[is_selected].iloc[[0]]
else:
group_result = group
group_results.append(group_result)
results = pd.concat(group_results)
print(results)
输出:
Part Project Quote Price isSelected
1 1 A 1 2.2 Yes
4 3 B 3 5.5 No
5 3 B 3 4.6 No
3 5 C 2 1.2 Yes
使用.apply
该GroupBy.apply
方法本质上pd.concat
为您完成了列表附加部分。我们没有编写循环,而是编写了一个函数,我们将其传递给.apply
:
import io
import pandas as pd
data = pd.read_csv(io.StringIO('''
Part,Project,Quote,Price,isSelected
1,A,1,5.0,No
1,A,1,2.2,Yes
5,C,2,6.6,No
5,C,2,1.2,Yes
3,B,3,5.5,No
3,B,3,4.6,No
'''))
groups = data.groupby(['Part', 'Project', 'Quote'], as_index=False)
def process_group(group):
is_selected = group['isSelected'] == 'Yes'
if is_selected.any():
# Select the rows where 'isSelected' is True, and
# then select the first row from that output.
# Using [0] instead of 0 ensures that the result
# is still a DataFrame, and that it does not get
# "squeezed" down to a Series.
group_result = group.loc[is_selected].iloc[[0]]
else:
group_result = group
return group_result
# Use .reset_index to remove the extra index layer created by Pandas,
# which is not necessary in this situation.
results = groups.apply(process_group).reset_index(level=0, drop=True)
print(results)
输出:
Part Project Quote Price isSelected
1 1 A 1 2.2 Yes
4 3 B 3 5.5 No
5 3 B 3 4.6 No
3 5 C 2 1.2 Yes
推荐阅读
- node.js - MongoDB E11000 重复键错误集合,架构中没有唯一字段
- cucumber-java - Cucumber-Java-Selenium:如何在胶水代码之间共享变量
- javascript - 如何使用设备方向和指南针航向确定 iOS 设备指向天空的哪个位置?
- python - 使用数据框时出现意外的 __rsub__ 输出
- python - 我如何只能继承父类的 4 个属性中的 2 个?
- python - matplotlib如何增量add_subplot并在最后渲染
- spring - 无法在特定字典上运行 Docker 以保留 mongo
- python - 散景线图,有没有办法将线条颜色设置为渐变?
- c++ - 通过 ostringstream 格式化时可以混合字符串和整数/浮点数吗
- pandas - 如何使用 Pandas 数据框在多列中按 Id 分组