2017-10-19 19 views
1

J'ai un dataframe qui a deux indices de colonne de niveau. J'ai besoin d'avoir différentes fonctions d'agrégation sur deux clés (colonnes). Cependant, j'ai reçu une erreur sur mon code. Comment puis-je agréger sur plusieurs colonnes dans une structure de données multiniveau.globale de l'indice à plusieurs niveaux

dic1 = {('count', 'N.A.'): {Period('1993-01', 'M'): 0, 
    Period('1993-02', 'M'): 0, 
    Period('1993-03', 'M'): 0}, 
('count', 'No'): {Period('1993-01', 'M'): 1, 
    Period('1993-02', 'M'): 1, 
    Period('1993-03', 'M'): 1}, 
('count', 'Yes'): {Period('1993-01', 'M'): 0, 
    Period('1993-02', 'M'): 0, 
    Period('1993-03', 'M'): 0}, 
('sum', 'N.A.'): {Period('1993-01', 'M'): nan, 
    Period('1993-02', 'M'): nan, 
    Period('1993-03', 'M'): nan}, 
('sum', 'No'): {Period('1993-01', 'M'): 6.5820000000000007, 
    Period('1993-02', 'M'): 131.1865, 
    Period('1993-03', 'M'): 133.31049999999999}, 
('sum', 'Yes'): {Period('1993-01', 'M'): nan, 
    Period('1993-02', 'M'): nan, 
    Period('1993-03', 'M'): nan}} 

df1 = pd.DataFrame(dic1) 

df1.to_timestamp(how='end').groupby(pd.TimeGrouper('A')).agg(
{'count':['max', 'min', 'median', 'last'] , 
'sum':['mean', 'max' , 'last']}) 

error: KeyError: 'sum' 

enter image description here

Répondre

1

Vous pouvez aplatir la colonne multiindice avant le regroupement:

df1 = pd.DataFrame(dic1) 
df2 = df1.to_timestamp(how='end') 
df2 = df2.rename_axis(['operation', 'YN'], axis=1) 
df3 = df2.stack(level='YN').reset_index('YN') 
# operation  YN count  sum 
# 1993-01-31 N.A.  0  NaN 
# 1993-01-31 No  1 6.5820 
# 1993-01-31 Yes  0  NaN 
# 1993-02-28 N.A.  0  NaN 
# 1993-02-28 No  1 131.1865 
# 1993-02-28 Yes  0  NaN 
# 1993-03-31 N.A.  0  NaN 
# 1993-03-31 No  1 133.3105 
# 1993-03-31 Yes  0  NaN 

Une fois que vous avez déplacé la colonne YN dans niveau dex dans une colonne (en appelant stack/reset_index), vous pouvez aborder le problème de la manière habituelle:


import numpy as np 
import pandas as pd 
Period = pd.Period 
nan = np.nan 

dic1 = {('count', 'N.A.'): {Period('1993-01', 'M'): 0, Period('1993-02', 'M'): 0, Period('1993-03', 'M'): 0}, ('count', 'No'): {Period('1993-01', 'M'): 1, Period('1993-02', 'M'): 1, Period('1993-03', 'M'): 1}, ('count', 'Yes'): {Period('1993-01', 'M'): 0, Period('1993-02', 'M'): 0, Period('1993-03', 'M'): 0}, ('sum', 'N.A.'): {Period('1993-01', 'M'): nan, Period('1993-02', 'M'): nan, Period('1993-03', 'M'): nan}, ('sum', 'No'): {Period('1993-01', 'M'): 6.5820000000000007, Period('1993-02', 'M'): 131.1865, Period('1993-03', 'M'): 133.31049999999999}, ('sum', 'Yes'): {Period('1993-01', 'M'): nan, Period('1993-02', 'M'): nan, Period('1993-03', 'M'): nan}} 

df1 = pd.DataFrame(dic1) 
df2 = df1.to_timestamp(how='end') 
df2 = df2.rename_axis(['operation', 'YN'], axis=1) 
df3 = df2.stack(level='YN').reset_index('YN') 

grouped = df3.groupby([pd.TimeGrouper('A'), 'YN']) 
result = grouped.agg(
    {'count':['max', 'min', 'median', 'last'], 'sum':['mean', 'max' , 'last']}) 
result = result.unstack('YN') 
print(result) 

rendements

  sum              count \ 
      mean     max    last     max 
YN   N.A.   No Yes N.A.  No Yes N.A.  No Yes N.A. 
1993-12-31 NaN 90.359667 NaN NaN 133.3105 NaN NaN 133.3105 NaN  0 

      ...            
      ...  min  median  last   
YN   ... Yes N.A. No Yes N.A. No Yes N.A. No Yes 
1993-12-31 ... 0 0 1 0  0 1 0 0 1 0 
+0

Merci! 'reset_index (-1)' est pour faire des pandas répéter les dates ou il a d'autres fonctions? – Roo

+0

[ 'reset_index'] (https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.reset_index.html) déplace l'index (ou, dans le cas d'un multiindice, un niveau ou des niveaux du MultiIndex) aux colonnes du DataFrame. 'reset_index (-1)' déplace le dernier niveau de MultiIndex dans une colonne. Dans ce cas, il déplace le niveau d'index 'YN' dans une nouvelle colonne du même nom. 'reset_index (-1)' est utile lorsque le dernier niveau n'a pas de nom. Ici, j'aurais dû utiliser 'reset_index ('YN')' car c'est plus descriptif. – unutbu

+0

[pile] (https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.stack.html) déplace l'index de colonne (ou le niveau (s) d'une colonne multiindice) de l'index de ligne . Ensemble, 'stack' suivi de' reset_index' déplace un niveau de l'index de la colonne dans une nouvelle colonne DataFrame. – unutbu

2

Une sorte de façon hacky de le faire est de retirer tous les compter et colonnes somme respectivement:

In [11]: agg_dict = {col: ['mean', 'max' , 'median', 'last'] for col in df1.columns[df1.columns.get_level_values(0) == "count"]} 

In [12]: agg_dict.update({col: ['mean', 'max' , 'last'] for col in df1.columns[df1.columns.get_level_values(0) == "sum"]}) 

In [13]: g = df1.to_timestamp(how='end').groupby(pd.TimeGrouper('A')) 

In [14]: g.agg(agg_dict) 
Out[14]: 
      sum              count 
      N.A.     No      Yes   N.A.     No     Yes 
      mean max last  mean  max  last mean max last mean max median last mean max median last mean max median last 
1993-12-31 NaN NaN NaN 90.359667 133.3105 133.3105 NaN NaN NaN  0 0  0 0 1 1  1 1 0 0  0 0 
+0

solution Nice, merci @ Andy-hayden – Roo