Erhalten Sie Zugang zu diesem und mehr als 300000 Büchern ab EUR 5,99 monatlich.
Der unverzichtbare Werkzeugkasten für Data Science in der 2. Auflage - Das bewährte Standardwerk jetzt in vollständig aktualisierter Neuauflage - Behandelt die neuesten Versionen von IPython, NumPy, pandas, Matplotlib und Scikit-Learn - Die leicht nachvollziehbaren Beispiele helfen Ihnen bei der erfolgreichen Einrichtung und Nutzung der Data-Science-Tools - Inklusive Jupyter Notebooks, die es Ihnen ermöglichen, den Code direkt beim Lesen auszuprobieren Für viele Data Scientists ist Python die Sprache der Wahl, weil zahlreiche ausgereifte Bibliotheken zum Speichern, Bearbeiten und Auswerten von Daten verfügbar sind. Jake VanderPlas versammelt in dieser 2. Auflage seines Standardwerks alle wichtigen Datenanalyse Tools in einem Band und erläutert deren Einsatz in der Praxis. Beschrieben werden IPython, Jupyter, NumPy, Pandas, Matplotlib, Scikit Learn und verwandte Werkzeuge. Für Datenanalystinnen und analysten und Data Cruncher mit Python Kenntnissen ist dieses umfassende Handbuch von unschätzbarem Wert bei der Erledigung ihrer täglichen Aufgaben. Dazu gehören die Manipulation, Umwandlung und Bereinigung von Daten, die Visualisierung verschiedener Datentypen sowie die Nutzung von Daten zum Erstellen von Statistiken und Machine Learning Modellen. Dieses Handbuch beschreibt die folgenden Tools: - IPython und Jupyter bieten eine Umgebung für Berechnungen, die von vielen Data Scientists genutzt wird - NumPy stellt das ndarray zum effizienten Speichern und Bearbeiten dicht gepackter Datenarrays bereit - Pandas verfügt über das DataFrameObjekt für die Speicherung und Manipulation gelabelter und spaltenorientierter Daten - Matplotlib ermöglicht die flexible und vielseitige Visualisierung von Daten - ScikitLearn unterstützt bei der Implementierung der wichtigsten und gebräuchlichsten Algorithmen für das Machine Learning »Jake beschreibt weit mehr als die Grundlagen dieser Open-Source-Tools; er erläutert die zugrunde liegenden Konzepte, Vorgehensweisen und Abstraktionen in klarer Sprache und mit verständlichen Erklärungen.« -- Brian Granger, Physikprofessor und Mitbegründer des Jupyter-Projekts
Sie lesen das E-Book in den Legimi-Apps auf:
Seitenzahl: 587
Veröffentlichungsjahr: 2023
Das E-Book (TTS) können Sie hören im Abo „Legimi Premium” in Legimi-Apps auf:
Copyright und Urheberrechte:
Die durch die dpunkt.verlag GmbH vertriebenen digitalen Inhalte sind urheberrechtlich geschützt. Der Nutzer verpflichtet sich, die Urheberrechte anzuerkennen und einzuhalten. Es werden keine Urheber-, Nutzungs- und sonstigen Schutzrechte an den Inhalten auf den Nutzer übertragen. Der Nutzer ist nur berechtigt, den abgerufenen Inhalt zu eigenen Zwecken zu nutzen. Er ist nicht berechtigt, den Inhalt im Internet, in Intranets, in Extranets oder sonst wie Dritten zur Verwertung zur Verfügung zu stellen. Eine öffentliche Wiedergabe oder sonstige Weiterveröffentlichung und eine gewerbliche Vervielfältigung der Inhalte wird ausdrücklich ausgeschlossen. Der Nutzer darf Urheberrechtsvermerke, Markenzeichen und andere Rechtsvorbehalte im abgerufenen Inhalt nicht entfernen.
Grundlegende Tools für die Arbeit mit Daten
Jake VanderPlas
Deutsche Übersetzung von Knut Lorenzen und Jørgen W. Lang
Jake VanderPlas
Lektorat: Alexandra Follenius
Übersetzung: Knut Lorenzen, Jørgen W. Lang
Copy-Editing: Sibylle Feldmann, www.richtiger-text.de
Satz: III-satz, www.drei-satz.de
Herstellung: Stefanie Weidner
Umschlaggestaltung: Karen Montgomery, Michael Oréal, www.oreal.de
Bibliografische Information der Deutschen Nationalbibliothek
Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar.
ISBN:
Print 978-3-96009-225-4
PDF 978-3-96010-812-2
ePub 978-3-96010-813-9
mobi 978-3-96010-814-6
1. Auflage 2024
Translation Copyright für die deutschsprachige Ausgabe © 2024 dpunkt.verlag GmbH
Wieblinger Weg 17
69123 Heidelberg
Authorized German translation of the English edition of Python Data Science Handbook, 2nd Edition, ISBN 9781098121228 © 2023 Jake VanderPlas. This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same.
Dieses Buch erscheint in Kooperation mit O’Reilly Media, Inc. unter dem Imprint »O’REILLY«. O’REILLY ist ein Markenzeichen und eine eingetragene Marke von O’Reilly Media, Inc. und wird mit Einwilligung des Eigentümers verwendet.
Hinweis:
Dieses Buch wurde mit mineralölfreien Farben auf PEFC-zertifiziertem Papier aus nachhaltiger Waldwirtschaft gedruckt. Der Umwelt zuliebe verzichten wir zusätzlich auf die Einschweißfolie. Hergestellt in Deutschland.
Schreiben Sie uns:
Falls Sie Anregungen, Wünsche und Kommentare haben, lassen Sie es uns wissen: [email protected].
Die vorliegende Publikation ist urheberrechtlich geschützt. Alle Rechte vorbehalten. Die Verwendung der Texte und Abbildungen, auch auszugsweise, ist ohne die schriftliche Zustimmung des Verlags urheberrechtswidrig und daher strafbar. Dies gilt insbesondere für die Vervielfältigung, Übersetzung oder die Verwendung in elektronischen Systemen.
Es wird darauf hingewiesen, dass die im Buch verwendeten Soft- und Hardware-Bezeichnungen sowie Markennamen und Produktbezeichnungen der jeweiligen Firmen im Allgemeinen warenzeichen-, marken- oder patentrechtlichem Schutz unterliegen.
Alle Angaben und Programme in diesem Buch wurden mit größter Sorgfalt kontrolliert. Weder Autor noch Übersetzer noch Verlag können jedoch für Schäden haftbar gemacht werden, die in Zusammenhang mit der Verwendung dieses Buches stehen.
5 4 3 2 1 0
Einleitung
Teil I: Mehr als normales Python: Jupyter
1Der Einstieg in IPython und Jupyter
Die IPython-Shell starten
Das Jupyter Notebook starten
Hilfe und Dokumentation in IPython
Tastaturkürzel in der IPython-Shell
2Erweiterte interaktive Features
Magische Befehle in IPython
Verlauf der Ein- und Ausgabe
IPython und Shell-Befehle
3Debugging und Profiling
Fehler und Debugging
Profiling und Timing von Code
Weitere IPython-Ressourcen
Teil II: Einführung in NumPy
4Die Datentypen in Python
Python-Integer sind mehr als nur ganzzahlige Werte
Python-Listen sind mehr als nur einfache Listen
Arrays feststehenden Typs in Python
Arrays anhand von Listen erzeugen
Neue Arrays erzeugen
NumPys Standarddatentypen
5Grundlagen von NumPy-Arrays
Attribute von NumPy-Arrays
Indizierung von Arrays: Zugriff auf einzelne Elemente
Slicing: Teilmengen eines Arrays auswählen
Arrays umformen
Arrays verketten und aufteilen
6Berechnungen mit NumPy-Arrays: universelle Funktionen
Langsame Schleifen
Kurz vorgestellt: UFuncs
NumPys UFuncs im Detail
UFunc-Features für Fortgeschrittene
UFuncs: mehr erfahren
7Aggregationen: Minimum, Maximum und alles dazwischen
Summieren der Werte eines Arrays
Minimum und Maximum
Beispiel: Durchschnittliche Größe der US-Präsidenten
8Berechnungen mit Arrays: Broadcasting
Kurz vorgestellt: Broadcasting
Für das Broadcasting geltende Regeln
Broadcasting in der Praxis
9Vergleiche, Maskierungen und boolesche Logik
Beispiel: Regentage zählen
Vergleichsoperatoren als UFuncs
Boolesche Arrays verwenden
Boolesche Arrays als Maskierungen
Verwendung der Schlüsselwörter »and« bzw. »or« und der Operatoren & bzw. |
10Fancy Indexing
Fancy Indexing im Detail
Kombinierte Indizierung
Beispiel: Auswahl zufälliger Punkte
Werte per Fancy Indexing modifizieren
Beispiel: Daten gruppieren
11Arrays sortieren
Schnelle Sortierung in NumPy: np.sort und np.argsort
Nach Zeilen und Spalten sortieren
Teilsortierungen: Partitionierung
Beispiel: k nächste Nachbarn
12Strukturierte Daten: NumPys strukturierte Arrays
Strukturierte Arrays erzeugen
Erweiterte zusammengesetzte Typen
Record-Arrays: strukturierte Arrays mit Pfiff
Weiter mit Pandas
Teil III: Datenbearbeitung mit Pandas
13Kurz vorgestellt: Pandas-Objekte
Das Pandas-Series-Objekt
Das Pandas-DataFrame-Objekt
Das Pandas-Index-Objekt
14Daten indizieren und auswählen
Series-Daten auswählen
DataFrame-Daten auswählen
15Mit Pandas-Daten arbeiten
UFuncs: Indexerhaltung
UFuncs: Indexanpassung
UFuncs: Operationen mit DataFrame und Series
16Handhabung fehlender Daten
Kompromisse beim Umgang mit fehlenden Daten
Fehlende Daten in Pandas
Pandas nullfähige Datentypen
Mit Nullwerten arbeiten
17Hierarchische Indizierung
Mehrfach indizierte Series
Methoden zum Erzeugen eines MultiIndex
Indizierung und Slicing eines MultiIndex
Multi-Indizes umordnen
18Datenmengen kombinieren: concat und append
Verkettung von NumPy-Arrays
Einfache Verkettungen mit pd.concat
19Datenmengen kombinieren: merge und join
Relationale Algebra
Join-Kategorien
Angabe der zu verknüpfenden Spalten
Mengenarithmetik bei Joins
Konflikte bei Spaltennamen: das Schlüsselwort suffixes
Beispiel: Daten von US-Bundesstaaten
20Aggregation und Gruppierung
Planetendaten
Einfache Aggregationen in Pandas
GroupBy: Aufteilen, Anwenden und Kombinieren
21Pivot-Tabellen
Gründe für Pivot-Tabellen
Pivot-Tabellen von Hand erstellen
Die Syntax von Pivot-Tabellen
Beispiel: Geburtenraten
22Vektorisierte String-Operationen
Kurz vorgestellt: String-Operationen in Pandas
Liste der Pandas-String-Methoden
Beispiel: Rezeptdatenbank
23Zeitreihen verwenden
Kalenderdaten und Zeiten in Python
Zeitreihen in Pandas: Indizierung durch Zeitangaben
Datenstrukturen für Zeitreihen in Pandas
Gleichförmige Sequenzen: pd.date_range
Häufigkeiten und Abstände
Resampling, zeitliches Verschieben und geglättete Statistik
Beispiel: Visualisierung von Fahrradzählungen in Seattle
24Leistungsstarkes Pandas: eval und query
Der Zweck von query und eval: zusammengesetzte Ausdrücke
Effiziente Operationen mit pandas.eval
DataFrame.eval für spaltenweise Operationen
Die DataFrame.query-Methode
Performance: Wann eval und query verwendet werden sollten
Weitere Ressourcen
Teil IV: Visualisierung mit Matplotlib
25Allgemeine Tipps zu Matplotlib
Matplotlib importieren
Stil einstellen
show oder kein show? – Anzeige von Diagrammen
26Einfache Liniendiagramme
Anpassen des Diagramms: Linienfarben und -stile
Anpassen des Diagramms: Begrenzungen
Diagramme beschriften
Stolpersteine in Matplotlib
27Einfache Streudiagramme
Streudiagramme mit plt.plot erstellen
Streudiagramme mit plt.scatter erstellen
plot kontra scatter: eine Anmerkung zur Effizienz
Visualisierung von Messunsicherheiten
28Dichtediagramme und Konturdiagramme
Visualisierung einer dreidimensionalen Funktion
Histogramme, Binnings und Dichte
Zweidimensionale Histogramme und Binnings
29Anpassen der Legende
Legendenelemente festlegen
Legenden mit Punktgrößen
Mehrere Legenden
30Anpassen von Farbskalen
Farbskala anpassen
Beispiel: Handgeschriebene Ziffern
31Untergeordnete Diagramme
plt.axes: untergeordnete Diagramme von Hand erstellen
plt.subplot: untergeordnete Diagramme in einem Raster anordnen
plt.subplots: das gesamte Raster gleichzeitig ändern
plt.GridSpec: kompliziertere Anordnungen
32Text und Beschriftungen
Beispiel: Auswirkungen von Feiertagen auf die Geburtenzahlen in den USA
Transformationen und Textposition
Pfeile und Beschriftungen
33Achsenmarkierungen anpassen
Vorrangige und nachrangige Achsenmarkierungen
Markierungen oder Beschriftungen verbergen
Anzahl der Achsenmarkierungen verringern oder erhöhen
Formatierung der Achsenmarkierungen
Zusammenfassung der Formatter- und Locator-Klassen
34Matplotlib anpassen: Konfigurationen und Stylesheets
Diagramme von Hand anpassen
Voreinstellungen ändern: rcParams
35Dreidimensionale Diagramme in Matplotlib
Dreidimensionale Punkte und Linien
Dreidimensionale Konturdiagramme
Drahtgitter- und Oberflächendiagramme
Triangulation von Oberflächen
Beispiel: Visualisierung eines Möbiusbands
36Visualisierung mit Seaborn
Seaborn-Diagramme
Kategoriale Diagramme
Beispiel: Ergebnisse eines Marathonlaufs
Weiterführende Ressourcen
Weitere Grafikbibliotheken für Python
Teil V: Machine Learning
37Was ist Machine Learning?
Kategorien des Machine Learning
Qualitative Beispiele für Machine-Learning-Anwendungen
Zusammenfassung
38Kurz vorgestellt: Scikit-Learn
Datenrepräsentierung in Scikit-Learn
Die Estimator-API
Anwendung: Handgeschriebene Ziffern untersuchen
Zusammenfassung
39Hyperparameter und Modellvalidierung
Überlegungen zum Thema Modellvalidierung
Auswahl des besten Modells
Lernkurven
Validierung in der Praxis: Rastersuche
Zusammenfassung
40Feature Engineering
Kategoriale Features
Texte als Features
Bilder als Features
Abgeleitete Features
Vervollständigung fehlender Daten
Feature-Pipelines
41Ausführlich: Naive Bayes-Klassifikation
Bayes-Klassifikation
Gaußsche naive Bayes-Klassifikation
Multinomiale naive Bayes-Klassifikation
Einsatzgebiete für naive Bayes-Klassifikation
42Ausführlich: Lineare Regression
Einfache lineare Regression
Regression der Basisfunktion
Regularisierung
Beispiel: Vorhersage des Fahrradverkehrs
43Ausführlich: Support Vector Machines
Gründe für Support Vector Machines
Support Vector Machines: Maximierung des Randbereichs
Beispiel: Gesichtserkennung
Zusammenfassung
44Ausführlich: Entscheidungsbäume und Random Forests
Gründe für Random Forests: Entscheidungsbäume
Estimator-Ensembles: Random Forests
Random-Forest-Regression
Beispiel: Random Forest zur Klassifikation handgeschriebener Ziffern
Zusammenfassung
45Ausführlich: Hauptkomponentenanalyse
Hauptkomponentenanalyse: ein Überblick
Hauptkomponentenanalyse als Rauschfilter
Beispiel: Eigengesichter
Zusammenfassung
46Ausführlich: Manifold Learning
Manifold Learning: »HELLO«
Multidimensionale Skalierung
Nichtlineare Mannigfaltigkeiten: lokal lineare Einbettung
Überlegungen zum Thema Manifold-Methoden
Beispiel: Isomap und Gesichter
Beispiel: Visualisierung der Strukturen in Zifferndaten
47Ausführlich: k-Means-Clustering
Kurz vorgestellt: der k-Means-Algorithmus
Expectation-Maximization
Beispiele
48Ausführlich: Gaußsche Mixture-Modelle
Gründe für GMM: Schwächen von k-Means
EM-Verallgemeinerung: gaußsche Mixture-Modelle
Wahl des Kovarianztyps
GMM als Dichteschätzung
Beispiel: GMM zum Erzeugen neuer Daten verwenden
49Ausführlich: Kerndichteschätzung
Gründe für Kerndichteschätzung: Histogramme
Kerndichteschätzung in der Praxis
Auswahl der Bandbreite durch Kreuzvalidierung
Beispiel: Nicht ganz so naive Bayes-Klassifikation
50Anwendung: Eine Gesichtserkennungspipeline
HOG-Features
HOG in Aktion: eine einfache Gesichtserkennung
Vorbehalte und Verbesserungen
Weitere Machine-Learning-Ressourcen
Index
In diesem Buch geht es darum, Data Science mithilfe von Python zu betreiben, daher stellt sich unmittelbar die Frage: Was ist Data Science überhaupt? Das genau zu definieren, erweist sich als überraschend schwierig, insbesondere in Anbetracht der Tatsache, wie geläufig dieser Begriff inzwischen geworden ist. Von lautstarken Kritikern wird er mitunter als eine überflüssige Bezeichnung abgetan (denn letzten Endes kommt keine Wissenschaft ohne Daten aus) oder für ein leeres Schlagwort gehalten, das lediglich dazu dient, Lebensläufe aufzupolieren, um die Aufmerksamkeit übereifriger Personalverantwortlicher zu erlangen.
Meiner Ansicht nach übersehen diese Kritiker dabei einen wichtigen Punkt. Trotz des mit dem Begriff einhergehenden Hypes ist Data Science wohl die beste Beschreibung für fachübergreifende Fähigkeiten, die in vielen Anwendungsbereichen in Wirtschaft und Wissenschaft immer wichtiger werden. Entscheidend ist hier die Interdisziplinarität: Ich halte Drew Conways Venn-Diagramm, das er im September 2010 erstmals in seinem Blog veröffentlichte, für die beste Definition von Data Science (siehe Abbildung 1).
Zwar sind einige der Bezeichnungen für die Schnittmengen etwas überspitzt formuliert, aber dennoch erfasst dieses Diagramm das Wesentliche dessen, was gemeint ist, wenn man von »Data Science« spricht: Es handelt sich um ein grundlegend interdisziplinäres Thema. Data Science umfasst drei verschiedene und sich überschneidende Bereiche: die Statistik, um (immer größer werdende) Datenmengen modellieren und zusammenfassen zu können, die Informatik, um Algorithmen für die effiziente Speicherung, Verarbeitung und Visualisierung dieser Daten entwerfen zu können, und das erforderliche Fachwissen (das wir uns als das »klassisch« Erlernte eines Fachgebiets vorstellen können), um sowohl die angemessenen Fragen zu stellen als auch die Antworten im richtigen Kontext zu bewerten.
In diesem Sinne möchte ich Sie ermutigen, Data Science nicht als ein neu zu erlernendes Fachwissensgebiet zu begreifen, sondern als neue Fähigkeiten, die Sie im Rahmen Ihres vorhandenen Fachwissens anwenden können. Ob Sie über Wahlergebnisse berichten, Aktienrenditen vorhersagen, Mausklicks auf Onlinewerbung optimieren, Mikroorganismen auf Mikroskopbildern identifizieren, nach neuen Arten astronomischer Objekte suchen oder mit irgendwelchen anderen Daten arbeiten: Ziel dieses Buchs ist es, Ihnen die Fähigkeit zu vermitteln, neuartige Fragen über das von Ihnen gewählte Fachgebiet zu stellen und diese zu beantworten.
Abbildung 1: Das Venn-Diagramm zur Data Science von Drew Conway (Quelle: Drew Conway (https://oreil.ly/PkOOw), Abdruck mit freundlicher Genehmigung)
Sowohl in meinen Vorlesungen an der Universität Washington als auch auf verschiedenen technisch orientierten Konferenzen und Treffen wird mir am häufigsten diese Frage gestellt: »Wie kann man Python am besten erlernen?« Bei den Fragenden handelt es sich im Allgemeinen um technisch interessierte Studenten, Entwicklerinnen oder Forscher, die oftmals schon über umfangreiche Erfahrung mit dem Schreiben von Code und der Verwendung von rechnergestützten und numerischen Tools verfügen. Die meisten dieser Personen möchten Python erlernen, um die Programmiersprache als Tool für datenintensive und rechnergestützte wissenschaftliche Aufgaben zu nutzen. Für diese Zielgruppe ist eine Vielzahl von Lernvideos, Blogbeiträgen und Tutorials online verfügbar. Allerdings frustriert mich bereits seit geraumer Zeit, dass es auf obige Frage keine wirklich eindeutige und gute Antwort gibt – und das war der Anlass für dieses Buch.
Das Buch ist nicht als Einführung in Python oder die Programmierung im Allgemeinen gedacht. Ich setze voraus, dass die Leserinnen und Leser mit der Programmiersprache Python vertraut ist. Dazu gehören das Definieren von Funktionen, die Zuweisung von Variablen, das Aufrufen der Methoden von Objekten, die Steuerung des Programmablaufs und weitere grundlegende Aufgaben. Das Buch soll vielmehr Python-Usern dabei helfen, die zum Betreiben von Data Science verfügbaren Pakete zu nutzen – Bibliotheken wie die im folgenden Abschnitt genannten und ähnliche Tools –, um Daten effektiv zu speichern, zu handhaben und Einblick in diese Daten zu gewinnen.
Python hat sich in den vergangenen Jahrzehnten zu einem erstklassigen Tool für wissenschaftliche Berechnungen entwickelt, insbesondere auch für die Analyse und Visualisierung großer Datensätze. Die ersten Anhänger der Programmiersprache Python dürfte das ein wenig überraschen: Beim eigentlichen Design der Sprache wurde weder der Datenanalyse noch wissenschaftlichen Berechnungen besondere Beachtung geschenkt. Dass sich Python für die Data Science als so nützlich erweist, ist vor allem dem großen und aktiven Ökosystem der Programmpakete von Drittherstellern zu verdanken: Da gibt es NumPy für die Handhabung gleichartiger Array-basierter Daten, Pandas für die Verarbeitung verschiedenartiger und gelabelter Daten, SciPy für gängige wissenschaftliche Berechnungen, Matplotlib für druckreife Visualisierungen, IPython für die interaktive Ausführung und zum Teilen von Code, Scikit-Learn für Machine Learning sowie viele weitere Tools, die auf den folgenden Seiten vorgestellt werden.
Falls Sie auf der Suche nach einer Einführung in die Programmiersprache Python sind, empfehle ich das dieses Buch ergänzende Projekt A Whirlwind Tour of Python (https://oreil.ly/jFtWj). Bei diesem kurzen Bericht handelt es sich um eine Tour durch die wesentlichen Features der Sprache Python, die sich an Data Scientists richtet, die bereits mit anderen Programmiersprachen vertraut sind.
Alle nummerierten Teile in diesem Buch konzentrieren sich auf ein bestimmtes Paket oder Tool, das für die mit Python betriebene Data Science von grundlegender Bedeutung ist. Sie sind in eigenständige Kapitel unterteilt, die jeweils ein bestimmtes Konzept behandeln.
Teil I
, »
Mehr als normales Python: Jupyter
«, stellt IPython und Jupyter vor. Diese Pakete bieten eine Umgebung für Berechnungen, die von vielen Data Scientists genutzt wird, die Python einsetzen.
Teil II
, »
Einführung in NumPy
«, konzentriert sich auf die NumPy-Bibliothek, die das
ndarray
bereitstellt, das ein effizientes Speichern und die Handhabung dicht gepackter Daten-Arrays in Python ermöglicht.
Teil III
, »
Datenbearbeitung mit Pandas
«, stellt die Pandas-Bibliothek vor. Sie verfügt über das
DataFrame
-Objekt, das ein effizientes Speichern und die Handhabung gelabelter bzw. spaltenorientierter Daten in Python gestattet.
Teil IV
, »
Visualisierung mit Matplotlib
«, konzentriert sich auf Matplotlib, eine Bibliothek, die flexible und vielfältige Visualisierungen von Daten in Python ermöglicht.
Teil V
, »
Machine Learning
«, zeigt die Bibliothek Scikit-Learn. Sie stellt eine effiziente Implementierung der wichtigsten und gebräuchlichsten Machine-Learning-Algorithmen zur Verfügung.
Natürlich umfasst die PyData-Welt viel mehr als diese sechs Pakete – und sie wächst mit jedem Tag weiter. Ich werde mich im Folgenden daher bemühen, Hinweise auf andere interessante Projekte, Bestrebungen und Pakete zu geben, die die Grenzen des mit Python Machbaren erweitern. Dessen ungeachtet sind die Pakete, auf die ich mich hier konzentriere, derzeit für viele der mit Python möglichen Aufgaben der Data Science von grundlegender Bedeutung, und ich erwarte, dass sie wichtig bleiben, auch wenn das sie umgebende Ökosystem weiterhin wächst.
Die Installation von Python und den für wissenschaftliche Berechnungen erforderlichen Bibliotheken ist unkompliziert. In diesem Abschnitt finden Sie einige Überlegungen, denen Sie bei der Einrichtung Ihres Computers Beachtung schenken sollten.
Es gibt zwar verschiedene Möglichkeiten, Python zu installieren, allerdings empfehle ich zum Betreiben von Data Science die Anaconda-Distribution, die unter Windows, Linux und macOS auf ähnliche Weise funktioniert. Es gibt zwei Varianten der Anaconda-Distribution:
Miniconda (
https://oreil.ly/dH7wJ
) besteht aus dem eigentlichen Python-Interpreter und einem Kommandozeilenprogramm namens
conda
, das als plattformübergreifender Paketmanager für Python-Pakete fungiert. Das Programm arbeitet in ähnlicher Weise wie die Tools
apt
oder
yum
, die Linux-Usern bekannt sein dürften.
Anaconda (
https://oreil.ly/ndxjm
) enthält sowohl Python als auch
conda
und darüber hinaus eine Reihe vorinstallierter Pakete, die für wissenschaftliche Berechnungen konzipiert sind. Aufgrund der Größe dieser Pakete müssen Sie davon ausgehen, dass die Installation mehrere Gigabyte Speicherplatz auf der Festplatte belegt.
Alle in Anaconda enthaltenen Pakete können auch nachträglich der Miniconda-Installation hinzugefügt werden. Daher empfehle ich, mit Miniconda anzufangen.
Laden Sie zunächst das Miniconda-Paket herunter und installieren Sie es. Vergewissern Sie sich, dass Sie eine Version auswählen, die Python 3 enthält. Installieren Sie dann die in diesem Buch verwendeten Pakete:
[~]$ conda install numpy pandas scikit-learn matplotlib seaborn jupyter
Wir werden im gesamten Buch noch weitere, spezialisiertere Tools einsetzen, die zum wissenschaftlich orientierten Ökosystem in Python gehören. Für gewöhnlich ist zur Installation lediglich eine Eingabe wie conda installpackagename nötig. Sollten Ihnen einmal Pakete begegnen, die über den Standard-conda-Kanal nicht erhältlich sind, sollten Sie auf jeden Fall auf conda-forge (https://oreil.ly/CCvwQ) nachsehen, einem vielfältigen, von der Community gepflegten Repository mit conda-Paketen. Weitere Informationen über conda, beispielsweise über das Erstellen und Verwenden von conda-Umgebungen (die ich nur nachdrücklich empfehlen kann), finden Sie in der Onlinedokumentation (https://oreil.ly/MkqPw).
In diesem Buch gelten die folgenden typografischen Konventionen:
Kursiv
Kennzeichnet neue Begriffe, URLs, Dateinamen und Dateierweiterungen.
Nicht proportionale Schrift
Wird für Programmlistings und im Fließtext verwendet, um Programmbestandteile wie Variablen- oder Funktionsbezeichnungen, Datenbanken, Datentypen, Umgebungsvariablen, Anweisungen und Schlüsselwörter zu kennzeichnen.
Fette nicht proportionale Schrift
Kommandos oder sonstiger Text, der vom User buchstabengetreu eingegeben werden soll.
Kursive nicht proportionale Schrift
Text, der durch eigene Werte oder durch kontextabhängige Werte zu ersetzen ist.
Dieses Element steht für einen allgemeinen Hinweis.
Unter http://github.com/jakevdp/PythonDataScienceHandbook steht ergänzendes Material (Codebeispiele, Abbildungen usw.) zum Herunterladen zur Verfügung.
Dieses Buch soll Ihnen helfen, Ihre Arbeit zu erledigen. Den im Buch aufgeführten Code können Sie generell in Ihren eigenen Programmen und der Dokumentation verwenden. Sie brauchen uns nicht um Erlaubnis zu fragen, solange Sie nicht erhebliche Teile des Codes nutzen. Wenn Sie beispielsweise ein Programm schreiben, das einige der im Buch aufgeführten Codeschnipsel verwendet, benötigen Sie dafür keine Erlaubnis. Der Verkauf oder Vertrieb von Beispielen aus O’Reilly-Büchern bedarf hingegen einer Genehmigung. Das Beantworten von Fragen durch Verwendung von Zitaten oder Beispielcode aus diesem Buch muss nicht extra genehmigt werden. Die Verwendung erheblicher Teile des Beispielcodes in der Dokumentation Ihres eigenen Produkts erfordert jedoch eine Genehmigung.
Wir freuen uns über Quellennennungen, machen sie jedoch nicht zur Bedingung. Üblich ist die Nennung von Titel, Autor(en), Verlag, Erscheinungsjahr und ISBN, also beispielsweise: »Handbuch Data Science mit Python, 2. Auflage von Jake VanderPlas, O’Reilly 2024, ISBN 978-3-96009-225-4«.
Wenn Sie glauben, dass sich die Verwendung der Codebeispiele außerhalb der Fair-Use-Prinzipien oder der oben erwähnten Erlaubnis liegt, kontaktieren Sie uns bitte per E-Mail an [email protected].
Für Python stehen viele verschiedene Entwicklungsumgebungen zur Verfügung, und häufig werde ich gefragt, welche ich für meine eigenen Arbeiten verwende. Einige Menschen überrascht die Antwort: Meine bevorzugte Entwicklungsumgebung ist IPython (http://ipython.org) in Kombination mit einem Texteditor (entweder Emacs oder VSCode – das hängt von meiner Stimmung ab). Jupyter begann als die IPython-Shell, die 2001 von Fernando Perez in Form eines erweiterten Python-Interpreters ins Leben gerufen wurde und sich seither zu einem Projekt entwickelt hat, »Tools für den gesamten Lebenszyklus in der forschenden Informatik« – so Perez’ eigene Worte – bereitzustellen. Wenn man Python als Motor einer Aufgabe von Data Science betrachtet, können Sie sich Jupyter als die interaktive Steuerkonsole dazu vorstellen
Jupyter ist nicht nur eine nützliche interaktive Schnittstelle zu Python, sondern stellt darüber hinaus eine Reihe praktischer syntaktischer Erweiterungen der Sprache bereit. Die nützlichsten dieser Erweiterungen werden wir hier erörtern. Die bekannteste, vom Jupyter-Projekt bereitgestellte Schnittstelle ist wohl das Jupyter Notebook, eine browserbasierte Umgebung, die für die Entwicklung, die Zusammenarbeit, das Teilen und sogar die Veröffentlichung von Ergebnissen der Data Science gute Dienste leistet. Um ein Beispiel für die Nützlichkeit dieses Notebook-Formats zu geben: Betrachten Sie einfach nur die Seite, die Sie gerade lesen. Das vollständige Manuskript dieses Buchs wurde in Form einer Reihe von Jupyter Notebooks verfasst.
In diesem Teil des Buchs werden wir zunächst einige der Features von Jupyter betrachten, die sich in der Praxis der Data Science als nützlich erweisen. Der Schwerpunkt liegt hierbei auf der bereitgestellten Syntax, die mehr zu bieten hat als die Standardfeatures von Python. Anschließend werden wir uns etwas eingehender mit einigen der sehr nützlichen magischen Befehle befassen, die gängige Aufgaben bei der Erstellung und Verwendung des Data-Science-Codes beschleunigen können. Zum Abschluss erörtern wir dann einige der Features des Notebooks, die dem Verständnis der Daten und dem Teilen der Ergebnisse dienen können.
Beim Schreiben von Code für Data Science verfolge ich normalerweise drei Arbeitsweisen: Ich benutze die IPython-Shell, um kurze Folgen von Befehlen auszuprobieren, das Jupyter Notebook für längere interaktive Analysen und um Inhalte mit anderen zu teilen sowie interaktive Entwicklungsumgebungen (IDEs) wie Emacs oder VSCode, um wiederverwendbare Python-Pakete zu erstellen. Dieses Kapitel konzentriert sich auf die ersten beiden Methoden: die IPython-Shell und das Jupyter Notebook. Der Einsatz einer IDE für die Softwareentwicklung ist ein wichtiges drittes Werkzeug im Repertoire der Data Scientists, auf das wir hier aber nicht direkt eingehen.
Wie die meisten Teile dieses Buchs sollte auch dieser nicht passiv gelesen werden. Ich empfehle Ihnen, während der Lektüre mit den vorgestellten Tools und der angegebenen Syntax herumzuexperimentieren. Die durch das Nachvollziehen der Beispiele erworbenen Fingerfertigkeiten werden sich als sehr viel nützlicher erweisen, als wenn Sie nur darüber lesen. Geben Sie auf der Kommandozeile ipython ein, um den Python-Interpreter zu starten. Sollten Sie eine Distribution wie Anaconda oder EPD (Enthought Python Distribution) installiert haben, können Sie möglicherweise alternativ einen systemspezifischen Programmstarter verwenden.
Nach dem Start des Interpreters sollte Ihnen eine Eingabeaufforderung wie die folgende angezeigt werden:
Python 3.9.2 (v3.9.2:1a79785e3e, Feb 19 2021, 09:06:10)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.21.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]:
Nun können Sie fortfahren.
Das Jupyter Notebook ist eine browserbasierte grafische Schnittstelle für die IPython-Shell und besitzt eine große Vielfalt dynamischer Anzeigemöglichkeiten. Neben der Ausführung von Python-/IPython-Anweisungen gestattet das Notebook dem User das Einfügen von formatiertem Text, statischen und dynamischen Visualisierungen, mathematischen Formeln, JavaScript-Widgets und vielem mehr. Darüber hinaus können die Dokumente in einem Format gespeichert werden, das anderen Usern ermöglicht, sie auf ihren eigenen Systemen zu öffnen und den Code auszuführen.
Das Jupyter Notebook wird zwar in einem Fenster Ihres Webbrowsers angezeigt und bearbeitet, allerdings ist eine Verbindung zu einem laufenden Python-Prozess erforderlich, um Code auszuführen. Geben Sie in Ihrer System-Shell folgenden Befehl ein, um diesen Prozess (der als »Kernel« bezeichnet wird) zu starten:
$ jupyter lab
Dieser Befehl startet einen lokalen Webserver, auf den Ihr Browser zugreifen kann. Er gibt sofort einige Meldungen aus, die zeigen, was vor sich geht. Dieses Log sieht in etwa folgendermaßen aus:
$ jupyter lab
[ServerApp] Serving notebooks from local directory: /Users/jakevdp/ \
PythonDataScienceHandbook
[ServerApp] Jupyter Server 1.4.1 is running at:
[ServerApp] http://localhost:8888/lab?token=dd852649
[ServerApp] Use Control-C to stop this server and shut down all kernels
(twice to skip confirmation).
Nach der Eingabe des Befehls sollte sich automatisch Ihr Standardbrowser öffnen und die genannte lokale URL anzeigen. Die genaue Adresse ist von Ihrem System abhängig. Öffnet sich Ihr Browser nicht automatisch, können Sie von Hand ein Browserfenster öffnen und die Adresse (in diesem Beispiel http://localhost:8888/lab/) eingeben.
Auch wenn Sie die anderen Abschnitte dieses Kapitels überspringen, sollten Sie doch wenigstens diesen lesen: Ich habe festgestellt, dass die hier erläuterten IPython-Tools den größten Einfluss auf meinen alltäglichen Arbeitsablauf haben.
Wenn ein technologisch interessierter Mensch darum gebeten wird, einem Freund, einem Familienmitglied oder einer Kollegin bei einem Computerproblem zu helfen, geht es meistens gar nicht darum, die Lösung zu kennen, sondern zu wissen, wie man schnell eine noch unbekannte Lösung findet. Mit Data Science verhält es sich ähnlich: Durchsuchbare Webressourcen wie Onlinedokumentationen, Mailinglisten und auf Stackoverflowbusiness.com gefundene Antworten enthalten jede Menge Informationen, auch (oder gerade?) wenn es sich um ein Thema handelt, nach dem Sie selbst schon einmal gesucht haben. Für einen leistungsfähigen Praktiker der Data Science geht es weniger darum, das in jeder erdenklichen Situation einzusetzende Tool oder den geeigneten Befehl auswendig zu lernen, sondern vielmehr darum, zu wissen, wie man die benötigten Informationen schnell und einfach findet – sei es nun mithilfe einer Suchmaschine oder auf anderem Weg.
Zwischen dem User und der erforderlichen Dokumentation sowie den Suchvorgängen, die ein effektives Arbeiten ermöglichen, klafft eine Lücke. Diese zu schließen, ist eine der nützlichsten Funktionen von IPython/Jupyter. Zwar spielen Suchvorgänge im Web bei der Beantwortung komplizierter Fragen nach wie vor eine Rolle, allerdings stellt IPython bereits eine bemerkenswerte Menge an Informationen bereit. Hier einige Beispiele für Fragen, bei deren Beantwortung IPython nach einigen wenigen Tastendrücken hilfreich sein kann:
Wie rufe ich eine bestimmte Funktion auf? Welche Argumente und Optionen besitzt sie?
Wie sieht der Quellcode eines bestimmten Python-Objekts aus?
Was ist in einem importierten Paket enthalten?
Welche Attribute oder Methoden besitzt ein Objekt?
Wir erörtern nun die Tools von IPython und Jupyter für den schnellen Zugriff auf diese Informationen, nämlich das Zeichen ? zum Durchsuchen der Dokumentation, die beiden Zeichen ?? zum Erkunden des Quellcodes und die Tabulatortaste (Tab-Taste), die eine automatische Vervollständigung ermöglicht.
Die Programmiersprache Python und das für die Data Science geeignete Ökosystem schenken den Nutzerinnen und Nutzern große Beachtung. Dazu gehört insbesondere der Zugang zur Dokumentation. Alle Python-Objekte enthalten einen Verweis auf einen String, den sogenannten Docstring, der wiederum in den meisten Fällen eine kompakte Übersicht über das Objekt und dessen Verwendung enthält. Python verfügt über eine integrierte help-Funktion, die auf diese Informationen zugreift und sie ausgibt. Um beispielsweise die Dokumentation der integrierten Funktion len anzuzeigen, können Sie Folgendes eingeben:
In [1]: help(len)
Help on built-in function len in module builtins:
len(obj, /)
Return the number of items in a container.
Je nachdem, welchen Interpreter Sie verwenden, wird der Text auf der Konsole oder in einem eigenen Fenster ausgegeben.
Die Suche nach der Hilfe für ein Objekt ist äußerst nützlich und sehr häufig notwendig. Daher verwendet IPython das Zeichen ? als Abkürzung für den Zugriff auf die Dokumentation und weitere wichtige Informationen:
In [2]: len?
Signature: len(obj, /)
Docstring: Return the number of items in a container.
Type: builtin_function_or_method
Diese Schreibweise funktioniert praktisch mit allem, auch mit Objektmethoden:
Und sogar mit Objekten selbst – dann wird die Dokumentation des Objekttyps angezeigt:
In [5]: L?
Type: list
String form: [1, 2, 3]
Length: 3
Docstring:
Built-in mutable sequence.
If no argument is given, the constructor creates a new empty list.
The argument must be an iterable if specified.
Wichtig zu wissen ist, dass das ebenfalls mit Funktionen und anderen von Ihnen selbst erzeugten Objekten funktioniert:
In [6]: def square(a):
....: """Return the square of a."""
....: return a ** 2
....:
Beachten Sie hier, dass wir zum Erstellen des Docstrings unserer Funktion einfach eine literale Zeichenkette in die erste Zeile eingegeben haben. Da Docstrings für gewöhnlich mehrzeilig sind, haben wir gemäß Konvention Pythons Schreibweise für mehrzeilige Strings mit dreifachem Anführungszeichen verwendet.
Nun verwenden wir das Zeichen ?, um diesen Docstring anzuzeigen:
In [7]: square?
Signature: square(a)
Docstring: Return the square of a.
File: <ipython-input-6>
Type: function
Dieser schnelle Zugriff auf die Dokumentation via Docstring ist einer der Gründe dafür, dass Sie sich angewöhnen sollten, den von Ihnen geschriebenen Code immer zu dokumentieren!
Da die Programmiersprache Python sehr leicht verständlich ist, können Sie für gewöhnlich tiefere Einblicke gewinnen, wenn Sie sich den Quellcode eines Objekts ansehen, das Sie interessiert. Mit einem doppelten Fragezeichen (??) stellen IPython und Jupyter eine Abkürzung für den Zugriff auf den Quellcode zur Verfügung:
In [8]: square??
Signature: square(a)
Source:
def square(a):
"""Return the square of a."""
return a ** 2
File: <ipython-input-6>
Type: function
Bei so einfachen Funktionen wie dieser können Sie mit dem doppelten Fragezeichen einen schnellen Blick darauf werfen, was unter der Haube vor sich geht.
Wenn Sie damit weiter herumexperimentieren, werden Sie feststellen, dass ein angehängtes ?? manchmal gar keinen Quellcode anzeigt. Das liegt im Allgemeinen daran, dass das fragliche Objekt nicht in Python implementiert ist, sondern in C oder einer anderen kompilierten Erweiterungssprache. In diesem Fall liefert ?? dieselbe Ausgabe wie ?. Das kommt insbesondere bei vielen in Python fest integrierten Objekten und Typen vor, wie beispielsweise bei der vorhin erwähnten Funktion len:
In [9]: len??
Signature: len(obj, /)
Docstring: Return the number of items in a container.
Type: builtin_function_or_method
Der Einsatz von ? und/oder ?? bietet eine schnelle und leistungsfähige Möglichkeit für das Auffinden von Informationen darüber, was in einer Python-Funktion oder einem Python-Modul eigentlich geschieht.
Eine weitere nützliche Schnittstelle ist die Verwendung der Tabulatortaste zur automatischen Vervollständigung und zum Erkunden des Inhalts von Objekten, Modulen und Namensräumen. In den folgenden Beispielen wird durch <TAB> angezeigt, dass die Tabulatortaste gedrückt werden muss.
Jedes Python-Objekt besitzt verschiedene Attribute und Methoden, die ihm zugeordnet sind. Neben dem bereits erläuterten help verfügt Python über eine integrierte dir-Funktion, die eine Liste dieser Attribute und Methoden ausgibt. Allerdings ist es in der Praxis viel einfacher, die Tab-Vervollständigung zu verwenden. Um eine Liste aller verfügbaren Attribute anzuzeigen, geben Sie einfach den Namen des Objekts ein, gefolgt von einem Punkt (.) und einem Druck auf die Tab-Taste:
In [10]: L.<TAB>
append() count insert reverse
clear extend pop sort
copy index remove
Um die Anzahl der Treffer in der Liste zu verringern, geben Sie einfach den ersten oder mehrere Buchstaben des Namens ein. Nach dem Drücken der Tab-Taste werden dann nur noch die übereinstimmenden Attribute und Methoden angezeigt:
In [10]: L.c<TAB>
clear() count()
copy()
In [10]: L.co<TAB>
copy() count()
Wenn der Treffer eindeutig ist, wird die Zeile durch ein weiteres Drücken der Tabulatortaste vervollständigt. Die folgende Eingabe wird beispielsweise sofort zu L.count vervollständigt:
In [10]: L.cou<TAB>
Python erzwingt zwar keine strenge Unterscheidung zwischen öffentlichen/externen und privaten/internen Attributen, allerdings gibt es die Konvention, Letztere durch einen vorangestellten Unterstrich zu kennzeichnen. Der Einfachheit halber werden die privaten und besonderen Methoden in der Liste standardmäßig weggelassen. Es ist jedoch möglich, sie durch ausdrückliche Eingabe des Unterstrichs anzuzeigen:
In [10]: L._<TAB>
__add__ __delattr__ __eq__
__class__ __delitem__ __format__()
__class_getitem__() __dir__() __ge__ >
__contains__ __doc__ __getattribute__
Wir zeigen hier nur kurz die ersten paar Zeilen der Ausgabe. Bei den meisten handelt es sich um Pythons spezielle Methoden, deren Namen mit einem doppelten Unterstrich beginnen (engl. double underscore, daher oft auch »dunder«-Methoden genannt).
Die Tab-Vervollständigung kann außerdem beim Importieren von Objekten aus Paketen helfen. Hier benutzen wir sie, um alle möglichen Importe aus dem Paket itertools zu finden, die mit der Zeichenkette co beginnen:
In [10]: from itertools import co<TAB>
combinations() compress()
combinations_with_replacement() count()
Auf ähnliche Weise können Sie die Tab-Vervollständigung einsetzen, um zu sehen, welche Importe auf Ihrem System verfügbar sind (das kann sich ändern, je nachdem, welche Skripte oder Module von Drittherstellern für Ihre Python-Sitzung sichtbar sind):
In [10]: import <TAB>
abc anyio
activate_this appdirs
aifc appnope >
antigravity argon2
In [10]: import h<TAB>
hashlib html
heapq http
hmac
Die Tab-Vervollständigung ist nützlich, wenn Ihnen die ersten paar Buchstaben des Namens eines Objekts oder Attributs bekannt sind, das Sie suchen, hilft aber nicht weiter, wenn Sie nach übereinstimmenden Zeichen in der Mitte oder am Ende einer Bezeichnung suchen. Für diesen Anwendungsfall halten IPython und Jupyter mit dem Zeichen * eine Suche mithilfe von Wildcards bereit.
Wir können das Zeichen beispielsweise verwenden, um alle Objekte im Namensraum anzuzeigen, deren Namen auf Warning enden:
In [10]: *Warning?
BytesWarning RuntimeWarning
DeprecationWarning SyntaxWarning
FutureWarning UnicodeWarning
ImportWarning UserWarning
PendingDeprecationWarning Warning
ResourceWarning
Beachten Sie, dass das Zeichen * mit allen Strings übereinstimmt – auch mit einer leeren Zeichenkette.
Nehmen wir nun an, wir suchten nach einer String-Methode, die an irgendeiner Stelle in ihrem Namen das Wort find enthält. Auf diese Weise können wir sie finden:
In [11]: str.*find*?
str.find
str.rfind
Ich finde diese Art der flexiblen Suche mit Wildcards äußerst nützlich, um einen bestimmten Befehl zu finden, wenn ich ein neues Paket erkunde oder mich mit einem bereits bekannten erneut vertraut mache.
Auch wenn Sie nur wenig Zeit mit einem Computer verbringen, werden Sie vermutlich bereits festgestellt haben, dass sich das eine oder andere Tastaturkürzel für Ihren Arbeitsablauf als nützlich erweist. Am bekanntesten sind vielleicht Strg-C und Strg-V (bzw. Cmd-C und Cmd-V) zum Kopieren und Einfügen in vielen ganz verschiedenen Programmen und Systemen. Erfahrene User gehen oft sogar noch einen Schritt weiter: Gängige Texteditoren wie Emacs, Vim und andere stellen einen immensen Umfang an verschiedenen Funktionen durch komplizierte Kombinationen von Tastendrücken zur Verfügung.
Ganz so weit geht die IPython-Shell nicht, dennoch bietet sie einige Tastaturkürzel zum schnellen Navigieren beim Eingeben von Befehlen. Einige der Tastaturkürzel funktionieren eventuell auch in browserbasierten Notebooks, allerdings geht es in diesem Abschnitt vornehmlich um die Tastaturkürzel in der IPython-Shell.
Sobald Sie sich daran gewöhnt haben, sind sie äußerst nützlich, um schnell bestimmte Befehle auszuführen, ohne die Hände von der Tastatur nehmen zu müssen. Sollten Sie Emacs-User sein oder Erfahrung mit Linux-Shells haben, wird Ihnen das Folgende bekannt vorkommen. Ich gruppiere die Befehle nach bestimmten Kategorien: Tastaturkürzel zum Navigieren, Tastaturkürzel bei der Texteingabe, Tastaturkürzel für den Befehlsverlauf und sonstige Tastaturkürzel.
Dass die nach links und rechts weisenden Pfeiltasten dazu dienen, den Cursor in der Zeile rückwärts bzw. vorwärts zu bewegen, ist ziemlich offensichtlich, es gibt jedoch weitere Möglichkeiten, die es nicht erforderlich machen, Ihre Hände aus der gewohnten Schreibposition zu bewegen.
Tastaturkürzel
Beschreibung
Strg-A
Bewegt den Cursor an den Zeilenanfang.
Strg-E
Bewegt den Cursor an das Zeilenende.
Strg-B (oder Pfeiltaste nach links)
Bewegt den Cursor ein Zeichen rückwärts.
Strg-F (oder Pfeiltaste nach rechts)
Bewegt den Cursor ein Zeichen vorwärts.
Jeder Nutzerin und jedem Nutzer ist die Verwendung der Rückschritttaste zum Löschen des zuvor eingegebenen Zeichens bekannt, allerdings sind oftmals einige Fingerverrenkungen erforderlich, um sie zu erreichen, und außerdem löscht sie beim Drücken jeweils nur ein einzelnes Zeichen. In IPython gibt es einige Tastaturkürzel zum Löschen bestimmter Teile der eingegebenen Textzeile. Sofort nützlich sind die Befehle zum Löschen der ganzen Textzeile. Sie sind Ihnen in Fleisch und Blut übergegangen, wenn Sie feststellen, dass Sie die Tastenkombinationen Strg-B und Strg-D verwenden, anstatt die Rückschritttaste zu benutzen, um das zuvor eingegebene Zeichen zu löschen!
Tastaturkürzel
Beschreibung
Rückschritttaste
Zeichen links vom Cursor löschen.
Strg-D
Zeichen rechts vom Cursor löschen.
Strg-K
Text von der Cursorposition bis zum Zeilenende ausschneiden.
Strg-U
Text vom Zeilenanfang bis zur Cursorposition ausschneiden.
Strg-Y
Zuvor ausgeschnittenen Text einfügen.
Strg-T
Die beiden zuletzt eingegebenen Zeichen vertauschen.
Unter den hier aufgeführten von IPython bereitgestellten Tastaturkürzeln dürften diejenigen zur Navigation im Befehlsverlauf die größten Auswirkungen haben. Der Befehlsverlauf umfasst nicht nur die aktuelle IPython-Sitzung, Ihr gesamter Befehlsverlauf ist in einer SQLite-Datenbank im selben Verzeichnis gespeichert, in dem sich auch Ihr IPython-Profil befindet.
Die einfachste Zugriffsmöglichkeit auf Ihren Befehlsverlauf ist das Betätigen der Pfeiltasten nach oben und unten, mit denen Sie ihn schrittweise durchblättern können, es stehen aber noch andere Möglichkeiten zur Verfügung.
Tastaturkürzel
Beschreibung
Strg-P (oder Pfeiltaste nach oben)
Vorhergehenden Befehl im Verlauf auswählen.
Strg-N (oder Pfeiltaste nach unten)
Nachfolgenden Befehl im Verlauf auswählen.
Strg-R
Rückwärtssuche im Befehlsverlauf.
Die Rückwärtssuche kann besonders praktisch sein. Wie Sie wissen, haben wir im vorherigen Abschnitt eine Funktion namens square definiert. Durchsuchen Sie nun in einer neuen IPython-Shell den Befehlsverlauf nach dieser Definition. Wenn Sie im IPython-Terminal die Tastenkombination Strg-R drücken, wird Ihnen die folgende Eingabeaufforderung angezeigt:
In [1]:
(reverse-i-search)`':
Beginnen Sie nun damit, Zeichen einzugeben, zeigt IPython den zuletzt eingegebenen Befehl an (sofern vorhanden), der mit den eingegebenen Zeichen übereinstimmt:
In [1]:
(reverse-i-search)`squ': square??
Sie können jederzeit weitere Zeichen eingeben, um die Suche zu verfeinern, oder drücken Sie erneut Strg-R, um nach einem weiter zurückliegenden Befehl zu suchen, der zur Suchanfrage passt. Wenn Sie die Eingaben im letzten Abschnitt nachvollzogen haben, wird nach zweimaligem Betätigen von Strg-R Folgendes angezeigt:
In [1]:
(reverse-i-search)`squ': def square(a):
"""Return the square of a"""
return a ** 2
Sobald Sie den gesuchten Befehl gefunden haben, beenden Sie die Suche mit der Enter-Taste. Jetzt können Sie den gefundenen Befehl ausführen und die Sitzung fortsetzen:
In [1]: def square(a):
"""Return the square of a"""
return a ** 2
In [2]: square(2)
Out[2]: 4
Sie können auch die Tastenkombinationen Strg-P/Strg-N oder die Pfeiltasten nach oben und unten verwenden, um den Befehlsverlauf zu durchsuchen, allerdings werden dann bei der Suche lediglich die Zeichen am Anfang der Eingabezeile berücksichtigt. Wenn Sie also def eingeben und dann Strg-P drücken, wird der zuletzt eingegebene Befehl im Verlauf angezeigt (falls vorhanden), der mit den Zeichen def beginnt.
Darüber hinaus gibt es einige weitere nützliche Tastaturkürzel, die sich keiner der bisherigen Kategorien zuordnen lassen.
Tastaturkürzel
Beschreibung
Strg-L
Terminalanzeige löschen.
Strg-C
Aktuellen Python-Befehl abbrechen.
Strg-D
Python-Sitzung beenden.
Insbesondere der Befehl Strg-C kann sich als nützlich erweisen, wenn Sie versehentlich einen sehr zeitaufwendigen Job gestartet haben.
Einige der hier vorgestellten Befehle mögen auf den ersten Blick vielleicht uninteressant erscheinen, Sie werden sie aber mit etwas Übung wie im Schlaf verwenden. Haben Sie sich diese Fingerfertigkeiten einmal angeeignet, werden Sie sich sogar wünschen, dass diese Befehle auch an anderer Stelle zur Verfügung stünden.
Ein großer Teil der Leistungsfähigkeit von IPython und Jupyter wird durch ihre zusätzlichen interaktiven Werkzeuge erreicht. In diesem Kapitel werden einige dieser Werkzeuge behandelt, darunter die sogenannten »magischen« Befehle. Dies sind Werkzeuge zur Untersuchung des Ein- und Ausgabeverlaufs und zur Interaktion mit der Shell.
Das vorherige Kapitel zeigt, wie IPython es Ihnen ermöglicht, Python effektiv und interaktiv zu verwenden und zu erkunden. Nun kommen wir zu einigen Erweiterungen, die IPython der normalen Python-Syntax hinzufügt. Diese werden in IPython als magische Befehle oder Funktionen bezeichnet, und ihnen wird ein %-Zeichen vorangestellt. Die magischen Befehle sind dazu gedacht, verschiedene gängige Aufgaben, die bei einer Standarddatenanalyse immer wieder vorkommen, kurz und bündig zu erledigen. Von den magischen Befehlen/Funktionen (den sogenannten Magics) gibt es zwei Varianten: Line-Magics, denen ein einzelnes % vorangestellt wird und die jeweils eine einzelne Zeile verarbeiten, sowie Cell-Magics, die durch ein vorangestelltes %% gekennzeichnet sind und mehrzeilige Eingaben verarbeiten. Wir werden einige kurze Beispiele betrachten und befassen uns dann später mit einer eingehenderen Erläuterung verschiedener nützlicher magischer Befehle.
Wenn Sie damit anfangen, umfangreicheren Code zu entwickeln, werden Sie vermutlich feststellen, dass Sie sowohl IPython für interaktive Erkundungen als auch einen Texteditor zum Speichern von Code einsetzen, den Sie wiederverwenden möchten. Oft ist es praktisch, den Code nicht in einem neuen Fenster, sondern innerhalb der laufenden IPython-Sitzung auszuführen. Zu diesem Zweck gibt es den magischen Befehl %run.
Nehmen wir beispielsweise an, Sie hätten eine Datei namens myscript.py angelegt, die folgenden Inhalt hat:
# file: myscript.py
def square(x):
"""square a number"""
return x ** 2
for N in range(1, 4):
print(f"{N} squared is {square(N)}")
Sie können dies wie folgt in Ihrer IPython-Sitzung ausführen:
In [1]: %run myscript.py
1 squared is 1
2 squared is 4
3 squared is 9
Beachten Sie hier außerdem, dass nach der Ausführung dieses Skripts die darin definierten Funktionen in Ihrer IPython-Sitzung verfügbar sind:
In [2]: square(5)
Out[2]: 25
Es stehen verschiedene Möglichkeiten zur Verfügung, genauer einzustellen, wie Ihr Code ausgeführt wird. Sie können sich durch die Eingabe von %run? wie gewohnt die Dokumentation im IPython-Interpreter anzeigen lassen.
Ein weiteres Beispiel einer nützlichen magischen Funktion ist %timeit, die automatisch die Ausführungszeit einer einzeiligen Python-Anweisung ermittelt, die dem Befehl übergeben wird. Wir könnten beispielsweise die Performance einer Listenabstraktion wie folgt ermitteln:
Die %timeit-Funktion hat den Vorteil, dass sie bei kurzen Befehlen automatisch mehrere Durchläufe ausführt, um aussagekräftigere Ergebnisse zu erhalten. Bei mehrzeiligen Anweisungen macht das Hinzufügen eines zweiten %-Zeichens den Befehl zu einem Cell-Magic, das mehrzeilige Eingaben verarbeiten kann. Dies ist beispielsweise der entsprechende Code mit einer for-Schleife:
Wir können sofort feststellen, dass die Listenabstraktion in diesem Fall rund 10% schneller ist als die entsprechende for-Schleife. Wir werden uns mit %timeit und anderen Ansätzen für das Timing und Profiling von Code im Abschnitt »Profiling und Timing von Code« auf Seite 45 noch eingehender befassen.
Wie normale Python-Funktion besitzen auch IPythons magische Funktionen Docstrings, und auf diese nützliche Dokumentation kann man wie gewohnt zugreifen. Um also beispielsweise die Dokumentation des magischen Befehls %timeit zu lesen, geben Sie einfach Folgendes ein:
In [5]: %timeit?
Auf die Dokumentation anderer Funktionen wird auf ähnliche Weise zugegriffen. Zur Anzeige einer allgemeinen Beschreibung der verfügbaren magischen Funktionen inklusive einiger Beispiele geben Sie nachstehenden Befehl ein:
In [6]: %magic
Und so zeigen Sie schnell und einfach eine Liste aller zur Verfügung stehenden magischen Funktionen an:
In [7]: %lsmagic
Abschließend möchte ich noch erwähnen, dass es ganz einfach möglich ist, eigene magische Funktionen zu definieren. Wir werden darauf an dieser Stelle nicht weiter eingehen, aber wenn Sie daran interessiert sind, werfen Sie einen Blick auf die Hinweise im Abschnitt »Weitere IPython-Ressourcen« auf Seite 50.
Sie wissen bereits, dass die IPython-Shell es ermöglicht, mit den Pfeiltasten nach oben und unten (oder mit den entsprechenden Tastaturkürzeln Strg-P/Strg-N auf frühere Befehle zuzugreifen. Sowohl in der Shell als auch in Notebooks bietet IPython darüber hinaus verschiedene Möglichkeiten, die Ausgabe vorhergehender Befehle oder reine Textversionen der Befehle selbst abzurufen. Das sehen wir uns nun genauer an.
Die von IPython verwendeten Ausgaben der Form In [1]:/Out[1]: dürften Ihnen inzwischen hinlänglich vertraut sein. Dabei handelt es sich jedoch keinesfalls nur um hübsche Verzierungen, vielmehr geben sie einen Hinweis darauf, wie Sie auf vorhergehende Ein- und Ausgaben Ihrer aktuellen Sitzung zugreifen können. Nehmen wir an, Sie starten eine Sitzung, die folgendermaßen aussieht:
In [1]: import math
In [2]: math.sin(2)
Out[2]: 0.9092974268256817
In [3]: math.cos(2)
Out[3]: -0.4161468365471424
Wir haben das integrierte math-Paket importiert und dann den Sinus und den Kosinus von 2 berechnet. Diese Ein- und Ausgaben werden in der Shell mit In/Out-Labels angezeigt. Das ist jedoch noch nicht alles – tatsächlich erzeugt IPython verschiedene Python-Variablen namens In und Out, die automatisch aktualisiert werden und so den Verlauf widerspiegeln:
In [4]: In
Out[4]: ['', 'import math', 'math.sin(2)', 'math.cos(2)', 'In']
In [5]: Out
Out[5]:
{2: 0.9092974268256817,
3: -0.4161468365471424,
4: ['', 'import math', 'math.sin(2)', 'math.cos(2)', 'In', 'Out']}
Das In-Objekt ist eine Liste, die über die Reihenfolge der Befehle Buch führt (das erste Element der Liste ist ein Platzhalter, sodass In[1] auf den ersten Befehl verweist):
In [6]: print(In[1])
import math
Das Out-Objekt hingegen ist keine Liste, sondern ein Dictionary, in dem die Eingabenummern den jeweiligen Ausgaben (falls vorhanden) zugeordnet sind:
In [7]: print(Out[2])
.9092974268256817
Beachten Sie hier, dass nicht alle Operationen eine Ausgabe erzeugen. Beispielsweise haben die import- und print-Anweisungen keine Auswirkung auf die Ausgabe. Letzteres überrascht vielleicht etwas, ergibt jedoch Sinn, wenn man bedenkt, dass print eine Funktion ist, die None zurückliefert. Kurz und bündig: Alle Befehle, die None zurückgeben, werden nicht zum Out-Dictionary hinzugefügt.
Das kann sich als nützlich erweisen, wenn Sie die letzten Ergebnisse verwenden möchten. Berechnen Sie beispielsweise die Summe von sin(2) ** 2 und cos(2) ** 2 unter Zuhilfenahme der zuvor errechneten Ergebnisse:
In [8]: Out[2] ** 2 + Out[3] ** 2
Out[8]: 1.0
Das Ergebnis lautet 1.0, wie es gemäß der wohlbekannten trigonometrischen Gleichung auch zu erwarten ist. In diesem Fall wäre es eigentlich gar nicht notwendig, die vorhergehenden Ergebnisse zu verwenden, allerdings kann es ungemein praktisch sein, wenn Sie eine sehr zeitaufwendige Berechnung ausführen und vergessen, das Ergebnis einer Variablen zuzuweisen!
Die normale Python-Shell besitzt nur eine einfache Abkürzung für den Zugriff auf vorherige Ausgaben. Die Variable _ enthält das Ergebnis der jeweils letzten Ausgabe. In IPython funktioniert das ebenfalls:
In [9]: print(_)
.0
Allerdings geht IPython noch einen Schritt weiter – Sie können außerdem einen doppelten Unterstrich verwenden, um auf die vorletzte Ausgabe zuzugreifen, oder einen dreifachen, um auf die drittletzte Ausgabe zuzugreifen (wobei alle Befehle ohne Ausgabe übersprungen werden):
In [10]: print(__)
-0.4161468365471424
In [11]: print(___)
.9092974268256817
Hier ist in IPython jedoch Schluss: Mehr als drei Unterstriche sind etwas schwierig abzuzählen, und es ist einfacher, die Nummer der Ausgabe zu verwenden.
Eine weitere Abkürzung soll an dieser Stelle noch Erwähnung finden: _X (ein einfacher Unterstrich, gefolgt von der Ausgabenummer) ist die Abkürzung für Out[X]:
In [12]: Out[2]
Out[12]: 0.9092974268256817
In [13]: _2
Out[13]: 0.9092974268256817
Manchmal ist es erwünscht, die Ausgaben einer Anweisung zu unterdrücken (am häufigsten kommt das vielleicht bei den Befehlen zum Erstellen von Diagrammen vor, mit denen wir uns in Teil IV befassen werden). Oder der auszuführende Befehl liefert ein Ergebnis, das Sie lieber nicht im Verlauf der Ausgabe speichern möchten, möglicherweise damit der dadurch belegte Speicherplatz wieder freigegeben wird, wenn es keine weiteren Referenzen mehr darauf gibt. Die einfachste Methode zum Unterdrücken der Ausgabe ist das Anhängen eines Semikolons an das Zeilenende:
In [14]: math.sin(2) + math.cos(2);
Beachten Sie hier, dass das Ergebnis zwar berechnet, aber weder auf dem Bildschirm angezeigt noch im Out-Dictionary gespeichert wird:
In [15]: 14 in Out
Out[15]: False
Mit dem magischen Befehl %history kann man auf mehrere vorhergehende Eingaben gleichzeitig zugreifen. So können Sie die ersten vier Eingaben anzeigen:
In [16]: %history -n 1-3
1: import math
2: math.sin(2)
3: math.cos(2)
Sie können wie gewohnt %history? eingeben, um weitere Informationen und eine Beschreibung der möglichen Optionen anzuzeigen. (Zusätzliche Details zur Funktionsweise von ? finden Sie in Kapitel 1.) Weitere nützliche magische Befehle sind %rerun (erneute Ausführung eines Teils des Befehlsverlaufs) und %save (zum Speichern eines Teils des Befehlsverlaufs in einer Datei).
Wenn man einen normalen Python-Interpreter interaktiv verwendet, muss man sich damit herumärgern, dass man gezwungen ist, zwischen mehreren Fenstern hin und her zu schalten, um auf Python-Tools und Kommandozeilenprogramme des Systems zuzugreifen. IPython schließt diese Lücke und stellt eine Syntax zum Ausführen von Shell-Befehlen direkt im IPython-Terminal bereit. Möglich macht das ein Ausrufezeichen: Jeglicher nach einem ! stehender Text in einer Zeile wird nicht vom Python-Kernel, sondern von der Kommandozeile des Systems ausgeführt.
Im Folgenden wird vorausgesetzt, dass Sie ein unixoides System wie Linux oder macOS verwenden. Einige der Beispiele würden unter Windows fehlschlagen, das standardmäßig eine andere Art von Shell verwendet. Wenn Sie allerdings das Windows Subsystem for Linux (https://oreil.ly/H5MEE) verwenden, sollten die Beispiele korrekt ausgeführt werden. Sind Ihnen Shell-Befehle nicht geläufig, empfiehlt sich die Lektüre des Unix Shell-Tutorials (https://oreil.ly/RrD2Y), das von der ausgezeichneten Software Carpentry Foundation zusammengestellt wurde.
Eine vollständige Einführung in die Arbeit mit Shell, Terminal oder Kommandozeile geht weit über den Rahmen dieses Kapitels hinaus. An dieser Stelle folgt lediglich eine Kurzeinführung für diejenigen, die über gar keine Kenntnisse auf diesem Gebiet verfügen. Die Shell bietet eine Möglichkeit, per Texteingabe mit dem Computer zu interagieren. Seit Mitte der 1980er-Jahre, als Apple und Microsoft die ersten Versionen der heute allgegenwärtigen grafischen Betriebssysteme vorstellten, interagieren die meisten User mit ihrem Betriebssystem durch die vertraute Auswahl von Menüpunkten und durch Verschieben von Objekten mit der Maus. Nun gab es jedoch schon viel früher, lange bevor die grafischen Benutzeroberflächen entwickelt wurden, Betriebssysteme, die vornehmlich durch Texteingaben gesteuert wurden: Der User gibt auf der Kommandozeile einen Befehl ein, und der Computer führt aus, was der User ihm befohlen hat. Diese ersten Kommandozeilensysteme waren die Vorgänger der Shells und Terminals, die viele Data Scientists auch heute noch verwenden.
Wenn man mit der Shell nicht vertraut ist, mag man fragen, warum man sich diese Mühe machen sollte, wenn man doch mit ein paar Mausklicks auf Symbole und Menüs schon so viel erreichen kann. Ein Shell-User könnte mit einer Gegenfrage antworten: Warum irgendwelchen Symbolen nachjagen und Menüpunkte anklicken, wenn man seine Ziele durch Texteingaben viel einfacher erreichen kann? Zunächst hört sich das nach einer dieser typischen Pattsituationen zweier Lager mit unterschiedlichen Präferenzen an. Wenn jedoch mehr als nur grundlegende Arbeiten zu erledigen sind, wird schnell deutlich, dass die Shell bei anspruchsvolleren Aufgaben viel mehr Steuerungsmöglichkeiten bietet, wenngleich die Lernkurve zugegebenermaßen einschüchtern kann.
Nachstehend finden Sie als Beispiel eine Linux/macOS-Shell-Sitzung, in der ein User Dateien und Verzeichnisse auf dem System erkundet, anlegt und modifiziert (osx:~ $ ist die Eingabeaufforderung, und alles hinter dem $ ist der eingegebene Befehl; die Texte, denen ein # vorausgeht, sind lediglich Beschreibungen und müssen nicht eingetippt werden):
Wie Sie sehen, handelt es sich hier lediglich um eine kompakte Art und Weise, gängige Operationen (Navigieren in einer Verzeichnisstruktur, Anlegen eines Verzeichnisses, Datei verschieben usw.) durch die Eingabe von Befehlen auszuführen, statt Symbole und Menüs anzuklicken. Beachten Sie, dass sich die gebräuchlichsten Dateioperationen mit einigen wenigen Befehlen (pwd, ls, cd, mkdir und cp) erledigen lassen. Die wahre Leistungsfähigkeit der Shell zeigt sich vor allem aber dann, wenn man anspruchsvollere als diese grundlegenden Aufgaben erledigen möchte.
Sie können sämtliche Standardbefehle der Kommandozeile direkt in IPython verwenden, indem Sie ihnen ein !-Zeichen voranstellen. So können die Befehle ls, pwd und echo beispielsweise folgendermaßen ausgeführt werden:
In [1]: !ls
myproject.txt
In [2]: !pwd
/home/jake/projects/myproject
In [3]: !echo "printing from the shell"
printing from the shell
Diese Ergebnisse werden nicht als Liste zurückgegeben, sondern als ein in IPython definierter spezieller Rückgabetyp für Shells:
In [8]: type(directory)
IPython.utils.text.SList
Dieser Typ sieht zwar wie eine Python-Liste aus und verhält sich auch sehr ähnlich, verfügt aber über zusätzliche Funktionalität, wie z.B. über die grep- und fields-Methoden sowie die Eigenschaften s, n und p, die es Ihnen erlauben, die Ergebnisse auf komfortable Art und Weise zu durchsuchen, zu filtern und anzuzeigen. Weitere Informationen dazu finden Sie in IPythons integrierter Hilfefunktion.
Die Kommunikation in der anderen Richtung, also die Übergabe von Python an die Shell, wird durch die Verwendung der Syntax {varname} ermöglicht:
Der Variablenname wird von den geschweiften Klammern eingeschlossen und wird im Shell-Befehl durch den Inhalt der Variablen ersetzt.
Wenn Sie ein Weilchen mit IPythons Shell-Befehlen herumexperimentiert haben, ist Ihnen vielleicht aufgefallen, dass es nicht möglich ist, mit !cd im Dateisystem zu navigieren:
In [11]: !pwd
/home/jake/projects/myproject
In [12]: !cd ..
In [13]: !pwd
/home/jake/projects/myproject
Das liegt daran, dass die Shell-Befehle in einem Notebook in einer temporären Subshell ausgeführt werden, die den Zustand von Befehl zu Befehl nicht beibehält. Wenn Sie das Arbeitsverzeichnis dauerhaft ändern möchten, steht Ihnen dafür der magische Befehl %cd zur Verfügung:
In [14]: %cd ..
/home/jake/projects
Tatsächlich können Sie den Befehl standardmäßig sogar ohne das %-Zeichen aufrufen:
In [15]: cd myproject
/home/jake/projects/myproject
Man spricht hier von einer automagischen Funktion, deren Verhalten mit der magischen Funktion %automagic geändert werden kann.
Neben %cd gibt es für die Shell noch die magischen Funktionen %cat, %cp, %env, %ls, %man, %mkdir, %more, %mv, %pwd, %rm und %rmdir, die alle auch ohne das %-Zeichen verwendbar sind, sofern automagic eingeschaltet ist. Auf diese Weise können Sie die Kommandozeile in IPython fast wie eine normale Shell verwenden:
In [16]: mkdir tmp
In [17]: ls
myproject.txt tmp/
In [18]: cp myproject.txt tmp/
In [19]: ls tmp
myproject.txt
In [20]: rm -r tmp
Dieser Zugriff auf die Shell im selben Terminalfenster, in dem Ihre Python-Sitzung läuft, bedeutet für Sie beim Schreiben von Python-Code, dass Sie sehr viel weniger vom Interpreter zur Shell und wieder zurück wechseln müssen.
Zusätzlich zu den fortgeschrittenen interaktiven Werkzeugen, die im vorherigen Kapitel besprochen wurden, bietet Jupyter eine Reihe von Möglichkeiten, den ausgeführten Code zu untersuchen und zu verstehen, beispielsweise durch das Auffinden von Fehlern in der Logik oder einer unerwartet langsamen Ausführung. Dieses Kapitel stellt einige dieser Werkzeuge vor.
Bei der Entwicklung von Code und der Datenanalyse spielen auch Versuch und Irrtum immer eine gewisse Rolle. IPython bringt einige Tools mit, um diesen Vorgang zu optimieren. In diesem Abschnitt werden wir uns kurz mit einigen Optionen zur Konfiguration der Fehlerberichterstattung (Exceptions) in IPython befassen. Anschließend erkunden wir die Tools für das Debuggen von Fehlern im Code.
Wenn ein Python-Skript fehlschlägt, wird in den meisten Fällen eine Exception ausgelöst. Trifft der Interpreter auf eine solche Exception, finden sich Informationen über die Fehlerursache im sogenannten Traceback, auf das Sie von Python aus zugreifen können. Mit der magischen Funktion %xmode erhalten Sie von IPython die Möglichkeit, den Umfang der Informationen festzulegen, die ausgegeben werden, wenn eine Exception ausgelöst wird. Betrachten Sie den folgenden Code:
Der Aufruf von func2 verursacht einen Fehler, und im Traceback können wir genau sehen, was passiert ist. Standardmäßig enthält das Traceback einige Zeilen, die den Kontext der einzelnen Schritte zeigen, die zu dem Fehler geführt haben. Mit der magischen Funktion %xmode (kurz für exception mode) können wir ändern, welche Informationen ausgegeben werden.
%xmode benötigt ein einzelnes Argument, den Modus, für den es drei mögliche Werte gibt: Plain, Context und Verbose. Voreingestellt ist der Modus Context, der zu der obigen Ausgabe führt. Der Modus Plain sorgt für eine kompaktere Ausgabe und liefert weniger Informationen:
In [3]: %xmode Plain
Out[3]: Exception reporting mode: Plain
In [4]: func2(1)
Traceback (most recent call last):
File "<ipython-input-4-b2e110f6fc8f>", line 1, in <module>
func2(1)
File "<ipython-input-1-d849e34d61fb>", line 7, in func2
return func1(a, b)
File "<ipython-input-1-d849e34d61fb>", line 2, in func1
return a / b
ZeroDivisionError: division by zero
Im Modus Verbose werden einige zusätzliche Informationen ausgegeben, unter anderem die Argumente aller aufgerufenen Funktionen:
Diese zusätzlichen Informationen können Ihnen dabei helfen, einzugrenzen, warum eine Exception ausgelöst wird. Warum also nicht immer den Verbose-Modus nutzen? Wenn der Code komplizierter ist, kann diese Art des Tracebacks extrem umfangreich werden. Je nach Kontext lässt es sich manchmal besser mit der Knappheit des Plain- oder des Context-Modus arbeiten.
Das Standardtool für interaktives Debuggen ist pdb, der Python-Debugger. Mit diesem Debugger kann der User den Code Zeile für Zeile durchlaufen, um zu prüfen, was einen schwer zu findenden Fehler verursachen könnte. Die erweiterte IPython-Version heißt ipdb, das ist der IPython-Debugger.
Es gibt viele verschiedene Möglichkeiten, diese beiden Debugger zu starten und einzusetzen, die wir an dieser Stelle jedoch nicht vollständig abhandeln werden. Nutzen Sie die Onlinedokumentationen dieser beiden Hilfsprogramme, wenn Sie mehr erfahren möchten.
In IPython ist der magische Befehl %debug wohl die komfortabelste Debugging-Schnittstelle. Wenn Sie ihn aufrufen, nachdem eine Exception ausgelöst wurde, wird automatisch eine interaktive Kommandozeile geöffnet, und zwar an der Stelle, an der die Exception aufgetreten ist. Mit der ipdb-Kommandozeile können Sie den aktuellen Zustand des Stacks untersuchen, die Werte der verfügbaren Variablen anzeigen und sogar Python-Befehle ausführen!
Sehen wir uns also die letzte Exception einmal etwas genauer an. Wir führen einige grundlegende Aufgaben aus, nämlich die Ausgabe der Werte von a und b, und beenden die Debugging-Sitzung anschließend durch Eingabe von quit.
In [7]: %debug <ipython-input-1-d849e34d61fb>(2)func1()
1 def func1(a, b):
----> 2 return a / b
3
ipdb> print(a)
1
ipdb> print(b)
0
ipdb> quit
Der interaktive Debugger kann jedoch viel mehr als das – wir können sogar im Stack hinauf- und herabsteigen und die Werte der dort verfügbaren Variablen untersuchen:
Auf diese Weise können Sie nicht nur schnell herausfinden, was den Fehler verursacht hat, sondern auch, welche Funktionsaufrufe zu dem Fehler führten.
Wenn der Debugger automatisch starten soll, sobald eine Exception ausgelöst wird, nutzen Sie die magische Funktion %pdb, um dieses Verhalten zu aktivieren:
In [9]: %xmode Plain
%pdb on
func2(1)
Exception reporting mode: Plain
Automatic pdb calling has been turned ON
ZeroDivisionError: division by zero <ipython-input-1-d849e34d61fb>(2)func1()
1 def func1(a, b):
----> 2 return a / b
3
ipdb> print(b)
0
ipdb> quit
Und wenn Sie ein Skript von Anfang an im interaktiven Modus ausführen möchten, starten Sie es mit dem Befehl %run -d, Sie können dann mit dem Befehl next die Codezeilen schrittweise interaktiv durchlaufen.
Es sind deutlich mehr Befehle für den interaktiven Debugger verfügbar, als ich hier gezeigt habe. Tabelle 3-1 enthält eine kurze Beschreibung einiger der gebräuchlicheren Befehle.
Tabelle 3-1: Eine (unvollständige) Liste der Debugging-Befehle
Befehl
Beschreibung
l(ist)
Anzeige der aktuellen Position in der Datei.
h(elp)
Liste der Befehle oder Hilfe für einen bestimmten Befehl anzeigen.
q(uit)
Debugger und Programm beenden.
c(ontinue)
Den Debugger beenden und das Programm weiter ausführen.
n(ext)
Mit dem nächsten Schritt des Programms fortfahren.
<enter>
Den vorherigen Befehl wiederholen.
p(rint)
Variablen ausgeben.
s(tep)
In eine Subroutine springen.
r(eturn)
Aus einer Subroutine zurückkehren.
Verwenden Sie den help-Befehl im Debugger, um weitere Informationen aufzurufen, oder werfen Sie einen Blick in die Onlinedokumentation (https://oreil.ly/TVSAT) zu ipdb.
Bei der Entwicklung des Codes und der Erstellung von Datenverarbeitungspipelines muss man sich häufig zwischen verschiedenen Implementierungen entscheiden. In der Frühphase der Entwicklung eines Algorithmus kann es jedoch kontraproduktiv sein, sich darüber schon Gedanken zu machen. Oder wie Donald Knuth bekanntermaßen geistreich anmerkte: »Wir sollten es in vielleicht 97% aller Fälle bleiben lassen, uns mit winzigen Verbesserungen zu befassen: Verfrühte Optimierung ist die Wurzel allen Übels.«
Sobald der Code jedoch funktioniert, kann es durchaus sinnvoll sein, die Effizienz zu überprüfen. Manchmal erweist es sich als nützlich, die Ausführungszeit eines bestimmten Befehls oder einer Befehlsfolge zu messen. In anderen Fällen ist es hilfreich, mehrzeilige Codeabschnitte zu untersuchen und herauszufinden, an welcher Stelle es in einer komplizierten Abfolge von Operationen zu einem Engpass kommt. IPython bietet eine Vielzahl von Funktionen für diese Art des Timings und Profilings von Code. Im Folgenden betrachten wir die nachstehenden magischen Befehle in IPython:
%time
Die Ausführungszeit einer einzelnen Anweisung messen.
%timeit
Die Ausführungszeit einer einzelnen Anweisung mehrfach messen, um aussagekräftigere Ergebnisse zu erhalten.
%prun
Code mit dem Profiler ausführen.
%lprun
Code mit dem Profiler zeilenweise ausführen.
%memit
Den Speicherbedarf einer einzelnen Anweisung messen.
%mprun
Code mit dem Memory-Profiler zeilenweise ausführen.
Die letzten vier dieser Befehle sind nicht Bestandteil von IPython – Sie müssen die Erweiterungen line_profiler und memory_profiler installieren, die wir in den nächsten Abschnitten eingehender betrachten.
Im Abschnitt »Magische Befehle in IPython« auf Seite 31 haben Sie das Line-Magic %timeit und das Cell-Magic %%timeit bereits kennengelernt. Mit beiden kann die für die wiederholte Ausführung einer Anweisung erforderliche Zeit gemessen werden:
In [1]: %timeit sum(range(100))
