13

假设我有一个这样的熊猫数据框:

  cat  val
0   a    1
1   a    6
2   a   12
3   b    2
4   b    5
5   b   11
6   c    4
7   c   22

而且我想知道,对于每个类别('cat' 的每个值),值最接近给定值的位置是什么,比如 5.5。我可以减去我的目标值并取绝对值,给我这样的东西:

  cat  val  val_delt
0   a    1       4.5
1   a    6       0.5
2   a   12       6.5
3   b    2       3.5
4   b    5       0.5
5   b   11       5.5
6   c    4       1.5
7   c   22      16.5

但我不知道下一步该去哪里。我的第一个想法是将 argmin() 与 groupby() 一起使用,但这会产生错误:

In [375]: df.groupby('cat').val_delt.argmin()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-375-a2c3dbc43c50> in <module>()
----> 1 df.groupby('cat').val_delt.argmin()

TypeError: 'Series' object is not callable

当然,我可以在标准 python 中想出一些可怕的 hacky 东西,在其中迭代 cat 的所有值,然后选择与该值相对应的数据子集,执行 argmin 操作,然后找出原始数据框中的位置排是。但是必须有一种更优雅的方式来做到这一点。

我想要的输出是这样的:

  cat  val
1   a    6      
4   b    5       
6   c    4  

或至少一些包含相关信息的结构(例如 - {'a':1, 'b':4, 'c':6} )。我不在乎我是否取回索引值或索引位置,但我需要两者之一。我不在乎取回价值——一旦我有了索引子集,我总是可以在以后得到它。

4

5 回答 5

6

argmin()不是 agg 函数,您可以使用 apply 来获取每个组的最近索引:

txt = """  cat  val
0   a    1
1   a    6
2   a   12
3   b    2
4   b    5
5   b   11
6   c    4
7   c   22"""

import io

df = pd.read_csv(io.BytesIO(txt), delim_whitespace=True, index_col=0)
df["val_delt"] = (df.val - 5.5).abs()
idx = df.groupby("cat").apply(lambda df:df.val_delt.argmin())
df.ix[idx, :]

输出:

cat  val  val_delt
1   a    6       0.5
4   b    5       0.5
6   c    4       1.5
于 2013-10-29T01:39:53.780 回答
5

这里的所有答案都有些正确,但没有一个以简洁、美丽和 Python 的方式做到这一点。我在这里留下了一个明确的方法来做到这一点。

>>> indx = df.groupby('cat')['val_delt'].idxmin()
>>> df.loc[indx]

  cat  val  val_delt
1   a    6       0.5
4   b    5       0.5
6   c    4       1.5
于 2019-07-24T09:56:40.567 回答
4

只需添加到 HYRY 答案,您就可以使用 idxmin。例子:

import io
txt = """  cat  val
0   a    1
1   a    6
2   a   12
3   b    2
4   b    5
5   b   11
6   c    4
7   c   22"""
df = pd.read_csv(io.BytesIO(txt.encode()), delim_whitespace=True, index_col=0)
df["val_delt"] = (df.val - 5.5).abs()
idx = df.groupby("cat").apply(lambda df:df.val_delt.idxmin())
df.ix[idx, :]
于 2015-04-13T13:11:49.717 回答
3

你不需要申请。

idxmin足够了。只需要确保您已经设置了您想要的最小值。

>>> df['val_delt'] = (df.val - 5.5).abs()
>>> df.set_index('val').groupby('cat').idxmin()
     val_delt
cat          
a           6
b           5
c           4
于 2018-12-06T14:21:07.020 回答
0

您可以替换df.groupby('cat').val_delt.argmin()df.sort_values(['cat', 'val_delt']).groupby('cat').head(1). cat本质上,这是按两列( ,后跟)对 DataFrame 进行排序val_delt

代码

df = pd.DataFrame([['a', 1], ['a', 6], ['a', 12], ['b', 2], ['b', 5], ['b', 11], ['c', 4], ['c', 22]], columns=['cat', 'val'])
df['val_delt'] = (df.val - 5.5).abs()
df.sort_values(['cat', 'val_delt']).groupby('cat').head(1)

结果

  cat  val  val_delt
1   a    6       0.5
4   b    5       0.5
6   c    4       1.5
于 2020-04-13T05:12:50.230 回答