假设我有一个像这样的 Pandas 数据框:

  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中提出一些可怕的技巧,在其中迭代cat的所有值,然后选择与该值相对应的数据子集,执行argmin操作,然后找出原始数据框中的位置行了。但是必须有一种更优雅的方式来做到这一点。

我想要的输出是这样的:
  cat  val
1   a    6
4   b    5
6   c    4

或至少包含该相关信息的某些结构(例如-{'a':1,'b':4,'c':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

10-04 13:49