【问题标题】:How to return a value of another column within groupby+apply如何在 groupby+apply 中返回另一列的值
【发布时间】:2020-04-04 08:05:39
【问题描述】:

我有一个这样的数据框:

import pandas as pd
import numpy as np

df = pd.DataFrame.from_dict({'group': [1, 1, 1, 2, 2, 2, 3, 3, 3], 
                             'obj': [1, 2, 3, 1, 2, 3, 1, 2, 3],
                             'x0': np.repeat(np.random.rand(3), 3), 
                             'y0': np.repeat(np.random.rand(3), 3), 
                             'x': np.random.rand(9), 
                             'y': np.random.rand(9)})


   group  obj        x0        y0         x         y
0      1    1  0.577952  0.936173  0.681409  0.905242
1      1    2  0.577952  0.936173  0.995970  0.284488
2      1    3  0.577952  0.936173  0.436973  0.163712
3      2    1  0.802995  0.264205  0.586934  0.292848
4      2    2  0.802995  0.264205  0.204437  0.022746
5      2    3  0.802995  0.264205  0.626687  0.000793
6      3    1  0.343862  0.847310  0.966428  0.496161
7      3    2  0.343862  0.847310  0.465727  0.512349
8      3    3  0.343862  0.847310  0.069815  0.689743

我想将此 DataFrame 聚合为如下所示的:

   group        x0        y0  closest
0      1  0.577952  0.936173        3
1      2  0.802995  0.264205        1
2      3  0.343862  0.847310        1

其中closestobj 的值,它在每个group 中最接近(x0, y0)。但是,我无法使用aggregate 函数来计算使用列的距离。我得到的最远的是:

df.groupby('group').apply(lambda x: np.sqrt((x['x0'] - x['x']) ** 2 + (x['y0'] - x['y']) ** 2).argmin())

我计算最接近obj 的索引,但我不知道如何返回obj 的值。我试过lambda x: x.iloc[ np.sqrt((x['x0'] - x['x']) ** 2 + (x['y0'] - x['y']) ** 2).argmin(), 'obj'],但它会导致错误。因此我的问题是:

  • 如何返回值 obj 而不是索引?
  • 我从 groupby + apply 获得的对象是什么?它似乎不是 DataFrame,因为我不能在上面使用.iloc

【问题讨论】:

    标签: python pandas group-by aggregate


    【解决方案1】:

    我相信您希望 DataFrameGroupBy.idxmin 带有帮助列以提高性能:

    df['new'] = np.sqrt((df['x0'] - df['x']) ** 2 + (df['y0'] - df['y']) ** 2)
    
    df = df.loc[df.groupby('group')['new'].idxmin()]
    print (df)
       group  obj        x0        y0         x         y       new
    0      1    1  0.577952  0.936173  0.681409  0.905242  0.107982
    3      2    1  0.802995  0.264205  0.586934  0.292848  0.217951
    8      3    3  0.343862  0.847310  0.069815  0.689743  0.316116
    

    您的解决方案返回相同的 obj 值:

    def f(x):
        x = df.iloc[np.sqrt((x['x0'] - x['x']) ** 2 + (x['y0'] - x['y']) ** 2).argmin()]
        return x
    
    df = df.groupby('group').apply(f)
    print (df)
           group  obj        x0        y0         x         y
    group                                                    
    1        1.0  1.0  0.577952  0.936173  0.681409  0.905242
    2        2.0  1.0  0.802995  0.264205  0.586934  0.292848
    3        3.0  3.0  0.343862  0.847310  0.069815  0.689743
    

    但是有警告:

    “Series.argmin”的当前行为已弃用,请改用“idxmin”。
    'argmin' 的行为将被纠正以在将来返回位置最小值。现在,使用 'series.values.argmin' 或 'np.argmin(np.array(values))' 来获取最小行的位置。

    【讨论】:

    • 我喜欢第一种方法及其效率。但是当组内new 列的所有值都是NaN 并且结果NaN 被传递给df.loc 导致KeyError: 'Passing list-likes to .loc or [] with any missing labels is no longer supported 时,我该如何处理?
    • @jakes 1.idea 正在使用 reindex 而不是 loc,但我猜 idxmin 与 nan 返回 nan,因此 reindex 创建了新的行填充 nan。我认为主要问题是 nans 的预期输出是什么?因为如果组的第一行那么应该将 nans 替换为 python 的最大值浮点数或一些大整数。因此,如果每个组的所有 nan 都返回第一个值,但也避免如果每个组只有一些 nan,则不能使用此值(因为那时必须至少存在一个少一个数字).2。想法只是通过 df.dropna(subset=['new']) 删除每个新列的所有 nans 行。未测试,因为离线,仅在手机上。
    • 如果idxmin() 结果为NaN,我希望new 列具有NaN 值。恐怕dropna 不会那样工作,因为它会扔掉整行。
    • 我同意了你的第一个建议,即df['new'] = np.sqrt((df['x0'] - df['x']) ** 2 + (df['y0'] - df['y']) ** 2).fillna(9999); df = df.loc[df.groupby('group')['new'].idxmin()]; df['new'].replace(9999, np.nan),效果很好!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-25
    • 2018-11-04
    • 1970-01-01
    • 2020-10-26
    • 2011-01-31
    相关资源
    最近更新 更多