Pandas - GroupBy, а затем Merge на оригинальной таблице

Я пытаюсь написать функцию для агрегирования и вычисления различных статистических данных на фрейме данных в Pandas, а затем объединить его с исходным фреймворком данных, однако я бегу к проблемам. Это эквивалент кода в SQL:

SELECT EID,
       PCODE,
       SUM(PVALUE) AS PVALUE,
       SUM(SQRT(SC*EXP(SC-1))) AS SC,
       SUM(SI) AS SI,
       SUM(EE) AS EE
INTO foo_bar_grp
FROM foo_bar
GROUP BY EID, PCODE 

И затем присоединитесь к исходной таблице:

SELECT *
FROM foo_bar_grp INNER JOIN 
foo_bar ON foo_bar.EID = foo_bar_grp.EID 
        AND foo_bar.PCODE = foo_bar_grp.PCODE

Вот шаги: Загрузка данных IN: →

pol_dict = {'PID':[1,1,2,2],
             'EID':[123,123,123,123],
             'PCODE':['GU','GR','GU','GR'],
             'PVALUE':[100,50,150,300],
             'SI':[400,40,140,140],
             'SC':[230,23,213,213],
             'EE':[10000,10000,2000,30000],
             }


pol_df = DataFrame(pol_dict)

pol_df

OUT: →

   EID    EE PCODE  PID  PVALUE   SC   SI
0  123  10000    GU    1     100  230  400
1  123  10000    GR    1      50   23   40
2  123   2000    GU    2     150  213  140
3  123  30000    GR    2     300  213  140

Шаг 2. Вычисление и группировка данных:

Мой Pandas код выглядит следующим образом:

#create aggregation dataframe
poagg_df = pol_df
del poagg_df['PID']
po_grouped_df = poagg_df.groupby(['EID','PCODE'])

#generate acc level aggregate
acc_df = po_grouped_df.agg({
    'PVALUE' : np.sum,
    'SI' : lambda x: np.sqrt(np.sum(x * np.exp(x-1))),
    'SC' : np.sum,
    'EE' : np.sum
})

Это работает нормально, пока я не захочу присоединиться к исходной таблице:

В: →

po_account_df = pd.merge(acc_df, po_df, on=['EID','PCODE'], how='inner',suffixes=('_Acc','_Po'))

OUT: → KeyError: u'no элемент с именем EID '

По какой-то причине сгруппированный блок данных не может присоединиться к исходной таблице. Я рассмотрел способы попыток конвертировать столбцы groupby в фактические столбцы, но это, похоже, не работает.

Обратите внимание: конечная цель - найти процент для каждого столбца (PVALUE, SI, SC, EE) IE:

pol_acc_df['PVALUE_PCT'] = np.round(pol_acc_df.PVALUE_Po/pol_acc_df.PVALUE_Acc,4)

Спасибо!

Ответы

Ответ 1

По умолчанию вывод groupby имеет столбцы группировки как знаки, а не столбцы, поэтому слияние не выполняется.

Существует несколько способов обращения с ним, возможно, самым простым является использование параметра as_index при определении объекта groupby.

po_grouped_df = poagg_df.groupby(['EID','PCODE'], as_index=False)

Затем ваше слияние должно работать как ожидалось.

In [356]: pd.merge(acc_df, pol_df, on=['EID','PCODE'], how='inner',suffixes=('_Acc','_Po'))
Out[356]: 
   EID PCODE  SC_Acc  EE_Acc        SI_Acc  PVALUE_Acc  EE_Po  PVALUE_Po  \
0  123    GR     236   40000  1.805222e+31         350  10000         50   
1  123    GR     236   40000  1.805222e+31         350  30000        300   
2  123    GU     443   12000  8.765549e+87         250  10000        100   
3  123    GU     443   12000  8.765549e+87         250   2000        150   

   SC_Po  SI_Po  
0     23     40  
1    213    140  
2    230    400  
3    213    140  

Ответ 2

Из документов панд:

Преобразование: выполнить некоторые групповые вычисления и вернуть объект с одинаковым индексом

К сожалению, transform работы последовательно за серией, поэтому вы не сможете выполнять несколько функций для нескольких столбцов, как вы это делали с помощью agg, но transform позволяет пропустить merge

po_grouped_df = pol_df.groupby(['EID','PCODE'])
pol_df['sum_pval'] = po_grouped_df['PVALUE'].transform(sum)
pol_df['func_si'] = po_grouped_df['SI'].transform(lambda x: np.sqrt(np.sum(x * np.exp(x-1))))
pol_df['sum_sc'] = po_grouped_df['SC'].transform(sum)
pol_df['sum_ee'] = po_grouped_df['EE'].transform(sum)
pol_df

Результаты в:

PID EID PCODE   PVALUE  SI  SC  EE      sum_pval    func_si         sum_sc  sum_ee
1   123 GU      100     400 230 10000   250         8.765549e+87    443     12000
1   123 GR      50      40  23  10000   350         1.805222e+31    236     40000
2   123 GU      150     140 213 2000    250         8.765549e+87    443     12000
2   123 GR      300     140 213 30000   350         1.805222e+31    236     40000

Для получения дополнительной информации, проверьте этот SO ответ.