我有一个Pandas DataFrame,其中有一个有意义的索引和各种重复行的组。假设它看起来像这样:
>>> import pandas as pd
>>> df = pd.DataFrame([[1, 1, 1], [2, 3, 4], [2, 3, 4], [1, 1, 1], [1, 1, 1], [1, 1, 1], [3, 3, 3]], columns=["a", "b", "c"])
>>> df
a b c
0 1 1 1
1 2 3 4
2 2 3 4
3 1 1 1
4 1 1 1
5 1 1 1
6 3 3 3
我试图删除重复的行(除了每个重复批处理中的第一个),但保留批处理中最后一行的索引。
我正在寻找的结果是这个(即一个新的"last";包含批处理中最后一个重复行的索引的列(如果没有重复,则等于索引):
>>> df2
last a b c
0 0 1 1 1
1 2 2 3 4
3 5 1 1 1
6 6 3 3 3
注意,[1, 1, 1]
条目出现了两次,并且被视为单独的块。
我尝试了group_by
,duplicated
等的各种组合,但没有找到必要的配方。这感觉应该是一件相当标准的事情。是否有一种直接的方法来实现任意数据框架?
编辑:
请注意,我希望保留批处理中第一个项目的原始索引,并为批处理中的最后一个索引添加一个名为last
的新列。
在你的例子中
out = df[~df.shift().ne(df).cumsum().duplicated(keep='last')]
Out[19]:
a b c
0 1 1 1
2 2 3 4
5 1 1 1
6 3 3 3
一种方法,类似于BENYs的方法,但使用pandas.DataFrame.diff
:
df[~df.diff().cumsum().duplicated(keep='last')]
a b c
0 1 1 1
2 2 3 4
5 1 1 1
6 3 3 3
感谢@BENY和@jab的回答,非常接近我所需要的。我添加了额外的last
索引列,并进行了一些简单的调整,如下所示:
last_indices = df[~df.diff().cumsum().duplicated(keep='last')].index
df2 = df[~df.diff().cumsum().duplicated(keep='first')]
df2.insert(0, "last", last_indices)
这个收益率:
last a b c
0 0 1 1 1
1 2 2 3 4
3 5 1 1 1
6 6 3 3 3
扩展:
虽然在问题中没有要求,但一个有用的扩展是添加一个包含每个组的计数的列。下面的代码实现了这一点(不依赖于密集的整数索引):
count_groups = df.ne(df.shift()).cumsum().max(axis=1)
counts = count_groups.groupby(count_groups).agg("count")
df2.insert(1, "counts", counts.values)
收益率:
last counts a b c
0 0 1 1 1 1
1 2 2 2 3 4
3 5 3 1 1 1
6 6 1 3 3 3