2016-04-06 19 views
5

Mam ramkę danych pogrupowaną według identyfikatora. Istnieje wiele grup, a każda grupa ma zmienną liczbę wierszy. Pierwsze trzy wiersze wszystkich grup nie zawierają interesujących danych. Chciałbym "zwinąć" pierwsze trzy wiersze w każdej grupie, tworząc pojedynczy wiersz w następujący sposób:Pandy: Zwiń pierwsze n wierszy w każdej grupie według agregacji.

"id", a "typ" pozostanie taki sam w nowym "zwiniętym" wierszu.
„grp_idx” zostanie zmieniona na „0”, gdy agregacja pierwszych trzech wierszach występuje
col_1 będzie suma pierwszych trzech rzędach
col_2 będzie suma pierwszych trzech rzędach
do „flag” w wierszu "zwiniętym" będzie 0, jeśli wszystkie wartości wynoszą 0 w pierwszych 3 wierszach. "flaga" będzie miała wartość 1, jeśli jest 1 w jednym z pierwszych trzech wierszy. (Prosta suma wystarczy dla tej logiki, ponieważ flaga jest ustawiona tylko w jednym wierszu dla każdego)

Oto przykład tego, co dataframe wygląda następująco:

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 

Po przetworzeniu Spodziewam ramka danych wygląda następująco:

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 

Nie jestem pewien, jak postępować. Starałem się bawić z

df.groupby ('id'). Głowy (3) .sum()

ale to nie robi to, czego potrzebuję. Każda pomoc, sugestie, fragment kodu będą naprawdę doceniane.

Odpowiedz

2

można uruchomić poprzez ustawienie grp_idx:

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

Teraz id i grp_idx tworzyć ugrupowania chcesz:

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 

Przypuszczałem typ nie może być różny dla tego samego identyfikatora, jak nie zrobił nie podają żadnych warunków dla tej kolumny. Przyjąłem również, że df jest sortowane według id. Jeśli nie, możesz najpierw posortować go na grp_idx, aby był poprawny.

+0

Niesamowite !! Nigdy bym tego nie wymyślił sam. Dziękuję za poświęcenie czasu na pomoc. – Learner

+0

Nie ma za co. To było miłe ćwiczenie. – ayhan

2

starałem się bawić z

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

Po wywołaniu groupby(), trzeba aggregate() w celu połączenia w sposób chcesz. Spróbuj czegoś takiego:

# 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]) 

Zobacz here o wiele więcej informacji na ubiegać-łączenie podzielonego podejścia.

+0

Dzięki Zachary! Technika, którą nakreśliłeś, jest naprawdę przyjemna. Coś, co dodam do mojej skąpej wiedzy. Twoja sugestia z pewnością może pomóc w osiągnięciu tego, co jest potrzebne. Muszę porzucić pierwsze trzy rzędy. Jeszcze raz dziękuję za podzielenie się swoją wiedzą. – Learner

Powiązane problemy