在进行groupby时保留其他列
我在使用 groupby
这个功能来处理 pandas 数据框,目的是删除那些在某个特定列中没有最小值的行。大概是这样的:
df1 = df.groupby("item", as_index=False)["diff"].min()
不过,如果我有超过这两个列,其他的列(比如我例子中的 otherstuff
)就会被删除。我能不能在使用 groupby
的时候保留这些列,还是说我得找其他方法来删除这些行呢?
我的数据看起来是这样的:
item diff otherstuff
0 1 2 1
1 1 1 2
2 1 3 7
3 2 -1 0
4 2 1 3
5 2 4 9
6 2 -6 2
7 3 0 0
8 3 2 9
最后应该变成这样:
item diff otherstuff
0 1 1 2
1 2 -6 2
2 3 0 0
但我现在得到的是:
item diff
0 1 1
1 2 -6
2 3 0
我查阅了文档,但找不到相关的信息。我尝试过:
df1 = df.groupby(["item", "otherstuff"], as_index=false)["diff"].min()
df1 = df.groupby("item", as_index=false)["diff"].min()["otherstuff"]
df1 = df.groupby("item", as_index=false)["otherstuff", "diff"].min()
但是这些都不管用。
5 个回答
-1
如果你知道你的所有“项目”都有多个记录可以排序,那么可以使用 duplicated
这个功能:
df.sort_values(by='diff').duplicated(subset='item', keep='first')
1
我试过了大家的方法,但就是没法正常工作。最后我一步一步地做,结果得到了正确的结果。
df.sort_values(by='item', inplace=True, ignore_index=True)
df.drop_duplicates(subset='diff', inplace=True, ignore_index=True)
df.sort_values(by=['diff'], inplace=True, ignore_index=True)
再多解释一下:
- 先按你想要的最小值对项目进行排序
- 去掉你想排序的那一列中的重复项
- 重新对数据进行排序,因为数据还是按照最小值排序的
1
上面的回答在只有一个最小值的情况下效果很好。如果你想要多个最小值,或者在我的情况下有多个最小值,我想要所有等于最小值的行,而 .idxmin()
这个方法并不能满足这个需求。这个方法可以解决我的问题。
def filter_group(dfg, col):
return dfg[dfg[col] == dfg[col].min()]
df = pd.DataFrame({'g': ['a'] * 6 + ['b'] * 6, 'v1': (list(range(3)) + list(range(3))) * 2, 'v2': range(12)})
df.groupby('g',group_keys=False).apply(lambda x: filter_group(x,'v1'))
顺便提一下,.filter() 这个方法也和这个问题有关,但对我来说没有用。
15
你可以使用 DataFrame.sort_values
结合 DataFrame.drop_duplicates
来处理数据。
df = df.sort_values(by='diff').drop_duplicates(subset='item')
print (df)
item diff otherstuff
6 2 -6 2
7 3 0 0
1 1 1 2
如果每个组里可能有多个最小值,并且你想要所有这些最小值的行,可以使用 boolean indexing
和 transform
来获取每个组的最小值。
print (df)
item diff otherstuff
0 1 2 1
1 1 1 2 <-multiple min
2 1 1 7 <-multiple min
3 2 -1 0
4 2 1 3
5 2 4 9
6 2 -6 2
7 3 0 0
8 3 2 9
print (df.groupby("item")["diff"].transform('min'))
0 1
1 1
2 1
3 -6
4 -6
5 -6
6 -6
7 0
8 0
Name: diff, dtype: int64
df = df[df.groupby("item")["diff"].transform('min') == df['diff']]
print (df)
item diff otherstuff
1 1 1 2
2 1 1 7
6 2 -6 2
7 3 0 0
175
方法一:使用 idxmin()
来获取最小 diff
元素的 索引,然后选择这些索引对应的元素:
>>> df.loc[df.groupby("item")["diff"].idxmin()]
item diff otherstuff
1 1 1 2
6 2 -6 2
7 3 0 0
[3 rows x 3 columns]
方法二:先按 diff
排序,然后从每个 item
组中取第一个元素:
>>> df.sort_values("diff").groupby("item", as_index=False).first()
item diff otherstuff
0 1 1 2
1 2 -6 2
2 3 0 0
[3 rows x 3 columns]
请注意,虽然行内容相同,但得到的索引是不同的。