Pandas groupby и apply - получение нового DataFrame поверх переменной groupby - PullRequest
0 голосов
/ 28 ноября 2018

Я пытаюсь использовать pandas.DataFrame.groupby['x'] для расчета по сгруппированному df, по x.

Проблема возникает, когда 'x' повторяется более одного раза.Функция apply будет выполнять вычисления столько раз, сколько повторяется 'x', хотя мне нужны только "агрегированные" значения (на самом деле это не агрегация , а скорее как - обработка ).

Вот игрушечный пример:

def simulate_complicated_func(df):
    # This function simulates complicate calculations
    returned_col_names = ['calc1', 'calc2', 'calc3']

    df['calc1'] = ''.join(df['var1'])
    df['calc2'] = df['var2'].mean()
    df['calc3'] = ''.join(df['var1']) + str(df['var2'].max())

    return df[['id'] + returned_col_names]

df = pd.DataFrame({'id':['id1', 'id1', 'id2', 'id3', 'id3', 'id3'],
                   'var1':['abc', 'cba', 'abc', 'cba', 'abc', 'cba'],
                   'var2':[9, 4, 7, 4, 1, 3]})

print(df)

    id var1  var2
0  id1  abc     9
1  id1  cba     4
2  id2  abc     7
3  id3  cba     4
4  id3  abc     1
5  id3  cba     3

res_df = df.groupby(['id']).apply(simulate_complicated_func).drop_duplicates()
print(res_df)

    id      calc1     calc2       calc3
0  id1     abccba  6.500000     abccba9
2  id2        abc  7.000000        abc7
3  id3  cbaabccba  2.666667  cbaabccba4

Вывод - именно то, что я хочу, но он не эффективен.Есть ли лучший способ сделать это с помощью панд?

Редактировать: Как оптимизировать?

Если мы добавим оператор print к simulate_complicated_func()

def simulate_complicated_func(df):
    # This function simulates complicate calculations
    print("function called")
    # ...

Мы видим, что код напечатает его 6 раз:

function called
function called
function called
function called
function called
function called

На самом деле, нам нужно получить доступ к этой функции только 3 раза (количество групп, созданных groupby).

1 Ответ

0 голосов
/ 28 ноября 2018

Одной идеей является возврат Series из пользовательской функции, поэтому drop_duplicates не требуется:

def simulate_complicated_func(df):
    # This function simulates complicate calculations
    returned_col_names = ['calc1', 'calc2', 'calc3']

    a = ''.join(df['var1'])
    b = df['var2'].mean()
    c = ''.join(df['var1']) + str(df['var2'].max())

    return pd.Series([a,b,c], index=returned_col_names)

res_df = df.groupby(['id']).apply(simulate_complicated_func).reset_index()
print(res_df)
    id      calc1     calc2       calc3
0  id1     abccba  6.500000     abccba9
1  id2        abc  7.000000        abc7
2  id3  cbaabccba  2.666667  cbaabccba4

Другая идея заключается в использовании DataFrameGroupBy.agg, но это возможно только дляобработка всех столбцов с помощью агрегированных функций, таких как join и mean.Функция agg работает с каждым столбцом отдельно, поэтому cal3 не представляется возможным простым / эффективным способом подсчета - необходима снова пользовательская функция и вывод последнего соединения вместе:

def simulate_complicated_func(df):
    # This function simulates complicate calculations
    returned_col_names = ['calc3']
    c = ''.join(df['var1']) + str(df['var2'].max())
    return pd.Series([c], index=returned_col_names)

d = {'var1': ''.join, 'var2':'mean'}
cols = {'var1':'calc1','var2':'calc2'}
g = df.groupby(['id'])

df1 = g.agg(d).rename(columns=cols)
print (df1)
         calc1     calc2
id                      
id1     abccba  6.500000
id2        abc  7.000000
id3  cbaabccba  2.666667

df2 = df.groupby(['id']).apply(simulate_complicated_func)
print(df2)
          calc3
id             
id1     abccba9
id2        abc7
id3  cbaabccba4

df = pd.concat([df1, df2], axis=1).reset_index()
print (df)
    id      calc1     calc2       calc3
0  id1     abccba  6.500000     abccba9
1  id2        abc  7.000000        abc7
2  id3  cbaabccba  2.666667  cbaabccba4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...