Maschinelles Lernen und neuronale Netze - Seite 67

 

2.4 Big O von K-nächsten Nachbarn (L02: Methoden des nächsten Nachbarn)



2.4 Big O von K-nächsten Nachbarn (L02: Methoden des nächsten Nachbarn)

Lassen Sie uns nun in das Thema der Laufzeitkomplexität eintauchen und uns dabei insbesondere auf die Big-O-Notation und die Laufzeitkomplexität des KNN-Algorithmus (k-nearest neighbors) konzentrieren.

Die Big-O-Notation ist ein Konzept, das in der Informatik zur Analyse der Effizienz von Algorithmen verwendet wird. Es bezieht sich in erster Linie auf die Laufzeitkomplexität, die bestimmt, wie sich die Ausführungsgeschwindigkeit eines Algorithmus mit zunehmender Eingabegröße verhält. Darüber hinaus kann die Big-O-Notation auch verwendet werden, um die Speichereffizienz eines Algorithmus zu analysieren und die für seine Ausführung erforderliche Speichermenge anzugeben.

Im Fall von KNN umfasst der Trainingsschritt das Speichern des Trainingsdatensatzes, was speicherintensiv sein kann. Das Speichern eines großen Trainingsdatensatzes erfordert möglicherweise eine erhebliche Menge an RAM oder Festplattenspeicher. Auch wenn der Speicherplatz im Laufe der Zeit günstiger geworden ist, kann er bei der Verarbeitung großer Datenmengen, beispielsweise Millionen von Bildern, immer noch zu Einschränkungen führen.

Lassen Sie uns jedoch während des Vorhersageschritts unseren Fokus auf die Laufzeitkomplexität von KNN verlagern. Bevor wir fortfahren, wollen wir kurz die Big-O-Notation vorstellen. Dabei handelt es sich um eine Notation zur Beschreibung der Effizienz von Algorithmen, die typischerweise durch Funktionen bezeichnet wird. Diese Funktionen stellen die Laufzeitkomplexität von Algorithmen dar. Häufige Beispiele sind O(1) (konstant), O(log n) (logarithmisch) usw. Diese Funktionen geben an, wie die Laufzeit eines Algorithmus mit der Eingabegröße (n) skaliert.

Um ein besseres Verständnis der Laufzeitkomplexität zu erlangen, können wir die Funktionen in aufsteigender Effizienzreihenfolge anordnen, von O(1) bis zur exponentiellen Komplexität. In diesem Zusammenhang ist eine konstante Funktion ideal, da sie von der Eingabegröße unbeeinflusst bleibt und eine konstante Ausführungsgeschwindigkeit gewährleistet. Logarithmische und lineare Funktionen sind ebenfalls effizient, wenn auch nicht so ideal wie konstante Funktionen. Wenn jedoch die Komplexität zu quadratisch, kubisch und exponentiell zunimmt, verschlechtert sich die Effizienz des Algorithmus erheblich. Exponentielle Komplexität ist besonders schädlich und sollte vermieden werden, insbesondere beim Umgang mit großen Datensätzen beim maschinellen Lernen.

Um die Laufzeitkomplexität in Bezug auf n (Eingabegröße) zu visualisieren, kann ein Diagramm erstellt werden, in dem die x-Achse n und die y-Achse die Komplexität des Algorithmus darstellt. Mit zunehmendem n weisen bestimmte Funktionen eine zunehmend schlechtere Leistung auf. Algorithmen mit hoher Komplexität, wie etwa quadratische, kubische oder exponentielle Algorithmen, sind unbedingt zu vermeiden, da diese zu übermäßig langen Ausführungszeiten führen können.

Lassen Sie uns nun untersuchen, wie wir die Big-O-Notation für eine bestimmte Funktion ableiten. Betrachten Sie beispielsweise eine quadratische Funktion f(x) = ax^2 + bx + c. Bei der Ableitung der Big-O-Notation konzentrieren wir uns auf den dominanten Term, der am schnellsten wächst. In diesem Fall ist der dominante Term x^2. Daher wäre die Big-O-Notation für diese Funktion O(x^2), was quadratische Komplexität anzeigt.

Betrachten wir eine weitere Funktion, um diesen Prozess weiter zu veranschaulichen. Angenommen, wir haben eine Funktion f(x) = ax(log x). Auch hier identifizieren wir den dominanten Term, nämlich x(log x). Hier ignorieren wir den konstanten Faktor a und konzentrieren uns auf den Term x(log x). Folglich wäre die Big-O-Notation für diese Funktion O(x log x), was auf logarithmisch-lineare Komplexität hinweist.

Es ist erwähnenswert, dass die Basis des Logarithmus (z. B. Logarithmus zur Basis 2 oder natürlicher Logarithmus) keinen Einfluss auf die Big-O-Notation hat. Verschiedene Basen führen lediglich einen Skalierungsfaktor ein, der bei der Bestimmung der Laufzeitkomplexität vernachlässigt werden kann. Der Einfachheit halber betrachten wir daher normalerweise den natürlichen Logarithmus (log), ohne die Basis anzugeben.

Um Ihr Verständnis weiter zu festigen, untersuchen wir eine Python-Funktion für die Matrixmultiplikation und demonstrieren die Anwendung der Big-O-Notation auf Rechenalgorithmen. Die Funktion führt eine Matrixmultiplikation zwischen zwei Matrizen, A und B, durch. Obwohl die Implementierung aus Gründen der Veranschaulichung absichtlich ineffizient ist, ermöglicht sie uns die Analyse ihrer Laufzeitkomplexität.

Die Funktion beginnt mit der Initialisierung einer leeren Matrix C der Größe nxn, wobei n die Dimension der Eingabematrizen ist. Anschließend durchläuft es jede Zeile i der Matrix A und jede Spalte j der Matrix B. Innerhalb der verschachtelten Schleifen berechnet es das Skalarprodukt der Zeile i in Matrix A und der Spalte j in Matrix B und speichert das Ergebnis in der entsprechenden Zelle von Matrix C.

Hier ist der Python-Code für die Matrixmultiplikationsfunktion:

def matrix_multiplication(A, B):
    n = len(A)  # Assuming square matrices of size n x n
    C = [[ 0 ] * n for _ in range(n)]  # Initialize matrix C
    
     for i in range(n):
         for j in range(n):
             for k in range(n):
                C[i][j] += A[i][k] * B[k][j]  # Calculate dot product and update C[i][j]
    
    return C
Um die Laufzeitkomplexität dieser Funktion zu analysieren, analysieren wir sie. Die äußere Schleife iteriert n-mal und stellt die Zeilen der Matrix A dar. Die zweite Schleife iteriert ebenfalls n-mal und stellt die Spalten der Matrix B dar. Innerhalb dieser Schleifen gibt es eine verschachtelte Schleife, die ebenfalls n-mal iteriert und die Skalarproduktberechnung darstellt. Somit beträgt die Gesamtkomplexität O(n^3), was auf kubische Komplexität hinweist.

Es ist wichtig zu beachten, dass die kubische Komplexität nicht ideal ist, insbesondere für große Werte von n. Mit zunehmender Eingabegröße erhöht sich die Ausführungszeit dieser Funktion erheblich. Folglich sollte für größere Matrizen ein effizienterer Algorithmus zur Durchführung der Matrixmultiplikation verwendet werden, wie etwa der Strassen-Algorithmus oder andere optimierte Ansätze, die bessere Laufzeitkomplexitäten erreichen, wie etwa O(n^2,81).

Zusammenfassend ist das Verständnis der Laufzeitkomplexität von Algorithmen, angegeben durch die Big-O-Notation, von entscheidender Bedeutung für die Bewertung ihrer Effizienz und Skalierbarkeit. Es ermöglicht uns, die Leistung eines Algorithmus bei zunehmender Eingabegröße abzuschätzen. Dadurch können wir die am besten geeigneten Algorithmen für verschiedene Szenarien auswählen und ineffiziente Algorithmen für große Datensätze vermeiden.

2.4 Big O of K-nearest neighbors (L02: Nearest Neighbor Methods)
2.4 Big O of K-nearest neighbors (L02: Nearest Neighbor Methods)
  • 2020.09.08
  • www.youtube.com
In this video, we are looking at the Big-O runtime complexity of a naive implementation of k-nearest neighbors-------This video is part of my Introduction of...
 

2.5 Verbesserung der k-nächsten Nachbarn (L02: Methoden des nächsten Nachbarn)



2.5 Verbesserung der k-nächsten Nachbarn (L02: Methoden des nächsten Nachbarn)

In diesem Video befassen wir uns mit der Verbesserung des K-Nearest-Neighbors-Algorithmus durch bestimmte Modifikationen und die Berücksichtigung von Hyperparametern. Im vorherigen Video haben wir die Verwendung einer Prioritätswarteschlange als Datenstruktur besprochen, um die Effizienz bei der Suche nach nächsten Nachbarn zu verbessern. Diese Prioritätswarteschlange hilft dabei, das Durchsuchen des gesamten Trainingssatzes nach jedem neuen Nachbarn zu vermeiden.

Lassen Sie uns nun einen anderen Ansatz untersuchen, um die Rechenleistung des K-Nearest-Neighbors-Algorithmus durch die Nutzung raumpartitionierender Datenstrukturen zu verbessern. Eine solche Datenstruktur ist der Heap, der als Raumaufteilungsstruktur dient, um den Suchprozess über die Trainingsbeispiele zu beschleunigen. Durch die Aufteilung des Datensatzes in Teilmengen innerhalb der Datenstruktur können wir die Notwendigkeit von Distanzberechnungen für jeden Trainingsdatenpunkt minimieren.

Eine Methode zur Raumaufteilung heißt Bucketing. Dazu gehört die Aufteilung des Datensatzes in Teilmengen oder Buckets auf der Grundlage bestimmter Kriterien, beispielsweise gleich große Buckets oder durch Feature-Messungen definierte Grenzen. Auf diese Weise können wir das Durchsuchen des gesamten Trainingssatzes vermeiden und uns bei der Suche nach Nachbarn eines Abfragepunkts nur auf relevante Punkte innerhalb eines bestimmten Buckets konzentrieren. Durch diese Optimierung wird die Effizienz des Suchprozesses deutlich gesteigert.

Eine weitere Raumpartitionierungstechnik ist der KD-Baum, der Hyperwürfel zur Aufteilung des Datensatzes erstellt. Diese Methode unterscheidet sich vom Bucketing, hat jedoch das gemeinsame Ziel, die Sucheffizienz durch Reduzierung der Anzahl der Entfernungsberechnungen zu verbessern. KD-Bäume eignen sich besonders für Datensätze mit vielen Merkmalen.

In ähnlicher Weise erstellt der Ball-Tree-Algorithmus Hypersphären als Raumunterteilungen. Die Wahl zwischen KD-Bäumen und Ballbäumen hängt von den Eigenschaften des Datensatzes ab. Für Datensätze mit hoher Dimensionalität wird häufig der Ball-Tree-Algorithmus bevorzugt. Es ist erwähnenswert, dass die scikit-learn-Bibliothek für maschinelles Lernen, ein weit verbreitetes Tool, verschiedene Optionen für den Algorithmus des K-Nearest-Neighbor-Klassifikators bietet und automatisch den effizientesten Raumpartitionierungsalgorithmus basierend auf dem Datensatz auswählt. Sie können diese Einstellung jedoch bei Bedarf manuell überschreiben.

Darüber hinaus können wir die Leistung der K-nächsten Nachbarn verbessern, indem wir Techniken zur Dimensionsreduzierung einsetzen. Die Reduzierung der Dimensionalität gibt es in zwei Varianten: Merkmalsextraktion und Merkmalsauswahl. Bei der Merkmalsextraktion werden vorhandene Merkmale transformiert oder kombiniert, um eine niedrigerdimensionale Darstellung der Daten zu erstellen. Andererseits umfasst die Feature-Auswahl die Auswahl einer Teilmenge der verfügbaren Features, ohne neue zu erstellen. Durch die Reduzierung der Anzahl der Features können wir den Rechenaufwand für Distanzberechnungen reduzieren und möglicherweise die Effizienz des Algorithmus verbessern. Darüber hinaus leiden hochdimensionale Datensätze häufig unter dem Fluch der Dimensionalität, der aufgrund von Überanpassung zu einer schlechten Generalisierungsleistung führen kann. Daher kann die Reduzierung der Dimensionalität auch dazu beitragen, dieses Problem zu lindern.

Um die Rechenleistung der K-nächsten Nachbarn zu optimieren, können wir Bearbeitungs- oder Bereinigungstechniken untersuchen. Beim Beschneiden werden unnötige Datenpunkte aus dem Trainingssatz entfernt, ohne die Entscheidungsgrenze zu beeinträchtigen. Durch die Eliminierung redundanter Punkte können wir die Anzahl der Vergleiche und Distanzberechnungen reduzieren und so den Algorithmus effizienter machen. Ebenso beinhaltet die Erstellung von Prototypen das Ersetzen eines dichten Bereichs von Trainingsdatenpunkten durch einen einzelnen repräsentativen Punkt. Diese Strategie reduziert den Speicherplatzbedarf und bewahrt gleichzeitig die Vorhersagegenauigkeit des Algorithmus.

Darüber hinaus spielt die Optimierung der Hyperparameter eine entscheidende Rolle bei der Verbesserung der Vorhersageleistung des K-Nearest-Neighbors-Algorithmus. Hyperparameter sind anpassbare Einstellungen, die das Verhalten des Algorithmus beeinflussen, aber nicht aus den Trainingsdaten gelernt werden. Dazu gehören der Wert von K (die Anzahl der zu berücksichtigenden Nachbarn), die Merkmalsskalierung, das verwendete Entfernungsmaß und das Gewichtungsschema für die Entfernungsberechnung. Die Wahl geeigneter Werte für diese Hyperparameter kann die Leistung des Algorithmus erheblich beeinflussen. Es ist jedoch wichtig, vorsichtig zu sein und eine Überanpassung des Modells an die Trainingsdaten zu vermeiden.

Durch die Nutzung raumpartitionierender Datenstrukturen, den Einsatz von Techniken zur Dimensionsreduzierung, die Anwendung von Bearbeitungs- und Bereinigungsmethoden und die Feinabstimmung von Hyperparametern können wir sowohl die Rechenleistung als auch die Vorhersageleistung des K-Nearest-Neighbors-Algorithmus verbessern.

2.5 Improving k-nearest neighbors (L02: Nearest Neighbor Methods)
2.5 Improving k-nearest neighbors (L02: Nearest Neighbor Methods)
  • 2020.09.08
  • www.youtube.com
This video summarizes some of the common tricks for making k-nearest neighbors more efficient in terms of computational performance and predictive performanc...
 

2.6 K-nächste Nachbarn in Python (L02: Methoden des nächsten Nachbarn)



2.6 K-nächste Nachbarn in Python (L02: Methoden des nächsten Nachbarn)

Nach einer ausführlichen Diskussion über K-Nearest Neighbors wird im Text ein Python-Beispiel vorgestellt, das die Implementierung von K-Nearest Neighbors mithilfe der beliebten Scikit-Learn-Bibliothek demonstriert. Der Autor räumt ein, dass möglicherweise nicht alle Aspekte sofort klar sind, und versichert den Lesern, dass zukünftige Vorträge tiefer auf Python, NumPy und Scikit-Learn eingehen werden. Dennoch dient das bereitgestellte Beispiel als Vorgeschmack, um eine Top-Down-Perspektive auf die Funktionsweise dieser Tools zu bieten.

Zur Unterstützung des Implementierungsbeispiels verweist der Autor auf eine Website, auf der Leser Codebeispiele finden können. Darüber hinaus erklärt der Autor den Prozess des Herunterladens eines Repositorys von GitHub mithilfe der ZIP-Datei oder des Klonens. Der Autor betont die Bedeutung von GitHub als reales Tool und weist darauf hin, dass ein GitHub-Profil und das Teilen von Projekten von Vorteil sein können, um die eigene Arbeit potenziellen Arbeitgebern vorzustellen.

Anschließend enthält der Text detaillierte Anweisungen zum Klonen eines Repositorys mithilfe des GitHub-Links und des Befehls „git clone“. Der Autor räumt zwar ein, dass der Prozess für Windows-Benutzer leicht variieren kann, empfiehlt jedoch, Tutorials oder Unterstützung vom TA (Lehrassistenten) einzuholen. Sobald das Repository erfolgreich geklont wurde, weist der Autor die Leser an, zum Ordner zu navigieren, und erklärt, dass Aktualisierungen mithilfe des Befehls „git pull“ abgerufen werden können.

Im Anschluss an die Codebeispiele demonstriert der Autor Schritt für Schritt das Öffnen eines Jupyter-Notebooks, insbesondere Jupyter Lab, und die Ausführung von Befehlen. Um die Leser nicht zu überfordern, betont der Autor, wie wichtig es ist, die Ausgaben nach jeder Ausführung zu löschen. Darüber hinaus erwähnt der Autor die Nützlichkeit der Wasserzeichenerweiterung in Jupyter Notebooks, die die Versionen verwendeter Softwarepakete anzeigt. Diese Informationen helfen bei der Fehlerbehebung und stellen die Reproduzierbarkeit der Ergebnisse sicher. Um die Implementierung zu erleichtern, werden wichtige Pakete wie Pandas, NumPy, Matplotlib und scikit-learn installiert.

Als Nächstes lädt der Autor den Iris-Datensatz aus einer CSV-Datei und demonstriert die Verwendung von Befehlen wie „head“ und „tail“, um eine Vorschau des Datensatzes anzuzeigen. Die Daten werden mit der Funktion „read_csv“ in einen Pandas DataFrame geladen. Der Autor weist zwar darauf hin, dass maschinelles Lernen typischerweise NumPy-Arrays verwendet, betont jedoch, dass scikit-learn auch DataFrames unterstützt. Um dies zu veranschaulichen, liefert der Autor ein Beispiel für das Extrahieren bestimmter Spalten aus dem DataFrame, um ein NumPy-Array zu erstellen. Die Form des Arrays, die die Anzahl der Trainingsbeispiele und Features angibt, wird mit dem Befehl „shape“ angezeigt.

Der Text beschreibt eine Reihe von Schritten, die einen Arbeitsablauf für maschinelles Lernen unter Verwendung von Python und der scikit-learn-Bibliothek bilden. Hier ist eine detaillierte Zusammenfassung dieser Schritte:

  1. Mischen von Indizes und Beschriftungen: Der Autor leitet den Arbeitsablauf ein, indem er den Prozess des Mischens von Indizes und Beschriftungen in einem Datensatz erläutert. Der Zweck des Mischens besteht darin, die Reihenfolge der Datenpunkte zu randomisieren und sicherzustellen, dass jede Beschriftung der richtigen Zeile in der Merkmalsmatrix entspricht.

  2. Datensatzaufteilung: Der Datensatz ist in einen Trainingssatz und einen Testsatz unterteilt. Der Autor wählt manuell die ersten 105 Beispiele für den Trainingssatz aus und reserviert die restlichen 45 Beispiele für den Testsatz. Diese Unterteilung ist entscheidend für die Bewertung der Leistung des maschinellen Lernmodells.

  3. Einführung in scikit-learn und den Iris-Datensatz: Der Autor stellt die scikit-learn-Bibliothek vor, insbesondere die Implementierung des Iris-Datensatzes und der Funktion „train_test_split“. Der Iris-Datensatz ist ein beliebter Datensatz, der häufig für Klassifizierungsaufgaben verwendet wird. Die Funktion „train_test_split“ mischt den Datensatz automatisch und teilt ihn für Training und Tests in die angegebenen Anteile auf.

  4. Visualisierung mithilfe einer Streudiagrammmatrix: Der Autor stellt eine praktische Funktion namens „Streudiagrammmatrix“ zur Visualisierung des Datensatzes bereit. Diese Funktion nutzt die Matplotlib-Bibliothek, um eine Streudiagrammmatrix mit diagonal angezeigten Histogrammen zu erstellen. Die Streudiagrammmatrix stellt die Beziehungen zwischen verschiedenen Features im Datensatz visuell dar.

  5. Demonstration der Streudiagrammmatrix: Der Autor demonstriert die Verwendung der Streudiagrammmatrix durch die Darstellung des Iris-Datensatzes. Zur Darstellung unterschiedlicher Blumenklassen werden unterschiedliche Farben zugeordnet. Insbesondere hebt der Autor hervor, dass bestimmte Merkmale wie die Blütenblattlänge und -breite besonders nützlich für die Unterscheidung zwischen verschiedenen Blütenklassen sind.

  6. Einführung in den Klassifikator für k-nächste Nachbarn (k-NN): Der Autor erklärt dann den Klassifikator für k-nächste Nachbarn (k-NN), bei dem es sich um einen unkomplizierten Algorithmus handelt, der Datenpunkte basierend auf ihrer Nähe zu benachbarten Datenpunkten klassifiziert. Um den k-NN-Klassifikator zu instanziieren, erstellt der Autor ein Objekt mit drei Nachbarn.

  7. Anpassen des k-NN-Klassifikators: Der k-NN-Klassifikator wird mithilfe der „Fit“-Methode an den Trainingssatz angepasst. In diesem Schritt wird das Modell mithilfe der bereitgestellten Trainingsdaten trainiert.

  8. Vorhersage für den Testsatz: Der Autor verwendet den angepassten k-NN-Klassifikator, um mithilfe der „Vorhersage“-Methode Vorhersagen für den Testsatz zu treffen. Die Vorhersagen werden in einer Variablen namens „pred“ gespeichert.

  9. Leistungsbewertung: Um die Leistung des Modells zu bewerten, vergleicht der Autor die vorhergesagten Labels (gespeichert in „pred“) mit den wahren Labels des Testsatzes (gespeichert in „y_test“). Durch die Berechnung der Anzahl korrekter Vorhersagen kann die Genauigkeit des Modells auf dem Testsatz bestimmt werden.

  10. Fazit und weitere Erkundung: Die Vorlesung schließt mit der Ermutigung der Leser, die scikit-learn-Dokumentation zu durchsuchen, um zusätzliche Informationen zum k-Nearest-Neighbors-Algorithmus und seinen verschiedenen Optionen zu erhalten. Darüber hinaus stellt der Autor den Lesern eine Frage zur standardmäßigen Distanzmetrik, die vom k-NN-Klassifikator verwendet wird, und schlägt eine Übung zur Untersuchung und Diskussion dieses Aspekts vor.

Die Vorlesung bietet eine umfassende Erläuterung verschiedener Themen, darunter das Konzept der K-Nearest Neighbors, eine Beispielimplementierung mithilfe der Scikit-Learn-Bibliothek, Richtlinien zum Herunterladen und Klonen von Repositorys von GitHub, eine Einführung in Jupyter Notebook und Jupyter Lab sowie das Laden eines Datensatzes in einen Pandas DataFrame und demonstriert die Extraktion von Spalten und die Konvertierung in NumPy-Arrays.

2.6 K-nearest neighbors in Python (L02: Nearest Neighbor Methods)
2.6 K-nearest neighbors in Python (L02: Nearest Neighbor Methods)
  • 2020.09.10
  • www.youtube.com
In this video, we are talking about using k-nearest neighbors in Python using scikit-learn. Jupyter Notebook: https://github.com/rasbt/stat451-machine-learni...
 

3.1 (Optional) Python-Übersicht



3.1 (Optional) Python-Übersicht

Ich hoffe, dass Sie bisher alle eine tolle Woche hatten und die Vorträge genießen. Heute möchte ich einige wichtige Themen besprechen, die in den letzten Vorträgen behandelt wurden.

Zuerst hielten wir einen Vortrag über die Verbesserung Kanaans, gefolgt von einem Vortrag über die Implementierung von Kin in Python mithilfe von psychischem Lernen. Aufgrund Ihres Feedbacks aus dem Einführungsquiz zum Kennenlernen habe ich herausgefunden, dass die meisten von Ihnen einen Programmierhintergrund haben oder bereits einen Programmierkurs besucht haben. Das sind großartige Neuigkeiten, denn sie werden Ihnen in diesem Kurs von großem Nutzen sein. Allerdings ist mir aufgefallen, dass nur etwa die Hälfte von Ihnen solide Erfahrung mit Python hat. Bevor wir uns daher mit dem wissenschaftlichen Rechnen mit Python befassen und uns eingehender mit psychischem Lernen befassen, denke ich, dass es hilfreich wäre, denjenigen, die neu darin sind, Hilfe bei der Einrichtung von Python zu geben. Dadurch wird sichergestellt, dass die nächste Vorlesung für alle reibungsloser verläuft.

Um es leichter zu sagen: Ich habe es wirklich genossen, über Ihre Lieblingshobbys zu lesen. Es scheint, als ob viele von Ihnen meine Liebe zu Outdoor-Aktivitäten wie Langlaufen, Laufen und Wandern teilen. Zeit in der Natur zu verbringen ist wirklich erfrischend, obwohl ich verstehe, dass regnerische Tage und lange Winter diese Möglichkeiten einschränken können. Einige von Ihnen erwähnten auch Ihr Interesse an Videospielen, ein Student erwähnte sogar die Zelda-Serie. Ich muss zugeben, dass ich auch ein großer Fan der Serie bin und sie gerne an verschneiten Weihnachtstagen oder nach einem anstrengenden Tag zum Entspannen spiele.

Wie versprochen ist die heutige Vorlesung optional. Wenn Sie bereits über umfassende Python-Erfahrung verfügen und Python auf Ihrem Computer eingerichtet haben, können Sie die folgenden drei Videos überspringen. Wenn Sie jedoch neu bei Python sind oder Hilfe bei der Einrichtung benötigen, empfehle ich Ihnen, sich diese anzuschauen. Diese Videos bieten Ihnen Motivation und praktische Ratschläge, die auf meinen eigenen Erfahrungen mit Python basieren. Es ist wichtig zu beachten, dass Sie kein erfahrener Programmierer sein müssen, um Python in diesem Kurs zu verwenden. Wir werden uns auf die Grundlagen konzentrieren, die für maschinelles Lernen erforderlich sind, und Sie werden im Laufe der Zeit mehr lernen.

Nächste Woche haben wir unsere erste echte Hausaufgabe, bei der Sie einen K-Nearest-Neighbor-Algorithmus implementieren werden. Für diese Aufgabe müssen Sie neben der Verwendung von psychischem Lernen auch Ihren eigenen Code schreiben. Daher wäre es für Sie von Vorteil, diese Woche Python als Vorbereitung auf die Hausaufgaben einzurichten. Mach dir keine Sorge; Die Aufgabe soll Ihnen helfen, den KNN-Algorithmus besser zu verstehen, und sie wird nicht allzu schwierig sein, da es sich um die erste Hausaufgabe handelt. Sobald wir diese Aufgabe abgeschlossen haben, werden wir uns eingehender mit konzeptionellen Aspekten des maschinellen Lernens befassen.

Bevor wir fortfahren, werfen wir einen kurzen Überblick über den Kursfortschritt. In der ersten Woche behandelten wir die Einführung in maschinelles Lernen und K-nächste Nachbarn. Derzeit befinden wir uns in der zweiten Woche und konzentrieren uns auf rechnerische Grundlagen. Diese Grundlagen sind von entscheidender Bedeutung, da wir sie später zur Umsetzung verschiedener Konzepte des maschinellen Lernens nutzen werden. Daher ist es wichtig, sich frühzeitig mit Python und seiner Verwendung vertraut zu machen. In dieser Vorlesung werden wir hauptsächlich Python und seine Einrichtung besprechen. Bitte beachten Sie, dass ich den Einrichtungsprozess auf meinem Mac demonstriere, unser TA Ihnen jedoch bei allen Windows-bezogenen Fragen behilflich sein kann.

Python ist eine interpretierte und dynamische Programmiersprache, was sie im Vergleich zu statisch typisierten Sprachen wie C oder C++ interaktiver und benutzerfreundlicher macht. Obwohl Python möglicherweise langsamer ist als diese Sprachen, stellt dies für unsere Zwecke kein großes Problem dar. Viele wissenschaftliche Computerbibliotheken, die wir in der nächsten Vorlesung untersuchen werden, sind in C oder Fortran geschrieben und bieten schnelle Ausführungszeiten. Python ist eine universelle Programmiersprache, die in verschiedenen Anwendungen weit verbreitet ist, darunter Web-Frameworks wie Django und beliebte Dienste wie Instagram und Dropbox.

Vergleichen wir nun Python mit einer statisch typisierten Sprache wie C, indem wir ein einfaches Programm schreiben. In C müssen wir Variablen deklarieren und ihre Datentypen explizit angeben, z. B. Ganzzahlen, Gleitkommazahlen oder Zeichen. Hier ist ein Beispiel für ein einfaches Programm in C:

#include <stdio.h>

int main() {
     int age = 25 ;
     float height = 1.75 ;
     char initial = 'J' ;

    printf( "My age is %d\n" , age);
    printf( "My height is %.2f meters\n" , height);
    printf( "My initial is %c\n" , initial);

     return 0 ;
}
In diesem C-Programm haben wir die Variablen „Alter“, „Höhe“ und „Initial“ mit ihren jeweiligen Datentypen deklariert. Anschließend haben wir diesen Variablen Werte zugewiesen und sie mit printf() ausgedruckt.

Vergleichen wir nun dasselbe Programm in Python:

age = 25
height = 1.75
initial = 'J'

print( "My age is" , age)
print( "My height is" , height, "meters" )
print( "My initial is" , initial)
In Python müssen Sie Variablentypen nicht explizit deklarieren. Sie können Variablen direkt Werte zuweisen und Python leitet die Datentypen automatisch ab. Zur Anzeige der Ausgabe wird die Funktion print() verwendet.

Die Einfachheit und Lesbarkeit von Python machen es zu einer ausgezeichneten Wahl sowohl für Anfänger als auch für erfahrene Programmierer. Es verfügt über ein riesiges Ökosystem an Bibliotheken und Frameworks, die es für wissenschaftliches Rechnen, Datenanalyse, maschinelles Lernen und mehr geeignet machen.

Fahren wir nun mit der Einrichtung von Python auf Ihrem Computer fort. Es gibt verschiedene Möglichkeiten, Python zu installieren, ich empfehle jedoch die Verwendung der Anaconda-Distribution, die viele nützliche Bibliotheken für das wissenschaftliche Rechnen vorinstalliert enthält. Hier sind die Schritte zur Installation von Anaconda:

  1. Besuchen Sie die Anaconda-Website ( https://www.anaconda.com/products/individual ) und laden Sie das für Ihr Betriebssystem (Windows, macOS oder Linux) geeignete Installationsprogramm herunter.

  2. Führen Sie das Installationsprogramm aus und befolgen Sie die Anweisungen auf dem Bildschirm. Sie können die Standardinstallationsoptionen auswählen, es sei denn, Sie haben bestimmte Präferenzen.

  3. Nach Abschluss der Installation sollten Anaconda Navigator und Anaconda Prompt (oder Anaconda PowerShell Prompt) auf Ihrem Computer installiert sein. Dies sind praktische Tools zum Verwalten von Python-Umgebungen und -Paketen.

  4. Öffnen Sie den Anaconda Navigator und klicken Sie auf die Registerkarte „Umgebungen“. Hier können Sie eine neue Umgebung für diesen Kurs erstellen. Klicken Sie auf die Schaltfläche „Erstellen“, geben Sie einen Namen für die Umgebung ein (z. B. „Machine-Learning“) und wählen Sie die Python-Version (vorzugsweise Python 3.x). Klicken Sie auf „Erstellen“, um die Umgebung zu erstellen.

  5. Sobald die Umgebung erstellt ist, klicken Sie im Anaconda Navigator auf die Registerkarte „Home“. Sie sollten eine Liste der verfügbaren Anwendungen und Umgebungen sehen. Wählen Sie Ihre neu erstellte Umgebung aus dem Dropdown-Menü oben im Fenster aus.

  6. Klicken Sie auf der Registerkarte „Home“ im Abschnitt „Jupyter Notebook“ auf die Schaltfläche „Installieren“. Dadurch wird Jupyter Notebook installiert, das wir für die interaktive Programmierung und die Ausführung von Python-Code verwenden werden.

  7. Klicken Sie nach der Installation auf die Schaltfläche „Starten“ neben Jupyter Notebook. Dadurch wird ein neuer Tab in Ihrem Webbrowser geöffnet, auf dem Jupyter Notebook ausgeführt wird.

Glückwunsch! Sie haben Python und Jupyter Notebook erfolgreich mit der Anaconda-Distribution installiert. Sie sind jetzt bereit, für diesen Kurs mit dem Programmieren in Python zu beginnen. In der nächsten Vorlesung werden wir tiefer in das wissenschaftliche Rechnen mit Python eintauchen und die beliebte Bibliothek namens scikit-learn erkunden.

Wenn Sie während des Installationsprozesses auf Probleme stoßen oder Fragen haben, zögern Sie bitte nicht, diese im Diskussionsforum zu stellen oder sich an den TA zu wenden, um Hilfe zu erhalten.

Bitte beachten Sie, dass diese Anweisungen spezifisch für Anaconda sind. Wenn Sie jedoch lieber eine andere Python-Distribution wie Miniconda oder die Standard-Python-Distribution verwenden möchten, können Sie dem Kurs trotzdem folgen.

3.1 (Optional) Python overview
3.1 (Optional) Python overview
  • 2020.09.16
  • www.youtube.com
In this optional videos, I mainly talk about the use of Python in this course. I will also show a quick demo using C (a statically typed language) vs Python....
 

3.2 (Optional) Python-Setup


3.2 (Optional) Python-Setup

Im zweiten Video des Kurses besprechen wir den Einrichtungsprozess und die Installation von Python. Im vorherigen Video haben wir die Grundlagen interpretierter und dynamischer Programmiersprachen behandelt und Python als dynamisch interpretierte Sprache hervorgehoben.

Bevor wir mit der Installation fortfahren, ist es wichtig, dass Sie sich das Video ansehen und während des Ansehens keine Installationen auf Ihrem Computer durchführen. Diese Vorsichtsmaßnahme stellt sicher, dass Sie die verschiedenen Installationsoptionen vollständig verstanden haben, bevor Sie eine Entscheidung treffen. Die Installation von Software ohne entsprechende Kenntnisse kann später zu Reue führen.

Zunächst empfiehlt es sich zu prüfen, ob auf Ihrem Computer bereits eine aktuelle Python-Version installiert ist. Auf Mac oder Linux können Sie den Befehl „which Python“ verwenden, um den Installationsort und die Version zu ermitteln. Ebenso können Sie unter Windows den Befehl „where“ verwenden, um den Installationsort zu finden.

Viele Macs verfügen traditionell über eine veraltete Version von Python, insbesondere Python 2. Es wird dringend empfohlen, Python zu aktualisieren, da Python 2 von der Python-Community nicht mehr unterstützt wird. Idealerweise empfiehlt sich die Installation von Python 3.8 oder 3.7, da sich die neuere Version 3.9 noch in der Entwicklung befindet.

Die offizielle Methode zur Installation von Python besteht darin, python.org zu besuchen und das Installationsprogramm herunterzuladen. Ein oft bevorzugter alternativer Ansatz ist jedoch die Verwendung von Anaconda oder genauer gesagt Miniconda. Miniconda ist eine schlanke Version von Anaconda, die keine unnötigen Bibliotheken enthält und so Speicherplatz auf Ihrem Computer spart. Während Anaconda über vorinstallierte Bibliotheken verfügt, ermöglicht Miniconda einen individuelleren Installationsprozess.

Persönlich empfiehlt der Dozent die Verwendung von Miniconda aufgrund der Benutzerfreundlichkeit und der positiven Erfahrungen, die viele Mitglieder der Python-Community für wissenschaftliches Rechnen damit gemacht haben. Miniconda bietet einen umfassenden Paketmanager, der sicherstellt, dass alle erforderlichen Paketversionen installiert sind, und Paketabhängigkeiten verwaltet. Diese Funktion erleichtert die Aufrechterhaltung einer stabilen und kompatiblen Entwicklungsumgebung.

Um Miniconda zu installieren, können Sie die Dokumentationswebsite docs.conda.io besuchen und zur neuesten englischen Version der Miniconda-Installationsseite navigieren. Von dort aus können Sie das passende Installationsprogramm für Ihr Betriebssystem auswählen. Für Mac-Benutzer wird häufig das Bash-Installationsprogramm verwendet. Führen Sie nach dem Herunterladen des Installationsprogramms das Skript aus, akzeptieren Sie die Lizenzvereinbarung und wählen Sie den Installationsort.

Sobald Miniconda installiert ist, können Sie Ihre Standard-Python-Version überprüfen, indem Sie eine Python-Shell öffnen, die nun die aktualisierte Version anzeigen sollte. Miniconda bietet außerdem Tools zur Verwaltung verschiedener Umgebungen, sodass Sie isolierte Umgebungen für verschiedene Projekte erstellen können. Obwohl diese Umgebungen für diesen Kurs nicht erforderlich sind, können sie nützlich sein, wenn Sie an mehreren Projekten gleichzeitig arbeiten.

Um Pakete zu installieren, wie zum Beispiel das für die nächste Vorlesung benötigte Paket „numpy“, können Sie den Paketmanager „pip“ oder den Conda-Installer verwenden. Da Sie Miniconda verwenden, wird empfohlen, wann immer möglich das Conda-Installationsprogramm zu verwenden, da es eine bessere Kompatibilität und Versionsverwaltung gewährleistet. Wenn ein Paket jedoch in Conda nicht verfügbar ist, können Sie auf „pip“ zurückgreifen.

Falls Sie Pakete installieren müssen, die in Conda nicht verfügbar sind, wie das Paket „mlxtend“, können Sie Conda Forge erkunden. Conda Forge ist ein von der Community betriebenes Repository, das Bibliotheken hostet, die von der breiteren Conda-Community unterstützt werden. Wenn Sie in Conda Forge nach dem gewünschten Paket suchen, finden Sie spezifische Installationsanweisungen für dieses Paket.

Denken Sie daran, dass Sie Pakete auch mit dem Conda-Paketmanager aktualisieren können, indem Sie Befehle wie „conda update“ gefolgt vom Paketnamen oder mit „pip“ verwenden, indem Sie „pip install --upgrade“ gefolgt vom Paketnamen verwenden.

Durch Befolgen dieser Installations- und Paketverwaltungsrichtlinien können Sie eine reibungslose und effiziente Einrichtung von Python für diesen Kurs sicherstellen.

Um Pakete vom Conda Forge-Kanal zu installieren, können Sie den folgenden Befehl verwenden:

conda install -c conda-forge <Paketname>

Um beispielsweise das MLX Extent-Paket von Conda Forge zu installieren, würden Sie Folgendes verwenden:

conda install -c conda-forge mlx_ext

Dieser Befehl sucht im Conda Forge-Kanal nach dem Paket und installiert es in Ihrer Umgebung.

Wenn das von Ihnen benötigte Paket nicht in Conda Forge oder einem anderen Conda-Kanal verfügbar ist, können Sie es auch mit dem Pip-Paketmanager installieren. Pip ist der Standardpaketmanager für Python und ermöglicht die Installation von Paketen aus dem Python Package Index (PyPI).

Um ein Paket mit pip zu installieren, können Sie den folgenden Befehl verwenden:

pip install <Paketname>

Um beispielsweise ein Paket namens „example-package“ mit pip zu installieren, würden Sie Folgendes verwenden:

pip install Beispielpaket

Stellen Sie sicher, dass Sie <Paketname> durch den tatsächlichen Namen des Pakets ersetzen, das Sie installieren möchten.

Beachten Sie, dass bei Verwendung von Conda und pip im Allgemeinen empfohlen wird, Conda als primären Paketmanager zu verwenden, um die Paketkompatibilität aufrechtzuerhalten und Abhängigkeiten zu verwalten. Wenn ein Paket jedoch in Conda nicht verfügbar ist, ist die Verwendung von pip eine geeignete Alternative.

Damit sind die Setup-Anweisungen für die Installation von Python und die Verwaltung von Paketen mit Conda und pip abgeschlossen. Denken Sie daran, sich das Video-Tutorial anzusehen, bevor Sie etwas auf Ihrem Computer installieren, und befolgen Sie die empfohlenen Schritte, um einen reibungslosen Installationsprozess zu gewährleisten.

3.2 (Optional) Python setup
3.2 (Optional) Python setup
  • 2020.09.16
  • www.youtube.com
In this optional video, I am demonstrating how to install Python using Miniconda on macOS. Also, I provide some brief demo of the conda package manager.-----...
 

3.3 (Optional) Ausführen von Python-Code


3.3 (Optional) Ausführen von Python-Code

Im dritten und letzten Video der dritten Vorlesung werde ich verschiedene Methoden zum Ausführen von Python-Code demonstrieren. Dieses Video konzentriert sich auf Jupiter-Notizbücher, ein Dateiformat und Programm, das bequemes Codieren, Schreiben von Texten, Rendern von Gleichungen und Plotten in einem einzigen Dokument ermöglicht, das für die bevorstehende Hausaufgabe verwendet wird.

Bevor ich in Jupiter-Notizbücher eintauche, zeige ich Ihnen zunächst die einfachste Möglichkeit, Python-Code auszuführen, nämlich den Python-Interpreter oder das, was manche Leute REPL (Read-Eval-Print Loop) nennen. Der Interpreter ermöglicht die interaktive Ausführung von Python-Code, d. h. der Code wird sofort ausgewertet. Um den Interpreter zu verwenden, können Sie Ihr Terminal öffnen und „python“ eingeben. Von dort aus können Sie Python-Ausdrücke eingeben und die Ergebnisse sofort sehen. Wenn Sie beispielsweise „print(1 + 2)“ eingeben, wird das Ergebnis „3“ angezeigt. Sie können den Interpreter auch für komplexere Aufgaben verwenden, z. B. das Durchlaufen von Werten und deren Drucken.

Während der Interpreter für schnelle Berechnungen oder Berechnungen nützlich sein kann, wird er für das Schreiben von komplizierterem Code nicht empfohlen. Es kann leicht passieren, dass man den Überblick über die Berechnungen verliert und das Zurückscrollen nach zuvor ausgeführten Befehlen umständlich wird. Daher ist es für komplexeren Code vorzuziehen, ein Python-Skript oder ein Jupiter-Notebook zu verwenden.

Als nächstes stelle ich einen alternativen interaktiven Python-Interpreter namens IPython vor. IPython bietet im Vergleich zum regulären Interpreter zusätzliche Features und Funktionalitäten, darunter Syntaxfärbung, Verlaufsfunktion zur einfachen Codeänderung und magische Befehle. Magic-Befehle sind spezielle Befehle, die mit einem Prozentzeichen (%) beginnen und nützliche Funktionen bieten. Ein solches Beispiel ist der magische Befehl „timeit“, der das Benchmarking verschiedener Code-Implementierungen ermöglicht. Ich demonstriere dies, indem ich zwei Funktionen zum Umkehren von Zeichenfolgen implementiert und ihre Effizienz mit dem Befehl „timeit“ vergleiche.

Nachdem ich die Vorteile von IPython vorgestellt habe, erkläre ich, dass Jupiter-Notebooks ursprünglich IPython-Notebooks genannt wurden, weil sie auf IPython basierten. Schon jetzt verlassen sich Jupiter-Notebooks auf IPython und bieten die gleichen Vorteile und zusätzliche Funktionen. Um IPython zu installieren, verwende ich Conda und zeige die IPython-Website für weitere Dokumentation.

Im Folgenden bespreche ich die zweite Methode zum Ausführen von Python-Code, nämlich die Verwendung von Python-Skripten. Bei dieser Methode wird eine Datei mit der Erweiterung .py erstellt, der Code in die Datei geschrieben und über die Befehlszeile ausgeführt. Ich stelle ein Beispiel für ein Python-Skript bereit, das eine Schleife verwendet, um Zahlen von 0 bis 4 auszugeben.

Abschließend erwähne ich, wie wichtig es ist, Codierungsstilrichtlinien wie PEP 8 einzuhalten, um sauberen und lesbaren Code zu schreiben. Ich zeige, wie die Verwendung eines Linters wie Flake8 in einer integrierten Entwicklungsumgebung wie Visual Studio Code dabei helfen kann, Stilprobleme zu identifizieren und zu beheben und so die Gesamtqualität des Codes zu verbessern.

Das Video behandelte verschiedene Möglichkeiten, Python-Code auszuführen, einschließlich der Verwendung des Interpreters, der Erstellung von Python-Skripten und der Nutzung der Vorteile von IPython- und Jupiter-Notebooks. Jede Methode hat ihre eigenen Vorteile und ist für unterschiedliche Zwecke geeignet.

3.3 (Optional) Running Python code
3.3 (Optional) Running Python code
  • 2020.09.16
  • www.youtube.com
In this third and last video of the optional lecture 3, I am demonstrating the different ways for running Python code: the REPL, IPython, .py scripts, and Vi...
 

4.1 Einführung in NumPy (L04: Wissenschaftliches Rechnen in Python)



4.1 Einführung in NumPy (L04: Wissenschaftliches Rechnen in Python)

In diesem Tutorial behandeln wir die Grundlagen von NumPy, einschließlich der Erstellung von Arrays, des Zugriffs auf Elemente, der Durchführung von Array-Operationen und mehr. Lass uns anfangen!

Zunächst müssen wir die NumPy-Bibliothek importieren. Herkömmlicherweise wird es unter dem Alias np importiert. Führen Sie den folgenden Code aus, um NumPy zu importieren:

import numpy as np
Nachdem wir nun NumPy importiert haben, erstellen wir unser erstes Array. NumPy-Arrays werden mit der Funktion np.array() erstellt, die eine Python-Liste als Eingabe verwendet. Führen Sie den folgenden Code aus, um ein Array zu erstellen:

arr = np.array([1, 2, 3, 4, 5])
print(arr)
Sie sollten die folgende Ausgabe sehen:

[1 2 3 4 5]
Glückwunsch! Sie haben Ihr erstes NumPy-Array erstellt. Lassen Sie uns nun einige grundlegende Operationen untersuchen, die wir an Arrays ausführen können.

Zugreifen auf Array-Elemente

Um auf Elemente in einem NumPy-Array zuzugreifen, können wir Indizierung und Slicing verwenden, ähnlich wie bei Python-Listen. Die Indizierung beginnt bei 0.

Führen Sie den folgenden Code aus, um auf Elemente im Array zuzugreifen:

 print (arr[ 0 ])   # Access the first element
print (arr[ 2 ])   # Access the third element
print (arr[- 1 ])   # Access the last element
Die Ausgabe wird sein:

1
3
5
Wir können Slicing auch verwenden, um auf eine Reihe von Elementen in einem Array zuzugreifen. Die Syntax für das Slicing lautet start:stop:step, wobei start der Startindex, stop der Stoppindex (exklusiv) und step die Schrittgröße ist.

Führen Sie den folgenden Code aus, um das Array zu segmentieren:

 print (arr[ 1 : 4 ])   # Access elements from index 1 to 3
print (arr[:: 2 ])   # Access every other element

Die Ausgabe wird sein:

[2 3 4]
[1 3 5]
Array-Operationen

NumPy-Arrays unterstützen verschiedene mathematische Operationen wie Addition, Subtraktion, Multiplikation und Division. Diese Operationen werden elementweise auf die Arrays angewendet.

Führen Sie den folgenden Code aus, um Array-Operationen auszuführen:

arr1 = np. array ([ 1 , 2 , 3 ])
arr2 = np. array ([ 4 , 5 , 6 ])

# Addition
print (arr1 + arr2)

# Subtraction
print (arr1 - arr2)

# Multiplication
print (arr1 * arr2)

# Division
print (arr1 / arr2)
Die Ausgabe wird sein:

 [5 7 9]
[-3 -3 -3]
[4 10 18]
[0.25 0.4  0.5]
NumPy bietet außerdem verschiedene mathematische Funktionen, die auf Arrays angewendet werden können. Beispielsweise kann die Funktion np.sin() verwendet werden, um den Sinus eines Arrays zu berechnen.

Führen Sie den folgenden Code aus, um eine mathematische Funktion auf ein Array anzuwenden:

arr = np. array ([ 0 , np.pi/ 2 , np.pi])

# Calculate sine
print (np.sin(arr))
Die Ausgabe wird sein:

[0.0000000e+00 1.0000000e+00 1.2246468e-16]

Array-Form und Umgestaltung

Die Form eines NumPy-Arrays stellt seine Abmessungen dar, beispielsweise die Anzahl der Zeilen und Spalten. Mit dem Shape-Attribut können wir die Form eines Arrays überprüfen.

Führen Sie den folgenden Code aus, um die Form eines Arrays zu überprüfen:

arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape)
Die Ausgabe wird sein:

(2, 3)
Wir können die Form eines Arrays auch mit der Funktion reshape() ändern. Mit dieser Funktion können wir die Größe eines Arrays ändern, ohne seine Daten zu ändern.

Führen Sie den folgenden Code aus, um ein Array umzuformen:

arr = np.array([1, 2, 3, 4, 5, 6])
reshaped_arr = arr.reshape((2, 3))
print(reshaped_arr)
Die Ausgabe wird sein:

[[1 2 3]
 [4 5 6]]
Dies sind nur einige der grundlegenden Vorgänge, die Sie mit NumPy ausführen können. Die Bibliothek bietet eine breite Palette an Funktionen und Möglichkeiten für die effiziente Arbeit mit Arrays. Ich empfehle Ihnen, die NumPy-Dokumentation zu durchsuchen, um mehr über die Funktionen zu erfahren.
4.1 Intro to NumPy (L04: Scientific Computing in Python)
4.1 Intro to NumPy (L04: Scientific Computing in Python)
  • 2020.09.20
  • www.youtube.com
This first video in the "L04: Intro to Scientific Computing in Python" introduces NumPy on a basic level before diving into more details in the following vid...
 

4.2 Aufbau und Indizierung von NumPy-Arrays (L04: Wissenschaftliches Rechnen in Python)



4.2 Aufbau und Indizierung von NumPy-Arrays (L04: Wissenschaftliches Rechnen in Python)

Im zweiten Video möchte ich den Aufbau und die Indizierung von Nicht-Python-Arrays besprechen. Array-Konstruktionsroutinen sind nützliche Bausteine oder Funktionen zum Erstellen von Arrays. Sie sind praktisch, wenn Sie ein Platzhalterarray benötigen, das Sie später mit bestimmten Werten füllen können. Lassen Sie mich zeigen, was ich meine.

Um ein mit der Zahl Eins gefülltes Array zu erstellen, können wir die Funktion „Einsen“ verwenden. Zum Beispiel generiert ones((3, 3)) ein 3x3-Array, bei dem alle Elemente auf eins gesetzt sind. Sie können auch verschiedene Dimensionen angeben, z. B. ones((3, 4)), wodurch eine 3x4-Matrix voller Einsen erstellt wird. Die Funktion ones akzeptiert verschiedene Argumente, einschließlich des Parameters dtype, der den Datentyp des Arrays bestimmt (Standard ist float64 für 64-Bit-Maschinen). Sie können es auf int64 setzen, um ein Array von Ganzzahlen zu erstellen. Darüber hinaus können Sie den Parameter order angeben, der steuert, wie das Array im Speicher angeordnet wird. Der Standardwert ist C und steht für den zeilenorientierten Stil. Sie können jedoch auch F für das Layout im Fortran-Stil wählen. Für diese Klasse müssen Sie sich jedoch nicht um diese Details kümmern, da sie für die Kombination von NumPy mit C- oder Fortran-Code relevanter sind.

Ebenso kann die Funktion „Zeros“ verwendet werden, um ein mit Nullen gefülltes Array zu erstellen. Sie können es auf die gleiche Weise wie solche verwenden. Denken Sie daran: Wenn Sie mehr über diese Funktionen erfahren möchten, können Sie die Hilfefunktion verwenden oder ein Fragezeichen (?) in Jupyter Lab oder IPython verwenden.

Es gibt auch die Funktion empty, die ein leeres Array erstellt, ohne dessen Werte zu initialisieren. In den meisten Fällen müssen Sie sich nicht um die Details dieser Funktion kümmern, da sie lediglich ein Array mit beliebigen Werten erstellt. Die Identitätsfunktion erstellt eine Identitätsmatrix, in der die Diagonalelemente Einsen und der Rest Nullen sind. Es kann verwendet werden, um eine Diagonalmatrix mit bestimmten Werten zu erstellen.

Kommen wir zur Indizierung: Die grundlegende Indizierung in NumPy-Arrays ähnelt der Indizierung in Python-Listen. Auf Elemente können Sie mit eckigen Klammern zugreifen. Array[0] gibt beispielsweise das erste Element zurück, Array[1] gibt das zweite Element zurück und so weiter. Auch Slicing ist möglich, genau wie bei Python-Listen. Array[1:4] gibt beispielsweise einen Ausschnitt des Arrays von Index 1 bis 3 (ausgenommen Index 4) zurück.

Wenn Sie mit zweidimensionalen Arrays arbeiten, können Sie eine Komma-Notation verwenden, um die beiden Dimensionen zu indizieren. Der erste Index gibt die Zeile an, während der zweite Index die Spalte angibt. Array[0, 0] gibt beispielsweise das Element in der ersten Zeile und ersten Spalte zurück, Array[1, 2] gibt das Element in der zweiten Zeile und dritten Spalte zurück und so weiter.

Mit negativer Indizierung kann auf Elemente vom Ende eines Arrays aus zugegriffen werden. Array[-1, -1] gibt beispielsweise das letzte Element im Array zurück. Ebenso gibt array[-1, -2] das vorletzte Element zurück. Dies kann bei der Arbeit mit großen Arrays hilfreich sein, da Sie die Array-Länge nicht im Auge behalten müssen.

Um eine ganze Zeile oder Spalte abzurufen, können Sie einen der Indizes weglassen. Beispielsweise gibt array[0, :] die gesamte erste Zeile und array[:, 1] die gesamte zweite Spalte zurück. Dies entspricht der Angabe des Indexbereichs (z. B. array[0, 0:3] für die erste Zeile). Das Slicing funktioniert in beiden Dimensionen, sodass Sie bestimmte Teile des Arrays auswählen können. Array[1:3, 2:4] gibt beispielsweise ein Unterarray zurück, das aus den Zeilen 1 und 2 (ohne Zeile 3) und den Spalten 2 und 3 (ohne Spalte 4) besteht.

Die boolesche Indizierung ist eine weitere leistungsstarke Funktion in NumPy. Sie können ein boolesches Array zum Indizieren eines Arrays verwenden und dabei nur die Elemente auswählen, die den wahren Werten im booleschen Array entsprechen. Angenommen, wir haben ein Array namens Array mit der Form (3, 3):

array( [[1, 2, 3] ,
       [4, 5, 6] ,
       [7, 8, 9] ])

Wir können ein boolesches Array basierend auf einer Bedingung erstellen, z. B. Array > 5, das das folgende boolesche Array zurückgibt:

array([[ False , False , False ],
       [ False , False , True ],
       [ True , True , True ]])
Wenn wir dieses boolesche Array als Index für das ursprüngliche Array verwenden, können wir nur die Elemente auswählen, die den wahren Werten entsprechen, was zu Folgendem führt:

array([6, 7, 8, 9])
Die boolesche Indizierung ermöglicht eine flexible und effiziente Auswahl von Elementen basierend auf bestimmten Bedingungen.

Zusätzlich zur grundlegenden Indizierung bietet NumPy erweiterte Indizierungstechniken, wie z. B. die Indizierung von ganzzahligen Arrays und die Verwendung von Arrays als Indizes. Diese Techniken ermöglichen komplexere und nicht zusammenhängende Indizierungsvorgänge für Arrays. Allerdings handelt es sich dabei um fortgeschrittenere Themen, die für die grundlegende Array-Manipulation möglicherweise nicht erforderlich sind.

4.2 NumPy Array Construction and Indexing (L04: Scientific Computing in Python)
4.2 NumPy Array Construction and Indexing (L04: Scientific Computing in Python)
  • 2020.09.20
  • www.youtube.com
This video explains how we can construct arrays in NumPy and how we access individual elements via indexing operations.Link to the Jupyter notebook: https://...
 

4.3 NumPy-Array-Mathematik und universelle Funktionen (L04: Wissenschaftliches Rechnen in Python)



4.3 NumPy-Array-Mathematik und universelle Funktionen (L04: Wissenschaftliches Rechnen in Python)

Nachdem wir viel Zeit in die Erstellung eines Rennens und die Indizierung einzelner Werte in einem Array investiert haben, wenden wir uns einem interessanteren Thema zu: Non-Pay-Array, Mathematik und universellen Funktionen.

Universelle Funktionen, oft als Ufunk oder Frank abgekürzt, sind ein leistungsstarkes Konzept in der Programmierung. Eine Universalfunktion (Ufunk) ist eine Kurzform einer Universalfunktion, die ein effizienteres und bequemeres Arbeiten mit Numpy-Arrays ermöglicht. Es führt ein Konzept namens Vektorisierung ein.

Bei der Vektorisierung wird eine mathematische oder arithmetische Operation an einer Folge von Objekten, beispielsweise einem Array, ausgeführt. Anstatt die Operation einzeln für jedes Element des Arrays auszuführen, ermöglicht uns die Vektorisierung, die Operation parallel auszuführen und dabei die fehlenden Abhängigkeiten zwischen den Elementen auszunutzen.

Betrachten wir zum Beispiel die Aufgabe, jedem Element in einem Array eine Zahl hinzuzufügen. Mit einer Python-for-Schleife würden wir jedes Element durchlaufen und eine Additionsfunktion aufrufen. Mit der Vektorisierung können wir die Addition jedoch gleichzeitig für das gesamte Array durchführen, ohne dass eine Schleife erforderlich ist. Dadurch wird die Effizienz deutlich verbessert.

In Numpy wird die Vektorisierung mithilfe universeller Funktionen (Ufunk) erreicht. In Numpy sind mehr als 60 Ufunk implementiert, von denen jeder einem bestimmten Zweck dient. Es wird empfohlen, die offizielle Dokumentation für eine vollständige Liste der verfügbaren Ufunk zu konsultieren.

Um das Konzept zu veranschaulichen, konzentrieren wir uns auf die elementweise Addition, eine häufige Operation. Angenommen, wir haben ein zweidimensionales Array, das als Liste von Listen in Python implementiert ist. Wenn wir zu jedem Element 1 hinzufügen möchten, verwenden wir normalerweise verschachtelte Schleifen oder Listenverständnisse. Allerdings können diese Ansätze insbesondere bei großen Arrays ineffizient sein.

In Numpy können wir den Ufunk „np.add“ verwenden, um die Zahl 1 vektorisiert zum gesamten Array hinzuzufügen. Dadurch entfällt die Notwendigkeit expliziter Schleifen und die Leistung wird erheblich verbessert.

Erwähnenswert ist, dass Numpy die Operatorüberlastung nutzt, was eine intuitive Nutzung von Ufunk ermöglicht. Wenn Sie beispielsweise den Operator „+“ zwischen einem Array und einer Zahl verwenden, wird automatisch der Ufunk „np.add“ aufgerufen.

Ein weiterer nützlicher Ufunk ist „np.square“, der jedes Element in einem Array quadriert. Ufunk-Funktionen können unär (mit einem einzelnen Wert arbeitend) oder binär (mit zwei Argumenten) sein. Die offizielle Numpy-Dokumentation enthält weitere Details zum verfügbaren Ufunk.

Kommen wir nun zu einem interessanteren Fall: Lassen Sie uns die Verwendung von Ufunk in Verbindung mit der „reduce“-Methode untersuchen. Die Operation „Reduzieren“ wendet eine Operation entlang einer angegebenen Achse an und reduziert so mehrere Werte auf einen einzigen Wert. Beispielsweise können wir Spaltensummen berechnen, indem wir „np.add“ mit der Methode „reduce“ verwenden.

In diesem Szenario bewegen wir uns über die angegebene Achse (in diesem Fall Achse 0) und kombinieren die Elemente mithilfe der angegebenen Operation. Der Vorgang „Reduzieren“ wird häufig mit Konzepten wie „Map Reduce“ und Hadoop in Verbindung gebracht, bei denen Berechnungen auf mehrere Knoten verteilt und dann kombiniert werden, um das Endergebnis zu erzeugen.

Auch wenn dies überwältigend erscheinen mag, ermöglicht das Verständnis dieser Konzepte eine effizientere und effektivere Programmierung mit Numpy. Durch die Nutzung von Ufunk und Vektorisierung können wir problemlos komplexe Operationen an Arrays durchführen und unseren Code für eine verbesserte Leistung optimieren.

Denken Sie daran, in der offiziellen Numpy-Dokumentation eine umfassende Liste der verfügbaren Ufunk sowie Beispiele und Nutzungsrichtlinien zu lesen. Die Erkundung der Möglichkeiten von Ufunk wird Ihr Toolkit erweitern und Ihnen helfen, verschiedene Rechenaufgaben in zukünftigen Projekten zu bewältigen.

In NumPy gibt es also eine Funktion namens Reduce, die es uns ermöglicht, Reduktionsoperationen entlang einer angegebenen Achse eines Arrays durchzuführen. Die Reduktionsoperation kombiniert mehrere Werte zu einem einzigen Wert. Standardmäßig wird die Reduzierung entlang der ersten Achse (Achse 0) des Arrays angewendet.

Nehmen wir ein Beispiel, um dieses Konzept besser zu verstehen. Betrachten Sie das folgende Array:

array( [[1, 2, 3] ,
       [4, 5, 6] ,
       [7, 8, 9] ])
Wenn wir die Spaltensummen berechnen möchten, können wir die Reduzierungsfunktion verwenden. Dieser Vorgang führt einen Rollvorgang über die erste Achse (Achse 0) durch und kombiniert die Werte in jeder Spalte. Das Ergebnis ist also ein eindimensionales Array, das die Summen jeder Spalte enthält.

Um dies zu erreichen, können wir die Funktion np.add verwenden, die eine elementweise Addition durchführt. Wir übergeben np.add als zu reduzierendes Funktionsargument und geben damit an, dass wir die Werte entlang der angegebenen Achse addieren möchten.

So sieht der Code aus:

import numpy as np

array = np. array ([[ 1 , 2 , 3 ],
                  [ 4 , 5 , 6 ],
                  [ 7 , 8 , 9 ]])

column_sums = np.reduce(np.add, array )
print (column_sums)
Die Ausgabe wird sein:

[12 15 18]
In diesem Beispiel durchläuft die Reduce-Funktion die Spalten des Arrays und addiert die Werte. Es kombiniert die erste Spalte (1 + 4 + 7), die zweite Spalte (2 + 5 + 8) und die dritte Spalte (3 + 6 + 9) in einem einzigen Array, das die Spaltensummen darstellt.

Dieser Ansatz ist effizienter, als die Spalten manuell zu durchlaufen und die Werte einzeln hinzuzufügen. Die von NumPy bereitgestellte vektorisierte Operation ermöglicht es uns, die Berechnung parallel durchzuführen und dabei optimierte zugrunde liegende Algorithmen zu nutzen.

Beachten Sie, dass Reduce je nach der auszuführenden Operation auch mit verschiedenen anderen Funktionen außer np.add verwendet werden kann. Das Konzept der Reduzierung ist wirkungsvoll und kann auf viele verschiedene Szenarien angewendet werden.

4.3 NumPy Array Math and Universal Functions (L04: Scientific Computing in Python)
4.3 NumPy Array Math and Universal Functions (L04: Scientific Computing in Python)
  • 2020.09.20
  • www.youtube.com
This video discusses one of the core aspects of NumPy: it's functions that allow us to work with NumPy arrays efficiently.Jupyter notebook: https://github.co...
 

4.5 NumPy Advanced Indexing – Speicheransichten und Kopien (L04: Wissenschaftliches Rechnen in Python)



4.5 NumPy Advanced Indexing – Speicheransichten und Kopien (L04: Wissenschaftliches Rechnen in Python)

In diesem fünften Video befassen wir uns noch einmal intensiv mit dem Thema Indexierung. Im Gegensatz zum ersten Video, in dem wir uns mit der grundlegenden Indizierung befasst haben, werden wir uns nun mit der erweiterten Indizierung befassen. In diesem Abschnitt werden Konzepte wie Speicheransichten und das Erstellen von Speicherkopien vorgestellt. Dabei handelt es sich um wichtige Vorgehensweisen zur Vermeidung unbeabsichtigter Fehler, z. B. des versehentlichen Überschreibens von Array-Werten. Es ist wichtig, dies zu verstehen, da es uns hilft, Fehler und unerwartetes Verhalten in NumPy zu verhindern.

Jetzt fangen wir an. Im vorherigen Abschnitt haben wir einen Aspekt von NumPy-Arrays namens „Ansichten“ besprochen. Ansichten werden erstellt, wenn wir reguläre Indizierungs- oder grundlegende Slicing-Vorgänge verwenden. Diese Ansichten fungieren als implizite Dimensionen und ermöglichen es uns, Operationen durchzuführen, die im strengen mathematischen Rahmen der linearen Algebra nicht möglich sind. Das Arbeiten mit Ansichten kann jedoch riskant sein, da wir möglicherweise versehentlich das ursprüngliche Array ändern, ohne es zu merken.

Um dies zu veranschaulichen, betrachten wir ein einfaches Beispiel. Angenommen, wir haben ein zweidimensionales Array mit zwei Zeilen und drei Spalten. Der Einfachheit halber werde ich die erste Zeile einer separaten Variablen namens „first_row“ zuweisen. Hier kommt nun der entscheidende Punkt: Durch die Zuweisung der ersten Zeile zu einer Variablen wird eine Ansicht erstellt, kein neues Objekt. Dies bedeutet, dass diese Variable lediglich auf den Speicherort des ursprünglichen Arrays verweist. Wenn wir also die Werte in dieser Variablen ändern, ändern wir auch die entsprechenden Werte im ursprünglichen Array.

Um dies zu demonstrieren, erhöhen wir jedes Element in der Variablen „first_row“ um 99. Durch die Ausführung dieser Operation werden nicht nur die Werte in der Variablen geändert, sondern auch die Werte in der ersten Zeile des ursprünglichen Arrays überschrieben. Dieses Verhalten ist ein Hinweis darauf, dass wir mit einer Ansicht und nicht mit einem unabhängigen Objekt arbeiten. Sich dessen nicht bewusst zu sein, kann gefährlich sein, da es beim Arbeiten mit einer Ansicht leicht passieren kann, dass Werte im ursprünglichen Array unbeabsichtigt überschrieben werden.

Andererseits können Ansichten für die Speichereffizienz unglaublich nützlich sein, da sie es uns ermöglichen, unnötige Array-Kopien zu vermeiden. Es gibt jedoch Situationen, in denen wir möglicherweise explizit eine Kopie eines Arrays erstellen möchten. Zu diesem Zweck können wir die Funktion „Kopieren“ verwenden, die ein neues Array mit denselben Werten wie das Original generiert. Im bereitgestellten Beispiel erstelle ich mit der Funktion „Kopieren“ eine Kopie der zweiten Zeile des Arrays. Dadurch haben Änderungen an der Variablen „first_row“ keinen Einfluss auf das ursprüngliche Array.

Es ist wichtig zu beachten, dass Slicing und ganzzahlbasierte Indizierung zwar Speicheransichten erstellen, es aber eine andere Art der Indizierung namens „Fancy Indexing“ gibt, die Kopien des Arrays erstellt. Unter ausgefallener Indizierung versteht man die Verwendung mehrerer ganzzahliger Indizes, um bestimmte Elemente aus einem Array auszuwählen. Diese Funktion wird als „fancy“ bezeichnet, da sie in regulären Python-Listen nicht unterstützt wird. NumPy ermöglicht uns jedoch die Durchführung dieser Art der Indizierung, die sehr leistungsfähig sein kann.

Beispielsweise können wir in einer regulären Python-Liste nicht gleichzeitig das erste und dritte Element abrufen. Doch in NumPy können wir dies durch eine ausgefallene Indizierung erreichen. Ebenso können wir eine ausgefallene Indizierung verwenden, um bestimmte Spalten aus einem zweidimensionalen Array auszuwählen. Es ist erwähnenswert, dass eine ausgefallene Indizierung immer zu einer Kopie des Arrays und nicht zu einer Ansicht führt.

Die Unterscheidung zwischen Ansichten und Kopien hängt mit den Effizienzüberlegungen in NumPy zusammen. Durch das Slicing können wir bestimmte Werte im Speicher zwischenspeichern und so die Leistung optimieren. Die Implementierung dieses Caching-Mechanismus mit ausgefallener Indizierung ist jedoch nicht einfach, da wir keinen zusammenhängenden Speicherblock extrahieren können. Stattdessen wählen wir einzelne Werte aus, was zur Erstellung eines neuen Arrays führt. Dieses Verhalten erklärt, warum die ausgefallene Indizierung eher Kopien als Ansichten erzeugt.

Ein weiterer interessanter Aspekt der ausgefallenen Indizierung besteht darin, dass wir damit die Reihenfolge der Spalten in einem Array ändern können. Indem wir die gewünschten Spaltenindizes mithilfe einer ausgefallenen Indizierung angeben, können wir die Spalten nach Bedarf neu anordnen.

Boolesche Masken in NumPy sind eine effiziente und leistungsstarke Möglichkeit, Arrays basierend auf bestimmten Bedingungen zu filtern. Eine boolesche Maske ist einfach ein NumPy-Array boolescher Werte (True oder False), das dieselbe Form wie das ursprüngliche Array hat. Indem wir die boolesche Maske auf das ursprüngliche Array anwenden, können wir die Elemente auswählen, die die gegebene Bedingung erfüllen, und den Rest verwerfen.

Um eine boolesche Maske zu erstellen, definieren wir zunächst eine Bedingung, die für jedes Element im Array einen booleschen Wert zurückgibt. Nehmen wir zum Beispiel an, wir haben ein Array namens arr:

import numpy as np
arr = np.array([1, 2, 3, 4, 5])
Wir können eine boolesche Maske basierend auf einer Bedingung erstellen, z. B. indem wir nur die Elemente auswählen, die größer als 3 sind:
mask = arr > 3
Die resultierende boolesche Maske mask ist [False, False, False, True, True]. Jedes Element in der Maske entspricht derselben Position im ursprünglichen Array und gibt an, ob die Bedingung für dieses Element wahr oder falsch ist.

Um die boolesche Maske anzuwenden und die Elemente abzurufen, die die Bedingung erfüllen, können wir die Maske einfach als Index für das Array verwenden:

filtered_arr = arr[mask]
Das resultierende filtered_arr ist [4, 5] und enthält nur die Elemente größer als 3 aus dem ursprünglichen Array.

Boolesche Masken können mit logischen Operatoren wie & (und), | kombiniert werden (oder) und ~ (nicht), um komplexere Bedingungen zu erstellen. Zum Beispiel:

mask = (arr > 2) & (arr < 5)
filtered_arr = arr[mask]
Diese Bedingung wählt Elemente aus, die größer als 2 und kleiner als 5 sind, was dazu führt, dass filtered_arr [3, 4] ist.

Boolesche Masken sind besonders nützlich, wenn Sie mit großen Datensätzen arbeiten oder Daten filtern und analysieren. Sie ermöglichen effiziente und präzise Operationen an Arrays, ohne dass explizite Schleifen oder Bedingungsprüfungen erforderlich sind.

Neben der Filterung von Arrays können boolesche Masken auch zur Elementzuordnung verwendet werden. Indem wir den ausgewählten Elementen über die Boolesche Maske neue Werte zuweisen, können wir bestimmte Teile des Arrays basierend auf einer Bedingung ändern.

Insgesamt bieten boolesche Masken eine flexible und effiziente Möglichkeit, NumPy-Arrays basierend auf bestimmten Bedingungen zu manipulieren und zu filtern, was sie zu einem wertvollen Werkzeug bei der Datenverarbeitung und -analyse macht.

4.5 NumPy Advanced Indexing -- Memory Views and Copies (L04: Scientific Computing in Python)
4.5 NumPy Advanced Indexing -- Memory Views and Copies (L04: Scientific Computing in Python)
  • 2020.09.20
  • www.youtube.com
We previously covered basic indexing. NumPy allows us to perform more advanced indexing beyond what regular Python lists are capable of. Jupyter notebook: ht...