2016-04-06 2 views
5

Ho un dataframe che è raggruppato per id. Ci sono molti gruppi e ogni gruppo ha un numero variabile di righe. Le prime tre righe di tutti i gruppi non contengono dati interessanti. Vorrei "comprimere" le prime tre righe di ciascun gruppo per formare una singola riga nel modo seguente:Panda: Comprimi prima n righe in ogni gruppo per aggregazione

"id" e "tipo" rimarranno gli stessi nella nuova riga "compresso".
'grp_idx' sarà rinominato "0" quando l'aggregazione delle prime tre righe verifica
col_1 sarà la somma delle prime tre righe
col_2 sarà la somma delle prime tre righe
Il 'bandiera' nella riga "compresso" sarà 0 se i valori sono tutti 0 nelle prime 3 righe. 'flag' sarà 1 se è 1 in una delle prime tre righe. (Un semplice somma sarà sufficiente per questa logica, dal momento che il flag è impostato solo in una riga per tutti i gruppi)

Ecco un esempio di ciò che il dataframe assomiglia:

import pandas as pd 
import numpy as np 
df = pd.DataFrame.from_items([ 
    ('id', [283,283,283,283,283,283,283,756,756,756]), 
    ('type', ['A','A','A','A','A','A','A','X','X','X']), 
    ('grp_idx', [1,2,3,4,5,6,7,1,2,3]), 
    ('col_1', [2,4,6,8,10,12,14,5,10,15]), 
    ('col_2', [3,6,9,12,15,18,21,1,2,3]), 
    ('flag', [0,0,0,0,0,0,1,0,0,1]), 
    ]); 
print(df) 

    id type grp_idx col_1 col_2 flag 
0 283 A  1  2  3  0 
1 283 A  2  4  6  0 
2 283 A  3  6  9  0 
3 283 A  4  8  12  0 
4 283 A  5  10  15  0 
5 283 A  6  12  18  0 
6 283 A  7  14  21  1 
7 756 X  1  5  1  0 
8 756 X  2  10  2  0 
9 756 X  3  15  3  1 

Dopo l'elaborazione, mi aspetto il dataframe a forma di:

ID Type grp_idx col_1 col_2 flag 
283 A   0  12  18  0 
283 A   4  8  12  0 
283 A   5  10  15  0 
283 A   6  12  18  0 
283 A   7  14  21  1 
756 X   0  30  6  1 

Non so come procedere. Stavo cercando di giocare con

df.groupby ('id'). Testa (3) .sum()

ma questo non sta facendo quello che mi serve. Qualsiasi aiuto, suggerimento, frammento di codice sarebbe molto apprezzato.

risposta

2

È possibile avviare impostando la grp_idx:

df["grp_idx"] = np.where(df.groupby("id").cumcount()<3, 0, df["grp_idx"]) 

Ora id e grp_idx creare il si raggruppamento desidera:

df.groupby(["id", "type", "grp_idx"]).sum().reset_index() 

    id type grp_idx col_1 col_2 flag 
0 283 A  0  12  18  0 
1 283 A  4  8  12  0 
2 283 A  5  10  15  0 
3 283 A  6  12  18  0 
4 283 A  7  14  21  1 
5 756 X  0  30  6  1 

ho assunto il tipo non può essere diverso per lo stesso ID come si didn non dare alcuna condizione per quella colonna Ho anche dato per scontato che il df sia ordinato per id. In caso contrario, è possibile prima ordinarlo per grp_idx per essere corretto.

+0

Fantastico !! Non l'avrei mai capito da solo. Grazie per aver dedicato del tempo per dare una mano. – Learner

+0

Prego. E 'stato un bel esercizio. – ayhan

2

stavo cercando di giocare con

df.groupby('id').head(3).sum() 

Dopo aver chiamato groupby(), è necessario aggregate() al fine di combinare nel modo desiderato. Provare qualcosa di simile:

# function to sum the first 3 rows 
def head_sum(x): 
    return x.head(3).sum() 

# function to get max of first 3 rows 
def head_max(x): 
    return x.head(3).max() 

# We can use a dictionary in `aggregate()` to call a 
# specific function for each column in the groupby 
column_funcs = {'col_1': head_sum, 
       'col_2': head_sum, 
       'flag': head_max, 
       'id': max, # all the vals should be the same 
       'type': max} # are the 'id' and 'type' always matched? 
collapsed = df.groupby('id').aggregate(column_funcs) 
collapsed['grp_idx'] = 0 

new_df = pd.concat([df, collapsed]) 

Vedi here per molto di più informazioni sul-apply-combinare diviso approccio.

+0

Grazie Zachary! La tecnica che hai delineato è davvero carina. Qualcosa che aggiungerò alla mia scarsa conoscenza. Il tuo suggerimento certamente può funzionare per realizzare ciò che è necessario. Devo solo eliminare le prime tre righe. Grazie ancora per aver condiviso la tua conoscenza. – Learner