2016-01-26 45 views
5

Ho un dataframe in cui sto cercando di raggruppare e quindi partizionare i valori all'interno di un gruppo in più colonne.Pandas groupby risultato in più colonne

Per esempio: dire che ho il seguente dataframe:

>>> import pandas as pd 
>>> import numpy as np 
>>> df=pd.DataFrame() 
>>> df['Group']=['A','C','B','A','C','C'] 
>>> df['ID']=[1,2,3,4,5,6] 
>>> df['Value']=np.random.randint(1,100,6) 
>>> df 
    Group ID Value 
0  A 1  66 
1  C 2  2 
2  B 3  98 
3  A 4  90 
4  C 5  85 
5  C 6  38 
>>> 

voglio GroupBy campo "Gruppo", ottenere la somma del campo "Valore", e ottenere nuovi campi, ognuno dei quali contiene i valori ID del gruppo.

Attualmente sono in grado di fare questo nel modo seguente, ma cerco di una metodologia più pulito:

In primo luogo, creo un dataframe con un elenco degli ID di ciascun gruppo.

>>> g=df.groupby('Group') 
>>> result=g.agg({'Value':np.sum, 'ID':lambda x:x.tolist()}) 
>>> result 
       ID Value 
Group     
A   [1, 4]  98 
B   [3]  76 
C  [2, 5, 6] 204 
>>> 

E quindi uso pd.Series per dividerli in colonne, rinominarli e quindi unirli di nuovo.

>>> id_df=result.ID.apply(lambda x:pd.Series(x)) 
>>> id_cols=['ID'+str(x) for x in range(1,len(id_df.columns)+1)] 
>>> id_df.columns=id_cols 
>>> 
>>> result.join(id_df)[id_cols+['Value']] 
     ID1 ID2 ID3 Value 
Group      
A  1 4 NaN  98 
B  3 NaN NaN  76 
C  2 5 6 204 
>>> 

C'è un modo per farlo senza dover prima creare l'elenco di valori?

risposta

8

Si potrebbe utilizzare

id_df = grouped['ID'].apply(lambda x: pd.Series(x.values)).unstack() 

per creare id_df senza l'intermedio result dataframe.


import pandas as pd 
import numpy as np 
np.random.seed(2016) 

df = pd.DataFrame({'Group': ['A', 'C', 'B', 'A', 'C', 'C'], 
        'ID': [1, 2, 3, 4, 5, 6], 
        'Value': np.random.randint(1, 100, 6)}) 

grouped = df.groupby('Group') 
values = grouped['Value'].agg('sum') 
id_df = grouped['ID'].apply(lambda x: pd.Series(x.values)).unstack() 
id_df = id_df.rename(columns={i: 'ID{}'.format(i + 1) for i in range(len(id_df))}) 
result = pd.concat([id_df, values], axis=1) 
print(result) 

rendimenti

 ID1 ID2 ID3 Value 
Group      
A  1 4 NaN  77 
B  3 NaN NaN  84 
C  2 5 6  86 
0

Uso get_dummies e MultiLabelBinarizer (scikit-learn):

import pandas as pd 
import numpy as np 
from sklearn import preprocessing 
df = pd.DataFrame() 
df['Group']=['A','C','B','A','C','C'] 
df['ID']=[1,2,3,4,5,6] 
df['Value']=np.random.randint(1,100,6) 

mlb = preprocessing.MultiLabelBinarizer(classes=classes).fit([]) 

df2 = pd.get_dummies(df, '', '', columns=['ID']).groupby(by='Group').sum() 
df3 = pd.DataFrame(mlb.inverse_transform(df2[df['ID'].unique()].values), index=df2.index) 
df3.columns = ['ID' + str(x + 1) for x in range(df3.shape[0])] 
pd.concat([df3, df2['Value']], axis=1) 


     ID1 ID2 ID3 Value 
Group      
A  1 4 NaN  63 
B  3 NaN NaN  59 
C  2 5 6 230 
Problemi correlati