Statt groupby/count
zu verwenden, verwenden groupby/transform/count
eine Serie zu bilden, die die gleiche Länge wie das ursprüngliche Datenrahmen ist df
:
c = df.groupby(keys)['z'].transform('count')
Dann können Sie eine boolean Maske bilden, die die gleiche Länge hat als df
:
In [35]: c<N
Out[35]:
0 False
1 False
2 False
3 True
4 True
5 False
6 False
7 False
Name: ok, dtype: bool
Zuordnung zu 01.230.geht viel glatter nun, ohne eine Schleife, Abfrage oder Unterindexierungs:
df['ok'] = c >= N
import pandas as pd
df = pd.DataFrame([
[1, 2, 1],
[1, 2, 2],
[1, 2, 3],
[2, 3, 1],
[2, 3, 2],
[4, 5, 1],
[4, 5, 2],
[4, 5, 3],
], columns=['x', 'y', 'z'])
keys = ['x', 'y']
N = 3
c = df.groupby(keys)['z'].transform('count')
df['ok'] = c >= N
print(df)
Ausbeuten
x y z ok
0 1 2 1 True
1 1 2 2 True
2 1 2 3 True
3 2 3 1 False
4 2 3 2 False
5 4 5 1 True
6 4 5 2 True
7 4 5 3 True
Da die builtin groupby/transform
methods (wie transform('count')
) sind Cythonized sie sind im Allgemeinen schneller als Aufruf groupby/transform
mit einer benutzerdefinierten Lambda-Funktion. So , Berechnen der ok
Spalte in zwei Schritten
c = df.groupby(keys)['z'].transform('count')
df['ok'] = c >= N
Verwendung schneller als
df.assign(ok=df.groupby(keys)['z'].transform(lambda x: x.size >= N))
Zusätzlich vektorisierten Operationen über eine gesamte Spalte (wie c >= N
) sind schneller als mehrere Operationen über Untergruppen. transform(lambda x: x.size >= N))
führt den Vergleich x.size >= N
einmal für jede Gruppe durch. Wenn viele Gruppen vorhanden sind, führt die Berechnung c >= N
zu einer Leistungsverbesserung.
Zum Beispiel mit diesem 1000-Reihe Datenrahmen:
import numpy as np
import pandas as pd
np.random.seed(2017)
df = pd.DataFrame(np.random.randint(10, size=(1000, 3)), columns=['x', 'y', 'z'])
keys = ['x', 'y']
N = 3
transform('count')
verwenden, sind etwa 12-fach schneller:
In [37]: %%timeit
....: c = df.groupby(keys)['z'].transform('count')
....: df['ok'] = c >= N
1000 loops, best of 3: 1.69 ms per loop
In [38]: %timeit df.assign(ok=df.groupby(keys)['z'].transform(lambda x: x.size >= N))
1 loop, best of 3: 20.2 ms per loop
In [39]: 20.2/1.69
Out[39]: 11.95266272189349
Im Beispiel oben gab es 100 Gruppen:
In [47]: df.groupby(keys).ngroups
Out[47]: 100
Der Geschwindigkeitsvorteil der Verwendung von transform('count')
nimmt zu, wenn die Anzahl der Gruppen zunimmt.Zum Beispiel mit 955 Gruppen:
In [48]: np.random.seed(2017); df = pd.DataFrame(np.random.randint(100, size=(1000, 3)), columns=['x', 'y', 'z'])
In [51]: df.groupby(keys).ngroups
Out[51]: 955
die transform('count')
Methode führt zu 92x schneller:
In [49]: %%timeit
....: c = df.groupby(keys)['z'].transform('count')
....: df['ok'] = c >= N
1000 loops, best of 3: 1.88 ms per loop
In [50]: %timeit df.assign(ok=df.groupby(keys)['z'].transform(lambda x: x.size >= N))
10 loops, best of 3: 173 ms per loop
In [52]: 173/1.88
Out[52]: 92.02127659574468
Großen und Details beantworten - danke! – lazy1