Как вернуть значение другого столбца в groupby + применить - PullRequest
0 голосов
/ 04 апреля 2020

У меня есть такой DataFrame:

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

, где closest - это значение obj, которое является ближайшим к (x0, y0) в каждом group. Однако у меня возникли проблемы с использованием функции 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 на нем

1 Ответ

1 голос
/ 04 апреля 2020

Полагаю, вы хотите 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))', чтобы получить позицию минимальной строки.

...