Polars, der in Rust geschriebene Pandas-Herausforderer, sorgt für erhebliche Beschleunigung nicht nur in der Ausführung des Codes, sondern auch in der Entwicklung. Pandas krankt seit jeher an einer API, die an vielen Stellen „historisch gewachsen“ ist. Ganz anders Polars: Eine API, die von Anfang an auf logische Konsistenz ausgelegt ist und deren Stringenz mit jedem Release sorgfältig gepflegt wird (im Zweifelsfall auch unter Verlusten an Rückwärtskompatibilität), sorgt für eine erheblich schnellere Entwicklung. An vielen Stellen, wo man bisher Pandas eingesetzt hat, kann man es problem los durch Polars ersetzen: In Ibis-Analytics-Projekten, und natürlich einfach für die tägliche Datenaufbereitung aller Art. Gut macht sich die überlegene Performance auch in interaktiven Umfeldern wie PowerBI .
Table of Contents
Polars-Plugins: eine unterschätzte Ressource
Obwohl Polars noch ein junges Projekt ist, gibt es bereits erste Ansätze zu einem Ökosystem an Plugins. Eines davon ist besonders nützlich in einer Situation, in der ich beispielsweise zu einem Dataframe mit geographischen Positionen von U-Bahn-Haltestellen jeweils alle Bushaltestellen (in einem zweiten Dataframe) finden möchte, die höchstens 500m entfernt sind. So etwas führt zu einem kartesischen Produkt (Cross Join) zwischen den beiden Dataframes, das ich anschließend mit Hilfe der Abstände zwischen U-Bahn- und Bushaltestellen filtern muss.
Kartesische Produkte werden selbst dann sehr groß, wenn die beteiligten Dataframes recht moderate Größen haben. Darum ist es wichtig, den anschließenden Filterschritt, der typischerweise den allergrößten Teil dieser Datenflut verwirft, sehr performant durchführen zu können. Wir brauchen also eine schnelle Berechnung des geographischen Abstands zwischen zwei Punkten. Uns reicht der sogenannte Haversine-Abstand, eine Näherungsformel für den Luftlinienabstand zwischen zwei Punkten auf der Erde. Die Formel tut so, als wäre die Erde eine Kugel. In Wahrheit ist sie nicht ganz kugelförmig, sondern an den Polen abgeplattet und überhaupt etwas kartoffelähnlich unregelmäßig. Für die meisten Zwecke ist diese Näherung aber genau genug. Und natürlich gibt es in Python Packages dafür. Nur leider ist die Berechnung furchtbar langsam, wenn man sich damit durch ein kartesisches Produkt quält.
Polars-distance rettet den Tag
Glücklicherweise gibt es das Polars-Plugin polars-distance von Ion Koutsouris, das diese Funktion in Rust implementiert und von Polars aus direkt zugänglich macht. Gegenüber einer Python-Implementation verbessert das die Performance enorm. Konkret: Ich hatte neulich die Aufgabe, zu jedem der über 8.000 Postleitzahlgebiete in Deutschland alle anderen Postleitzahlgebiete zu finden, deren Mittelpunkt höchstens eine gewisse Maximalanzahl an Kilometern entfernt ist. Zunächst versuchte ich die Python-Variante (mit einer zugegeben etwas genaueren und aufwendigeren Näherung der Entfernung, der geodesic-Funktion aus geopy). Nach 20 Minuten brach ich die Ausführung ab, weil ich keine Lust mehr hatte zu warten. Mit polars-distance dagegen war das Ganze nach zwei Sekunden (!) erledigt. Abbildung 1 zeigt ein Beispiel für ein Ergebnis, in diesem Fall alle Postleitzahlgebiete (gelb), die höchstens 30 km von der Bremer Innenstadt (PLZ-Gebiet 28203, der kleine orange Fleck in der Mitte) entfernt sind.
Zeit für etwas Code
Wie sieht der Join für das Postleitzahlenbeispiel konkret aus? Nehmen wir mal an, dass unsere Postleitzahlengebiete in einem Polars-Dataframe „postcode2center“, der eine String-Spalte („postcode“) mit der Postleitzahl hat und eine Spalte „center“, die Längen- und Breitengrad des Mittelpunkts des Postleitzahlgebiets enthält.
Die Spalte „center“ ist ein Polars-Struct mit zwei Float64-Feldern, nämlich „latitude“ und „longitude“. Der Maximalabstand, den wir zu akzeptieren gewillt sind, steht in der Variablen „radius_km“.
Ganz am Anfang („.lazy()“) und ganz am Ende („.collect(streaming=True)“) benutzen wir ein weiteres Polars-Feature, das bei Pandas fehlt: die lazy API. Sie sorgt hier dafür, dass uns der Prozess selbst dann nicht um die Ohren fliegt, wenn unser Hauptspeicher für die über 64 Millionen Zeilen des kartesischen Produkts ein wenig zu klein sein sollte. Der Einsatz von polars-distance (das wir hier als pld importiert haben) ist dann schnell erledigt in der Zeile, die mit „.with_columns“ anfängt. Dort wird eine neue Spalte mit dem Namen „distance_km“ erzeugt, nach der wir in der nächsten Zeile filtern. Man hätte das auch in einen Befehl packen können, aber so ist es lesbarer. Am Schluss erhalten wir einen Dataframe mit der Stringspalte „postcode“ und einer Spalte „postcodes_within_radius“, die die Postleitzahlgebiete in der Umgebung als Liste von Strings enthält.
Polars-distance: nicht nur für Geodaten
Das Plugin ist aber nicht nur für Geodaten nützlich. Auch wenn man zum Beispiel in einer Liste von Freitextfeldern alle Felder mit ähnlicher Schreibweise finden will, hat man dasselbe Problem: Man muss ein kartesisches Produkt schnell mit Hilfe eines Abstandsbegriffs filtern. polars-distance bietet hier den Levenshtein-Abstand an, der für solche Textoperationen erfunden wurde, sowie diverse Variationen davon. Auch Abstandsbegriffe für Listen bringt polars-distance mit. Die vollständige Liste findet sich in der Dokumentation. Also: Wenn ihr mal wieder ein Bedürfnis nach Abstand verspürt, schaut mal, ob euch polars-distance weiterhelfen kann! Und wenn ihr Fragen habt rund um den Übergang von Pandas zu Polars in eurem Unternehmen, sprecht uns gern an.
Wer ist b.telligent?
Du willst den IoT Core durch eine Multi-Cloud-Lösung ersetzen und die Vorteile weiterer IoT-Services von Azure oder Amazon Web Services nutzen? Dann melde Dich bei uns und wir unterstützen Dich bei der Umsetzung mit unserer Expertise und dem b.telligent Partnernetzwerk.
Neuronale Netze werden erfolgreich auf so ziemlich jeden Datentyp angewandt: Bilder, Audio, Texte, Videos, Graphen usw. Nur wenn es um Tabellendaten geht, sind baumbasierte Ensembles wie Random Forests und Gradient Boosted Trees immer noch sehr viel verbreiteter. Wenn man diese erfolgreichen Klassiker durch neuronale Netze ersetzen will, dürfte Ensemble Learning immer noch eine Schlüsselidee sein. Dieser Blogbeitrag erklärt, warum das so ist. Dazu gibt’s ein Notebook mit den praktischen Details.
Azure AI Search, Microsofts serverloses Angebot für das R in RAG, hat seine eigene Skalierungslogik. Sie verbirgt viel von der Komplexität serverbasierter Lösungen, erfordert aber spezifische Kenntnisse.
Machine Learning Operations (MLOps) sind eine Praxis für die Zusammenarbeit und Kommunikation zwischen Datenwissenschaftler:innen und Betriebsexpert:innen, um die Lebenszyklen von Machine Learning (ML) in der Produktion zu verwalten. Dabei werden die Grundsätze von DevOps in den ML-Lebenszyklus einbezogen, um den Prozess von der Modellentwicklung bis zur Bereitstellung und Überwachung zu rationalisieren und zu automatisieren. Ziel von MLOps ist es, ML-Modelle auf strukturierte und effiziente Art und Weise schneller bereitzustellen und zu skalieren.