Ein weiterer Methode ist die Verwendung von pipe()
um das Indizieren des Index von BoolCol
zu verketten. In Bezug auf die Leistung ist es genauso effizient wie das kanonische Indizieren mit []
.1
df['BoolCol'].pipe(lambda x: x.index[x])
Dies ist besonders nützlich, wenn BoolCol
tatsächlich das Ergebnis mehrerer Vergleiche ist und Sie die Methodenverknüpfung verwenden möchten, um alle Methoden in einer Pipeline zu platzieren.
Zum Beispiel, wenn Sie die Zeilenindizes erhalten möchten, bei denen der Wert von NumCol
größer als 0,5 ist, der Wert von BoolCol
True ist und das Produkt aus den Werten von NumCol
und BoolCol
größer als 0 ist, können Sie dies tun, indem Sie einen Ausdruck über eval()
evaluieren und dann pipe()
auf das Ergebnis aufrufen, um das Indizieren der Indizes durchzuführen.2
df.eval("NumCol > 0.5 and BoolCol and NumCol * BoolCol >0").pipe(lambda x: x.index[x])
1: Der folgende Benchmark verwendete ein DataFrame mit 20 Mio. Zeilen (im Durchschnitt wurden die Hälfte der Zeilen gefiltert) und holte ihre Indizes ab. Die Methodenverknüpfung über pipe()
funktioniert im Vergleich zu anderen effizienten Optionen sehr gut.
n = 20_000_000
df = pd.DataFrame({'NumCol': np.random.rand(n).astype('float16'),
'BoolCol': np.random.default_rng().choice([True, False], size=n)})
%timeit df.index[df['BoolCol']]
# 181 ms ± 2.47 ms pro Durchlauf (Mittelwert ± Standardabweichung von 10 Durchläufen, 1000 Schleifen pro Durchlauf)
%timeit df['BoolCol'].pipe(lambda x: x.index[x])
# 181 ms ± 1.08 ms pro Durchlauf (Mittelwert ± Standardabweichung von 10 Durchläufen, 1000 Schleifen pro Durchlauf)
%timeit df['BoolCol'].loc[lambda x: x].index
# 297 ms ± 7.15 ms pro Durchlauf (Mittelwert ± Standardabweichung von 10 Durchläufen, 1000 Schleifen pro Durchlauf)
2: Für ein 20 Mio. Zeilen DataFrame, das auf die gleiche Weise wie im 1 konstruiert wurde, werden Sie feststellen, dass die hier vorgeschlagene Methode die schnellste Option ist. Sie funktioniert besser als die Bit-Operator-Verkettung, weil eval()
aufgrund seiner Struktur mehrere Operationen schneller auf einem großen DataFrame durchführt als vektorisierte Python-Operationen und speichereffizienter als query()
ist, weil im Gegensatz zu query()
, eval().pipe(...)
keine Kopie des geschnittenen DataFrames erstellen muss, um dessen Index zu erhalten.