Start Nachrichten Warum Sie aufhören sollten, Schleifen in Pandas zu schreiben

Warum Sie aufhören sollten, Schleifen in Pandas zu schreiben

2
0
Warum Sie aufhören sollten, Schleifen in Pandas zu schreiben

: Als ich anfing, Pandas zu verwenden, habe ich ständig Schleifen wie diese geschrieben:

for i in range(len(df)):
if df.loc(i, "sales") > 1000:
df.loc(i, "tier") = "high"
else:
df.loc(i, "tier") = "low"

Es hat funktioniert. Und ich dachte, „Hey, das ist doch in Ordnung, oder?“
Es stellt sich heraus … nicht so sehr.

Ich wusste es damals noch nicht, aber Loops wie dieser sind eine klassische Anfängerfalle. Sie bringen Pandas dazu, viel mehr Arbeit zu erledigen, als nötig ist, und sie schleichen sich ein mentales Modell ein, das Sie dazu bringt, Zeile für Zeile statt Spalte für Spalte zu denken.

Sobald ich angefangen habe, nachzudenken Spaltendie Dinge haben sich geändert. Der Code wurde kürzer. Die Ausführung wurde schneller. Und plötzlich hatte Pandas das Gefühl, dass es tatsächlich dafür gebaut wurde Hilf mirbremst mich nicht.

Um dies zu zeigen, verwenden wir einen kleinen Datensatz, auf den wir durchgehend verweisen:

import pandas as pd
df = pd.DataFrame({
"product": ("A", "B", "C", "D", "E"),
"sales": (500, 1200, 800, 2000, 300)
})

Ausgabe:

product sales
0 A 500
1 B 1200
2 C 800
3 D 2000
4 E 300

Unser Ziel ist einfach: Beschriften Sie jede Zeile als high wenn der Umsatz größer als 1000 ist, andernfalls low.

Ich zeige Ihnen, wie ich es gemacht habe anfangsund warum es einen besseren Weg gibt.

Der Loop-Ansatz, mit dem ich angefangen habe

Hier ist die Schleife, die ich beim Lernen verwendet habe:

for i in range(len(df)):
if df.loc(i, "sales") > 1000:
df.loc(i, "tier") = "high"
else:
df.loc(i, "tier") = "low"
print(df)

Es ergibt dieses Ergebnis:

product sales tier
0 A 500 low
1 B 1200 high
2 C 800 low
3 D 2000 high
4 E 300 low

Und ja, es funktioniert. Aber Folgendes habe ich auf die harte Tour gelernt:
Pandas macht es eine kleine Operation für jede Zeileanstatt die gesamte Spalte auf einmal effizient zu bearbeiten.

Dieser Ansatz lässt sich nicht skalieren – was sich bei 5 Zeilen gut anfühlt, wird bei 50.000 Zeilen langsamer.

Noch wichtiger ist, dass Sie Zeile für Zeile wie ein Anfänger denken können und nicht wie ein professioneller Pandas-Benutzer.

Timing der Schleife (in dem Moment, als mir klar wurde, dass sie langsam war)

Als ich meine Schleife zum ersten Mal mit diesem winzigen Datensatz durchführte, dachte ich: „Kein Problem, es ist schnell genug.“ Aber dann fragte ich mich … was wäre, wenn ich einen größeren Datensatz hätte?

Also ich habe es versucht:

import pandas as pd
import time
# Make a bigger dataset
df_big = pd.DataFrame({
"product": ("A", "B", "C", "D", "E") * 100_000,
"sales": (500, 1200, 800, 2000, 300) * 100_000
})

# Time the loop
start = time.time()
for i in range(len(df_big)):
if df_big.loc(i, "sales") > 1000:
df_big.loc(i, "tier") = "high"
else:
df_big.loc(i, "tier") = "low"
end = time.time()
print("Loop time:", end - start)

Folgendes habe ich bekommen:

Loop time: 129.27328729629517

Das ist 129 Sekunden.

Über zwei Minuten nur um Zeilen als zu kennzeichnen "high" oder "low".

In diesem Moment hat es bei mir Klick gemacht. Der Code sei nicht nur „ein wenig ineffizient“ gewesen. Es war im Grunde die falsche Verwendung von Pandas.
Und stellen Sie sich vor, dass dies jeden Tag in einer Datenpipeline, in einer Dashboard-Aktualisierung, in Millionen von Zeilen ausgeführt wird.

Warum es so langsam ist

Die Schleife zwingt Pandas dazu:

  • Greifen Sie auf jede Zeile einzeln zu
  • Führen Sie für jede Iteration eine Logik auf Python-Ebene aus
  • Aktualisieren Sie den DataFrame jeweils zelleweise

Mit anderen Worten: Es verwandelt eine hochoptimierte Spalten-Engine in einen verherrlichten Python-Listenprozessor.

Und dafür ist Pandas nicht gebaut.

Der einzeilige Fix (und der Moment, in dem es Klick machte)

Nach dem Sehen 129 SekundenIch wusste, dass es einen besseren Weg geben musste.
Anstatt also die Zeilen zu durchlaufen, habe ich versucht, die Regel an der Stelle auszudrücken Spaltenebene:

„Wenn der Umsatz > 1000 ist, kennzeichnen Sie ihn als hoch. Andernfalls kennzeichnen Sie ihn als niedrig.“

Das ist es. Das ist die Regel.

Hier ist die vektorisierte Version:

import numpy as np
import time

start = time.time()
df_big("tier") = np.where(df_big("sales") > 1000, "high", "low")
end = time.time()
print("Vectorized time:", end - start)

Und das Ergebnis?

Vectorized time: 0.08

Lassen Sie das auf sich wirken.

Loop-Version: 129 Sekunden
Vektorisierte Version: 0,08 Sekunden

Das ist vorbei 1.600-mal schneller.

Was ist gerade passiert?

Der Hauptunterschied ist folgender:

Die Schleife hat den DataFrame verarbeitet Reihe für Reihe. Die vektorisierte Version verarbeitete das Ganze sales Spalte in einem optimierten Arbeitsgang.

Wenn Sie schreiben:

df_big("sales") > 1000

Pandas prüft die Werte in Python nicht einzeln. Es führt den Vergleich auf einer niedrigeren Ebene (über NumPy) im kompilierten Code über das gesamte Array durch.

Dann np.where() bringt die Etiketten in einem effizienten Durchgang an.

Hier ist die subtile, aber wirkungsvolle Änderung:

Anstatt zu fragen:

„Was soll ich mit dieser Zeile machen?“

Sie fragen:

„Welche Regel gilt für diese Spalte?“

Das ist die Grenze zwischen Anfänger-Pandas und Profi-Pandas.

Zu diesem Zeitpunkt dachte ich, ich hätte ein „Niveau erreicht“. Dann entdeckte ich, dass ich es noch einfacher machen könnte.

Und dann entdeckte ich die Boolesche Indizierung

Nachdem ich die vektorisierte Version zeitlich festgelegt hatte, war ich ziemlich stolz. Aber dann hatte ich eine andere Erkenntnis.

Ich brauche es nicht einmal np.where() dafür.

Kehren wir zu unserem kleinen Datensatz zurück:

df = pd.DataFrame({
"product": ("A", "B", "C", "D", "E"),
"sales": (500, 1200, 800, 2000, 300)
})

Unser Ziel ist immer noch dasselbe:

Beschriften Sie jede Zeile high wenn Verkäufe > 1000, sonst low.

Mit np.where() wir haben geschrieben:

df("tier") = np.where(df("sales") > 1000, "high", "low")

Es ist sauberer und schneller. Viel besser als eine Schleife.

Aber hier ist der Teil, der meine Einstellung zu Pandas wirklich verändert hat:
Diese Zeile hier…

df("sales") > 1000

…gibt bereits etwas unglaublich Nützliches zurück.

Schauen wir es uns an:

Ausgabe:

0 False
1 True
2 False
3 True
4 False
Name: sales, dtype: bool

Das ist eine Boolesche Reihe.

Pandas hat gerade die Bedingung für die gesamte Spalte auf einmal ausgewertet.

Keine Schleife. NEIN if. Keine zeilenweise Logik.

Es wurde auf einmal eine vollständige Maske mit Wahr/Falsch-Werten erstellt.

Die boolesche Indizierung fühlt sich wie eine Supermacht an

Jetzt wird es interessant.

Sie können diese boolesche Maske direkt verwenden, um Zeilen zu filtern:

df(df("sales") > 1000)

Und Pandas bietet Ihnen sofort:

Wir können das sogar bauen tier Spalte mit direkter boolescher Indizierung:

df("tier") = "low"
df.loc(df("sales") > 1000, "tier") = "high"

Ich sage im Grunde:

  • Gehe davon aus, dass alles so ist "low".
  • Überschreiben Sie nur die Zeilen, in denen der Umsatz > 1000 ist.

Das ist es.

Und plötzlich denke ich nicht mehr:

„Überprüfen Sie für jede Zeile den Wert…“

Ich denke:

„Beginnen Sie mit einem Standardwert. Wenden Sie dann eine Regel auf eine Teilmenge an.“

Dieser Wandel ist subtil, aber er verändert alles.

Nachdem ich mich mit Booleschen Masken vertraut gemacht hatte, begann ich mich zu fragen:

Was passiert, wenn die Logik nicht so sauber ist wie „größer als 1000“? Was ist, wenn ich benutzerdefinierte Regeln benötige?

Da habe ich es entdeckt apply(). Und zunächst fühlte es sich wie das Beste aus beiden Welten an.

Ist es nicht apply() Gut genug?

Ich werde ehrlich sein. Nachdem ich aufgehört hatte, Loops zu schreiben, dachte ich, ich hätte alles herausgefunden. Denn es gab diese magische Funktion, die alles zu lösen schien:
apply().

Es schien der perfekte Mittelweg zwischen chaotischen Schleifen und gruseliger Vektorisierung zu sein.

Also fing ich natürlich an, Dinge wie diese zu schreiben:

df("tier") = df("sales").apply(
lambda x: "high" if x > 1000 else "low"
)

Und auf den ersten Blick?

Das sieht toll aus.

  • NEIN for Schleife
  • Keine manuelle Indizierung
  • Leicht zu lesen

Es fühlt wie eine professionelle Lösung.

Aber Folgendes habe ich damals nicht verstanden:

apply() führt immer noch Python-Code für jede einzelne Zeile aus.
Es verbirgt nur die Schleife.

Wenn Sie Folgendes verwenden:

df("sales").apply(lambda x: ...)

Pandas ist immer noch:

  • Jeden Wert nehmen
  • Übergabe an eine Python-Funktion
  • Rückgabe des Ergebnisses
  • Wiederholen Sie das für jede Zeile

Es ist sauberer als ein for Schleife, ja. Aber leistungsmäßig? Es kommt einer Schleife viel näher als einer echten Vektorisierung.

Das war für mich so etwas wie ein Weckruf. Mir wurde klar, dass ich sichtbare Schleifen durch unsichtbare ersetzte.

Wann sollten Sie es verwenden? apply()?

  • Wenn die Logik mit vektorisierten Operationen ausgedrückt werden kann → tun Sie das.
  • Wenn es mit booleschen Masken ausgedrückt werden kann → tun Sie das.
  • Wenn unbedingt eine benutzerdefinierte Python-Logik erforderlich ist → dann verwenden apply().
    Mit anderen Worten:

Zuerst vektorisieren. Greifen Sie nach apply()only wenn du musst.
Nicht weil apply() ist schlecht. Sondern weil Pandas am schnellsten und saubersten ist, wenn man in Spalten und nicht in zeilenweisen Funktionen denkt.

Abschluss

Rückblickend war der größte Fehler, den ich gemacht habe, keine Schleifen zu schreiben. Es wurde davon ausgegangen, dass der Code, wenn er funktionierte, gut genug war.

Pandas bestraft Sie nicht sofort dafür, dass Sie in Reihen denken. Aber wenn Ihre Datensätze wachsen, wenn Ihre Pipelines skalieren, wenn Ihr Code in Dashboards und Produktionsworkflows landet, wird der Unterschied deutlich.

  • Das zeilenweise Denken lässt sich nicht skalieren.
  • Versteckte Python-Schleifen lassen sich nicht skalieren.
  • Regeln auf Spaltenebene tun dies.

Das ist die eigentliche Grenze zwischen der Nutzung von Pandas durch Anfänger und Profis.

Zusammenfassend also:

Hören Sie auf, zu fragen, was mit jeder Zeile geschehen soll. Fragen Sie sich, welche Regel für die gesamte Spalte gilt.

Sobald Sie diese Änderung vorgenommen haben, wird Ihr Code schneller, sauberer, einfacher zu überprüfen und einfacher zu warten. Und Sie erkennen sofort ineffiziente Muster, auch Ihre eigenen.

Quelle

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein