Pandas-Styling¶
Einführung¶
Reiner Text ist unkompliziert und leicht zu lesen, kann aber manchmal an Betonung und Klarheit fehlen, insbesondere bei komplexen oder umfangreichen Inhalten. Text mit Hervorhebungen, unterschiedlichen Schriftarten und Farben hingegen hilft, die Aufmerksamkeit des Lesers zu lenken, wichtige Punkte hervorzuheben und die Lesbarkeit zu verbessern. Durch visuelle Unterscheidungen wie Fettdruck, Kursivschrift und Farbcodierung können wichtige Informationen besser herausgestellt, das Verständnis gefördert und die Benutzerbindung verbessert werden. Ein übermäßiger Einsatz dieser Elemente kann jedoch zu Unordnung führen und die Lesbarkeit verringern – daher ist Balance entscheidend.
Das war ein Beispiel für einen reinen, sachlichen Stil, wie er häufig in seriösen Lehrbüchern zu finden ist. Im Gegensatz dazu könnte man einen ansprechenderen Stil so gestalten:
Reiner Text ist unkompliziert und leicht zu lesen, kann aber manchmal an Betonung und Klarheit fehlen, insbesondere bei komplexen oder umfangreichen Inhalten.
Andererseits hilft Text mit Hervorhebungen, unterschiedlichen Schriftarten und 🎨 Farben, um die Aufmerksamkeit des Lesers zu lenken, wichtige Punkte hervorzuheben und die Lesbarkeit zu verbessern.
✅ Die Verwendung von Fettdruck, Kursivschrift und 🟢 Farbcodierung kann wichtige Informationen hervorheben, das Verständnis erleichtern und die Nutzerbindung verbessern.
⚠️ Allerdings kann übermäßiger Einsatz dieser Elemente zu Unordnung führen und die Lesbarkeit beeinträchtigen, daher ist Balance entscheidend!
Nun hast du vielleicht schon eine Vorstellung vom Fokus dieses Kapitels in unserem Pandas-Tutorial. Lassen wir den Blick nun auf Python und Pandas richten: Genauso wie wir Texte durch Strukturierung und Hervorhebungen klarer und ansprechender gestalten können, lassen sich diese Prinzipien auch auf ein DataFrame anwenden. So kann man es lesbarer und optisch ansprechender gestalten, ohne die Rohdaten zu verändern.
In der Programmierung – einschließlich der Python-Entwicklung – gilt als grundlegende Best Practice, die Rohdaten (Logik) von ihrer Darstellung (Styling oder Rendering) zu trennen. Dieses Prinzip findet in verschiedenen Bereichen Anwendung, von der Webentwicklung über Data Science bis hin zur Backend-Entwicklung.
In Pandas halten wir uns an dieses Prinzip, indem wir die Rohdaten unabhängig von ihrer Präsentation bewahren. Dadurch bleiben die Daten präzise, rechnerisch nutzbar und jederzeit leicht formatiert, ohne ihre zugrunde liegende Struktur zu verändern.
Warum sollte man Daten von der Präsentation in Pandas trennen?¶
Bewahrt die Datenintegrität
Die zugrunde liegenden numerischen Werte bleiben unverändert, wodurch Rundungsfehler oder Datenkorruption vermieden werden.
Beispiel: Ein Wert bleibt als1234.5678
erhalten, anstatt als formatierter String"1.234,57 EUR"
gespeichert zu werden.Gewährleistet die Berechnungskompatibilität
Operationen wie Summieren, Mittelwertbildung oder statistische Analysen erfordern reine numerische Daten.
Beispiel: Wenn wir"$100.50"
als String speichern, kann Pandas die Gesamtverkäufe nicht korrekt berechnen.Ermöglicht flexible Präsentation
Die Formatierung kann je nach Anwendungsfall dynamisch angewendet werden (Berichte, Dashboards, benutzerspezifische Ansichten).
Beispiel: Anzeige als"50%"
, aber Speicherung als0.5
für Berechnungen.Erhöht die Wartbarkeit
Falls sich die Anzeigeanforderungen ändern (z. B. von USD zu EUR), muss nur die Styling-Logik angepasst werden, nicht die eigentlichen Daten.
Die .style
-Eigenschaft¶
Pandas bietet eine leistungsstarke .style
-Eigenschaft, die es ermöglicht, DataFrames optisch ansprechend zu formatieren und zu gestalten. Dies ist besonders nützlich für Jupyter Notebooks und Berichte.
Die .style
-Eigenschaft von Pandas erlaubt eine dynamische Formatierung und Visualisierung, ohne die Rohdaten zu verändern. Sie verbessert die Lesbarkeit durch Zahlenformatierung, Farbverläufe und Hervorhebungen, während Berechnungen unangetastet bleiben.
Grundlegende Formatierung mit .format
¶
Werfen wir zunächst einen Blick auf die format
-Methode der .style
-Eigenschaft von Pandas. Die format
-Methode wird verwendet, um die Anzeige von DataFrame-Werten anzupassen, ohne die zugrunde liegenden Daten zu verändern.
Das folgende Beispiel zeigt, wie man numerische Werte in einem DataFrame formatiert, indem die Spalte B auf zwei Dezimalstellen beschränkt wird:
import pandas as pd
df = pd.DataFrame({'A': [1, 2, 3], 'B': [4.1234, 5.5678, 6.91011]})
# Formatierung wird angewendet:
# Spalte 'B' mit 2 Nachkommastellen
styled_df = df.style.format({'B': "{:,.2f}"}) styled_df
Weitere Formatierungsmöglichkeiten:
Spezifizierer | Effekt | Beispiel ("{:.2f}".format(123.456) ) |
---|---|---|
.0f |
Rundet auf 0 Dezimalstellen | 123 |
.2f |
Rundet auf 2 Dezimalstellen | 123.46 |
.2% |
Umwandlung in Prozent mit 2 Dezimalstellen | 12345.60% |
.e |
Wissenschaftliche Notation (Kleinbuchstaben) | 1.23e+02 |
.E |
Wissenschaftliche Notation (Großbuchstaben) | 1.23E+02 |
.g |
Allgemeines Format (entfernt unnötige Dezimalstellen) | 123.456 |
.G |
Allgemeines Format (Großbuchstaben-Exponenten falls erforderlich) | 123.456 |
Häufige Anwendungsfälle:
"{:,.2f}"
→ Tausendertrennzeichen + 2 Dezimalstellen (1.234,56
)"{:.1%}"
→ Prozentanzeige (12,3%
)"{:.3e}"
→ Wissenschaftliche Notation (1.235e+02
)
Die Daten bleiben numerisch, werden aber in einer formatierten Weise angezeigt.
Bevor wir ein weiteres Formatierungsbeispiel erkunden, werfen wir zunächst einen Blick auf den falschen Ansatz, um zu verstehen, warum die Vermischung von Logik und Darstellung eine schlechte Praxis ist.
Indem wir diesen Fehler in Aktion sehen, wirst du die Bedeutung der Trennung von Datenverarbeitung und Präsentation besser zu schätzen wissen:
import pandas as pd
df = pd.DataFrame({'Preis': ['1.234,57 €', '9.876,43 €'], 'Rabatt': ['15%', '25%']})
df
Das ist schlecht, weil:
- Die Werte als Strings statt als numerische Typen gespeichert werden.
- Berechnungen wie Summieren, Mittelwertbildung oder Sortieren nicht durchgeführt werden können.
- Die Formatierung (Währungssymbole, Prozentzeichen) mit den Daten vermischt ist, was gegen das Prinzip der Trennung von Daten und Präsentation verstößt.
Nun die korrekte Vorgehensweise mit style.format
:
df = pd.DataFrame({'Preis': [1234.57, 9876.43], 'Rabatt': [0.15, 0.25]})
# Formatierung nur zur Anzeige anwenden (Zahlen bleiben unverändert)
df.style.format({'Preis': '{:,.2f} €', 'Rabatt': '{:.0%}'})
Das ist viel besser:
- Die "Preis"-Spalte bleibt ein Float (z. B.
1234.57
), wird aber als"1.234,57 €"
angezeigt. - Die "Rabatt"-Spalte bleibt ein Float (z. B.
0.15
), wird aber als"15%"
angezeigt.
Hervorheben der maximalen Werte¶
Das folgende Beispiel zeigt, wie man mit highlight_max()
den höchsten Wert in jeder Spalte hervorheben kann, sodass wichtige Werte visuell herausstechen.
import pandas as pd
df = pd.DataFrame({
'Vorname': ['Alice', 'Bob', 'Charlie', 'David', 'Emma'],
'Gewicht (kg)': [68, 85, 74, 90, 62],
'Größe (cm)': [165, 180, 175, 185, 160],
'IQ': [120, 135, 110, 132, 125]
})
# Styling anwenden, um den höchsten Wert in jeder Spalte hervorzuheben
styled_df = df.style.highlight_max(axis=0, color='lightgreen')
styled_df
Im vorherigen Beispiel haben wir den höchsten Wert in jeder Spalte hervorgehoben.
Allerdings wäre das Hervorheben der maximalen Werte in jeder Zeile nicht sinnvoll, da die Daten heterogen sind – es wäre unlogisch, innerhalb einer einzelnen Zeile einen Namen, ein Gewicht, eine Größe und einen IQ-Wert miteinander zu vergleichen.
Um ein Beispiel zu zeigen, bei dem die zeilenweise Hervorhebung sinnvoll ist, betrachten wir einen passenderen Datensatz.
Mit dem Parameter axis
können wir festlegen, ob wir zeilenweise (axis=1
) oder spaltenweise (axis=0
) hervorheben möchten.
import pandas as pd
df = pd.DataFrame({
'Montag': [8.5, 7.2, 9.0, 6.8, 8.3],
'Dienstag': [7.4, 8.1, 6.5, 9.2, 7.0],
'Mittwoch': [8.0, 9.3, 7.7, 8.1, 6.9],
'Donnerstag': [6.2, 8.4, 9.1, 7.3, 8.5],
'Freitag': [7.3, 6.8, 8.2, 7.6, 9.1]
}, index=['Alice', 'Bob', 'Charlie', 'David', 'Emma'])
# Styling anwenden, um den höchsten Wert in jeder Zeile hervorzuheben
# (der längste Arbeitstag jeder Person)
styled_df = df.style.highlight_max(axis=1, color='orange')
styled_df
Now, we highlight the longest workday per day with axis=0
:
import pandas as pd
df = pd.DataFrame({
'Montag': [8.5, 7.2, 9.0, 6.8, 8.3],
'Dienstag': [7.4, 8.1, 6.5, 9.2, 7.0],
'Mittwoch': [8.0, 9.3, 7.7, 8.1, 6.9],
'Donnerstag': [6.2, 8.4, 9.1, 7.3, 8.5],
'Freitag': [7.3, 6.8, 8.2, 7.6, 9.1]
}, index=['Alice', 'Bob', 'Charlie', 'David', 'Emma'])
# Styling anwenden, um den höchsten Wert in jeder Zeile hervorzuheben
# (der längste Arbeitstag jeder Person)
styled_df = df.style.highlight_max(axis=0, color='orange')
styled_df
Anwenden eines Farbverlaufs / Gradient¶
Die Methode .background_gradient()
wendet einen Farbverlauf auf jede Zelle basierend auf ihrem Wert an, indem eine bestimmte Farbskala (cmap
) verwendet wird.
Die dahinterliegende Logik besteht darin, die Daten zu normalisieren und sie anschließend einer Farbskala zuzuordnen.
df.style.background_gradient(cmap='Blues')
Schritt-für-Schritt-Logik hinter der Farbverlaufsfärbung:
- Werte normalisieren
- Pandas skaliert die Werte in jeder Spalte zwischen 0 und 1.
- Der kleinste Wert wird 0 (hellste Farbe) und der größte Wert wird 1 (dunkelste Farbe).
$$ \text{normalisierter Wert} = \frac{\text{Zellenwert} - \text{min(Spalte)}}{\text{max(Spalte)} - \text{min(Spalte)}} $$
Colormap anwenden (
cmap='Blues'
)- Eine matplotlib-Colormap (z. B.
"Blues"
) wird verwendet, um Farben basierend auf den normalisierten Werten zuzuweisen. - Kleinere Werte erhalten hellere Blautöne.
- Größere Werte erhalten dunklere Blautöne.
- Eine matplotlib-Colormap (z. B.
Farben rendern
- Die Hintergrundfarbe jeder Zelle wird mit der entsprechenden Farbe aus der Colormap gesetzt.
Standardmäßig normalisiert background_gradient()
die Werte spaltenweise (axis=0
).
Um stattdessen zeilenweise zu skalieren, muss axis
auf 1
gesetzt werden:
df.style.background_gradient(cmap='Blues', axis=1)
Du kannst mit verschiedenen cmap
-Werten experimentieren:
- 'Blues' → Blautöne (gut für Klarheit)
- 'Greens' → Grüntöne (umweltfreundlich, positive Wirkung)
- 'Oranges' → Orangetöne (warme Farben)
- 'Purples' → Lilatöne (stilvoll, künstlerisch)
- 'Reds' → Rottöne (Intensität, Dringlichkeit)
- 'Greys' → Grautöne (neutral, gut für dezente visuelle Effekte)
Divergierende Colormaps eignen sich hervorragend, um Abweichungen von einem zentralen Wert hervorzuheben (z. B. positive vs. negative Veränderungen).
- 'coolwarm' → Blau-Rot-Verlauf (gut zur Hervorhebung von Unterschieden)
- 'RdBu' → Rot zu Blau (gegensätzliche Extreme)
- 'PiYG' → Pink zu Grün (ästhetische Alternative zu Rot/Blau)
- 'BrBG' → Braun zu Grün (erdige Töne, gut für Kontraste)
Mehrfarbige & auffällige Colormaps bieten einzigartige und lebendige Effekte.
- 'viridis' → Gelb-Grün-Blau (farbenblindfreundlich, weit verbreitet in der Datenvisualisierung)
- 'plasma' → Lila-Rot-Gelb (hoher Kontrast, sticht hervor)
- 'magma' → Dunkellila-Orange-Gelb (dramatisch, gut für visuelle Effekte mit hoher Wirkung)
- 'cividis' → Blau-Gelb (farbenblindfreundliche Alternative zu Viridis)
Hier ist ein Beispiel mit cmap='cividis'
:
import pandas as pd
import numpy as np
daten = {
'Januar': [5000, -2000, 3000, -1000, 2600],
'Februar': [-1500, 4000, -2500, 500, -1100],
'März': [3000, -1800, 6200, -700, 1000],
'April': [-2200, 5000, -1200, 1000, 3500]
}
index = ['Nimbus Corp', 'Quantum Dynamics', 'Aurora Ventures',
'Vertex Solutions', 'Orion Enterprises']
df = pd.DataFrame(daten, index=index)
# Styling mit 'cividis'-Colormap anwenden
styled_df = df.style.background_gradient(cmap='cividis')
styled_df
Balkendiagramme innerhalb von Zellen anwenden¶
Die Methode .style.bar()
fügt Balkendiagramme innerhalb der Zellen hinzu, um die Werte visuell darzustellen.
Dies erleichtert den schnellen Vergleich von Arbeitsstunden pro Person (zeilenweise) oder pro Tag (spaltenweise).
import pandas as pd
df = pd.DataFrame({
'Montag': [8.5, 5.2, 9.8, 6.1, 7.3],
'Dienstag': [6.4, 8.7, 7.1, 9.0, 5.6],
'Mittwoch': [7.8, 9.5, 5.9, 8.3, 6.7],
'Donnerstag': [5.6, 7.2, 9.3, 6.8, 8.9],
'Freitag': [9.1, 6.5, 8.0, 7.6, 9.4]
}, index=['Alice', 'Bob', 'Charlie', 'David', 'Emma'])
# Balkendiagramme spaltenweise anwenden (jede Spalte hat ihre eigene Skala)
styled_columnwise_bar = df.style.bar(color='lightblue', axis=0)
# Balkendiagramme zeilenweise anwenden (jede Zeile hat ihre eigene Skala)
styled_rowwise_bar = df.style.bar(color='lightgreen',
width=90, # Maximale Breite der Balken in Prozent
axis=1)
styled_rowwise_bar
Ein weiteres Beispiel, das die Verwendung anderer Parameter demonstriert:
data = {
'Januar': [5000, -2000, 3000, -1000, 2600],
'Februar': [-1500, 4000, -2500, 500, -1100],
'März': [3000, -1800, 6200, -700, 1000],
'April': [-2200, 5000, -1200, 1000, 3500]
}
index = ['Nimbus Corp', 'Quantum Dynamics', 'Aurora Ventures',
'Vertex Solutions', 'Orion Enterprises']
df = pd.DataFrame(data, index=index)
styled_df = df.style.bar(
color=('red', 'green'), # Negative Werte in Rot, positive in Grün
align='zero', # Balken um Null zentrieren, andere Optionen: 'left', 'mid' (Standard)
width=80, # Maximale Balkenbreite auf 80 % setzen
axis=0 # Spaltenweise Balkenanzeige
)
styled_df
Funktionen spalten- oder zeilenweise anwenden¶
Die .apply()
-Methode in Pandas ermöglicht es, eine Funktion auf jedes Element, jede Zeile oder jede Spalte eines DataFrames anzuwenden.
Sie ist ein leistungsstarkes Werkzeug für Datenumwandlung, Feature Engineering und benutzerdefinierte Berechnungen.
Hintergrundfarben für Index-, Spalten- und Wertzellen¶
import pandas as pd
df = pd.DataFrame({
'Produkt': ['Hemd', 'Hose', 'Jacke', 'Schuhe', 'Hut'],
'Klein (€)': [25.90, 40.10, 60.00, 80.00, 15.00],
'Mittel (€)': [30.50, 45.00, 65.00, 85.00, 18.00],
'Groß (€)': [35.80, 50.00, 70.00, 90.00, 20.00]
})
def highlight_values(val):
""" Funktion zur Farbgebung der Werte-Zellen in Hellgelb """
return 'background-color: lightyellow;'
# Stile auf die Tabelle anwenden
styled_df = df.style.map(highlight_values).set_table_styles([
{'selector': 'th', 'props': [('background-color', 'orange'), ('color', 'black'), ('font-weight', 'bold')]}, # Spaltenüberschriften
{'selector': 'th.index', 'props': [('background-color', 'orange'), ('color', 'black'), ('font-weight', 'bold')]} # Index (Zeilenüberschriften)
])
# Den gestylten DataFrame anzeigen
styled_df
import pandas as pd
# Erstellen eines DataFrames mit Produkten und Preisen
df = pd.DataFrame({
'Produkt': ['Hemd', 'Hose', 'Jacke', 'Schuhe', 'Hut'],
'Klein (€)': [25.90, 40.10, 60.00, 80.00, 15.00],
'Mittel (€)': [30.50, 45.00, 65.00, 85.00, 18.00],
'Groß (€)': [35.80, 50.00, 70.00, 90.00, 20.00]
})
def highlight_values(val):
""" Hebt Werte-Zellen in Hellgelb hervor """
return 'background-color: lightyellow;'
# Stil auf den DataFrame anwenden
styled_df = df.style.map(highlight_values).set_table_styles([
{'selector': 'th', 'props': [('background-color', 'orange'), ('color', 'black'), ('font-weight', 'bold')]}, # Stil für Spaltenüberschriften
{'selector': 'th.index', 'props': [('background-color', 'orange'), ('color', 'black'), ('font-weight', 'bold')]} # Stil für Zeilenüberschriften (Index)
])
# Gestylten DataFrame anzeigen
styled_df
import pandas as pd
import numpy as np
# Monate definieren
monate = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember']
# Boutique-Standorte definieren
standorte = ['Zürich', 'Frankfurt', 'Hamburg', 'München']
# Zufällige Einkommenswerte generieren (einschließlich Verluste)
np.random.seed(42) # Für Reproduzierbarkeit
daten = np.random.randint(-5000, 20000, size=(12, 4)) # Zufällige Einkommenswerte
# DataFrame erstellen
df = pd.DataFrame(daten, index=monate, columns=standorte)
# Funktion zur Hervorhebung von Werten: Grün für Gewinne, Rot für Verluste
def highlight_values(val):
if val < 0:
return 'background-color: red; color: white; font-weight: bold'
else:
return 'background-color: lightgreen; color: black; font-weight: bold'
# Stile anwenden
styled_df = df.style.map(highlight_values) \
.set_table_styles([
{'selector': 'th',
'props': [('background-color', 'yellow'), ('color', 'black'), ('font-weight', 'bold')]}, # Spaltenüberschriften
{'selector': 'th.index',
'props': [('background-color', 'yellow'), ('color', 'black'), ('font-weight', 'bold')]} # Zeilenüberschriften
]) \
.format("{:,.0f}") # Tausendertrennzeichen für bessere Lesbarkeit hinzufügen
styled_df
📌 Kapitelzusammenfassung¶
In diesem Kapitel haben wir verschiedene Methoden zur Formatierung und Visualisierung von Pandas-DataFrames kennengelernt.
- Wir haben gezeigt, wie sich Werte formatieren lassen, ohne die Rohdaten zu verändern, indem wir
.style.format()
verwendet haben. - Mithilfe von Farbverläufen (
.background_gradient()
) konnten wir Werte visuell hervorheben und deren Unterschiede deutlicher machen. - Die Verwendung von Balkendiagrammen (
.bar()
) ermöglichte eine anschauliche Darstellung von Zahlen innerhalb der Tabellenzellen. - Mit
.apply()
konnten wir benutzerdefinierte Funktionen auf Spalten oder Zeilen anwenden, um Daten flexibel zu transformieren. - Abschließend haben wir gezeigt, wie man Zellen basierend auf ihren Werten einfärbt, um positive und negative Werte klar zu unterscheiden.
Diese Techniken helfen, Daten übersichtlicher und interpretierbarer zu machen, insbesondere in Berichten, Dashboards oder Jupyter Notebooks. 🚀