Załóżmy, że mam pandy DataFrame w ten sposób:
>>> df = pd.DataFrame({'id':[1,1,1,2,2,2,2,3,4],'value':[1,2,3,1,2,3,4,1,1]})
>>> df
id value
0 1 1
1 1 2
2 1 3
3 2 1
4 2 2
5 2 3
6 2 4
7 3 1
8 4 1
Chcę uzyskać nową ramkę DataFrame z 2 najlepszymi rekordami dla każdego identyfikatora, na przykład:
id value
0 1 1
1 1 2
3 2 1
4 2 2
7 3 1
8 4 1
Mogę to zrobić z numeracją rekordów w ramach grupy po grupie:
>>> dfN = df.groupby('id').apply(lambda x:x['value'].reset_index()).reset_index()
>>> dfN
id level_1 index value
0 1 0 0 1
1 1 1 1 2
2 1 2 2 3
3 2 0 3 1
4 2 1 4 2
5 2 2 5 3
6 2 3 6 4
7 3 0 7 1
8 4 0 8 1
>>> dfN[dfN['level_1'] <= 1][['id', 'value']]
id value
0 1 1
1 1 2
3 2 1
4 2 2
7 3 1
8 4 1
Ale czy istnieje bardziej efektywne / eleganckie podejście do tego? Jest też bardziej eleganckie podejście do rekordów liczbowych w każdej grupie (jak funkcja okna SQL numer_wiersza () ).
python
pandas
greatest-n-per-group
window-functions
top-n
Roman Pekar
źródło
źródło
Odpowiedzi:
Próbowałeś
df.groupby('id').head(2)
Wygenerowano Ouput:
(Pamiętaj, że może być konieczne wcześniejsze uporządkowanie / posortowanie, w zależności od danych)
EDYCJA: Jak wspomniała
df.groupby('id').head(2).reset_index(drop=True)
osoba pytająca , użyj, aby usunąć multindeks i spłaszczyć wyniki.źródło
.reset_index(drop=True)
cumcount
(ponumeruj rekordy w każdej grupie)id
zróbdf.sort_values(['id', 'value'], axis=0).groupby('id').head(2)
. Inny przykład, największą wartość naid
podajedf.sort_values(['id', 'value'], axis=0).groupby('id').tail(1)
.Od wersji 0.14.1 możesz teraz wykonywać
nlargest
insmallest
nagroupby
obiekcie:Jest niewielki niesamowitość, że masz oryginalny indeks również tam, ale to może być bardzo przydatne w zależności od tego, co oryginalny wskaźnik był .
Jeśli nie jesteś tym zainteresowany, możesz to zrobić
.reset_index(level=1, drop=True)
się go całkowicie pozbyć.(Uwaga: od 0.17.1 będziesz mógł to zrobić również w DataFrameGroupBy, ale na razie działa tylko z
Series
iSeriesGroupBy
.)źródło
unique_limit(n)
? Jak chcę, aby pierwsze n unikalnych wartości? Jeśli o to poproszęnlargest
, posortuję cały df, który może być drogidf.groupby([pd.Grouper(freq='M'), 'A'])['B'].count().nlargest(5, 'B')
To po prostu zwraca ogólnąDataFrameGroupBy
s, wydaje się fałszywe, połączone żądanie ściągnięcia wydaje się dodawać tylkonlargest
do prostychDataFrame
s. Co jest raczej niefortunne, bo co jeśli chcesz zaznaczyć więcej niż jedną kolumnę?Czasami sortowanie wszystkich danych z wyprzedzeniem jest bardzo czasochłonne. Możemy najpierw grupować i robić topki dla każdej grupy:
źródło