看过来
《pandas 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gr99123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。
此案例是将提供的数据进行过滤筛选,这个筛选操作是按分组进行的,按照组内的顺序,在上下相邻值和为 0 的时候,将这两个值所在的行删除。我们来看一下具体的数据和需求详情。在本例中,作者的 Python 版本是 3.11.3,pandas 版本为 2.0.1。
数据如下,我们依然用剪贴板方法读取到 DataFrame。
from io import StringIO
import pandas as pd
data = '''
x y
a 6
a 6
a 6
b -6
a -6
b 6
b -6
b 6
b 6
a 6
a -6
'''
df = pd.read_csv(StringIO(data), sep=r'\s+')
df
# ...
需求期望将 y 列的数值进行计算,以 a 组为例:
df.query('x=="a"')
'''
x y
0 a 6
1 a 6
2 a 6
4 a -6
9 a 6
10 a -6
'''
索引 0 和 1 之和不为 0,不删除;索引 1 和 2 之和不为 0,不删除;索引 2 和 4 之和为 0,需要将 索引 2 和 4 删除;接着往下,索引 4 已经删除,索引 9 和 10 求和,为 0,需要将 索引 9 和 10 删除。a 组最终仅保留索引 0 和 1 两行。
本例需要按分组进行处理,首先我们需要使用 pandas 的 groupby(),每个分组是一个子 DataFrame,我们现在只需要讨论单个分组的 DataFrame 如何处理就好,没问题后分组应用这个处理方法。
针对单个 DataFrame 中的一列 y,我们需要前后两两计算,开始如有一个列表 [1, 2, 3, 4],计算过程依次是 (1,2)、(2、3)、(3、4)。遇到这种情况,Python 内置的模块 itertools 提供了一个 pairwise 迭代器,可以实现这个功能。
利用 pairwise 迭代器的组合功能,我们将 y 这个 Series 进行迭代,如果计算为 0 行的索引就放入一个要删除的集合中(保证不重复),如果已经在这个集合就不再放入。
最后,将要删除的索引在子 DataFrame 进行反选,留下的就是要保留的行,最终产生一个要保留的 DataFrame。
我们根据上边的思路来编写代码。首先,将各组的子 DataFrame 处理方法封闭为一个函数:
from itertools import pairwise
def grou_del_idex(grp):
items = grp.y.items() # 【1】
del_idex = set() # 【2】
for i,nxt in pairwise(items): # 【3】
if (i[1] + nxt[1] == 0
and i[0] not in del_idex
and nxt[0] not in del_idex): # 【4】
del_idex.add(i[0])
del_idex.add(nxt[0])
return grp[~grp.index.isin(del_idex)] # 【5】
以下是这个函数的标注讲解:
最后,我们将这个处理函数应用到分组中:
df.groupby('x', group_keys=False).apply(grou_del_idex)
'''
x y
0 a 6
1 a 6
8 b 6
'''
这样就得到了最终结果。
(完)
更新时间:2024-08-18 15:55:08 标签:pandas python 分组