在进行groupby时保留其他列

101 投票
5 回答
95665 浏览
提问于 2025-04-18 04:54

我在使用 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. 先按你想要的最小值对项目进行排序
  2. 去掉你想排序的那一列中的重复项
  3. 重新对数据进行排序,因为数据还是按照最小值排序的
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 indexingtransform 来获取每个组的最小值。

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]

请注意,虽然行内容相同,但得到的索引是不同的。

撰写回答