Machine Learning für Softwareentwickler. Paolo Perrotta. Читать онлайн. Newlib. NEWLIB.NET

Автор: Paolo Perrotta
Издательство: Bookwire
Серия:
Жанр произведения: Математика
Год издания: 0
isbn: 9783969100264
Скачать книгу
den Zeilendaten Spaltendaten und umgekehrt. Die Dimensionen der Matrix werden vertauscht. In dem vorstehenden Beispiel wird aus der (4, 3)-Matrix durch Transponieren eine (3, 4)-Matrix.

      Jetzt wissen Sie, wie die Matrizenmultiplikation und die Transposition funktionieren. Beide Operationen werden wir in Kürze benötigen. Kehren wir nun aber wieder zu unserem Code zurück.

      Nach diesem mathematischen Exkurs kommen wir wieder zu unserer praktischen Arbeit zurück. Wir möchten unser ML-Programm so erweitern, dass es mit mehreren Eingabevariablen umgehen kann. Um den Überblick zu behalten, stellen wir zunächst einen Plan dafür auf:

       Erstens müssen wir die mehrdimensionalen Daten laden und aufbereiten, sodass wir sie in den Lernalgorithmus einspeisen können.

       Anschließend müssen wir alle Funktionen in unserem Code so anpassen, dass sie das neue Modell nutzen. Wie im Abschnitt »Noch mehr Dimensionen« auf Seite 58 beschrieben, gehen wir von einer Geradengleichung zu einer allgemeinen gewichteten Summe über.

      Diesen Plan werden wir nun Schritt für Schritt abarbeiten. Sie können die Befehle dabei gern in einen Python-Interpreter eingeben und selbst damit herumexperimentieren. Wenn Sie keinen Interpreter zu Hand haben, ist das jedoch auch kein Beinbruch, denn ich werde die Ausgaben aller wichtigen Befehle hier wiedergeben (wenn auch teilweise aus Platzgründen etwas bearbeitet).

      Ich wünschte, ich könnte Ihnen jetzt erzählen, dass sich bei ML alles darum dreht, fantastische KIs zu konstruieren und dabei den coolen Experten zu geben. In Wirklichkeit besteht ein Großteil der Arbeit jedoch darin, Daten für den Lernalgorithmus aufzubereiten. Dabei gehen wir wieder von der Datei mit unserer Datenmenge aus:

image

      In den vorherigen Kapiteln bestand diese Datei aus zwei Spalten, die wir mit der NumPy-Funktion loadtxt() in zwei Arrays geladen haben. Mehr war dazu nicht nötig. Da wir jetzt mehrere Eingabevariablen haben, hat X nun aber die Form einer Matrix:

image

      Jede Zeile von X ist ein Beispiel und jede Spalte eine Eingabevariable.

      Wenn wir die Datei wie zuvor mit loadtxt() laden, erhalten wir für jede Spalte ein NumPy-Array:

       import numpy as np

      x1, x2, x3, y = np.loadtxt("pizza_3_vars.txt", skiprows=1, unpack=True)

      Arrays sind das Merkmal, bei dem NumPy richtig glänzt! Es handelt sich um flexible Objekte, die alles Mögliche von einem Skalar (einer einzelnen Zahl) bis zu mehrdimensionalen Strukturen darstellen können. Diese Flexibilität macht den Umgang mit den Arrays jedoch zu Anfang auch etwas schwer. Ich werde Ihnen zeigen, wie Sie diese vier Arrays zu den Variablen X und Y umformen, die wir benötigen, aber wenn Sie diese Arbeiten selbst erledigen, ist es am besten, die Dokumentation von NumPy zur Hand zu haben.

      Um zu sehen, welche Dimensionen ein Array aufweist, verwenden wir die Operation shape():

      x1.shape # => (30, )

      Alle vier Spalten haben 30 Elemente, eines für jedes Beispiel in pizza_3_vars.txt. Das Komma am Ende ist die NumPy-Schreibweise dafür, dass diese Arrays nur jeweils eine Dimension aufweisen. Sie sind also weniger Matrizen als vielmehr das, was man sich gewöhnlich unter einem Array vorstellt.

      Wir wollen nun die Matrix X zusammenstellen, indem wir die ersten drei Arrays miteinander verbinden:

      X = np.column_stack((x1, x2, x3))

      X.shape # => (30, 3)

      Die ersten beiden Zeilen von X sehen nun wie folgt aus:

      X[:2] # => array([[13., 26., 9.], [2., 14., 6.]])

      Mit der Indizierung in NumPy lässt sich sehr viel anfangen, allerdings kann sie manchmal auch etwas verwirrend wirken. Die Schreibweise [:2] ist eine Abkürzung für [0:2] und bedeutet »die Zeilen vom Index 0 bis ausschließlich Index 2«, also die ersten beiden Zeilen.

      So viel zu X. Kümmern wir uns nun um y, das immer noch die eindimensionale Form (30, ) aufweist. Grundsätzlich sollten es NumPy-Matrizen nicht mit eindimensionalen Arrays vermischen. Code, in dem beides vorkommt, legt manchmal überraschendes Verhalten an den Tag. Aus diesem Grunde ist es am besten, eindimensionale Arrays mit der Funktion reshape() wie folgt in eine Matrix umzuwandeln. Dieser kleine Trick hat mir schon manchmal den Hals gerettet.

      Y = y.reshape(-1, 1)

      reshape() nimmt die Dimensionen des neuen Arrays entgegen. Wenn eine dieser Dimensionen –1 ist, dann setzt NumPy sie auf einen passenden Wert für die anderen Dimensionen. Die obige Zeile bedeutet also: »Gestalte Y zu einer Matrix mit einer Spalte und so vielen Zeilen um, wie für die aktuelle Anzahl der Elemente nötig sind.« Dadurch ergibt sich eine (30, 1)-Matrix:

image

      Y.shape # => (30, 1)

      Damit haben wir unsere Daten jetzt sauber in einer Matrix X für Eingabevariablen und einer Matrix Y für die Labels angeordnet. Den Punkt »Datenaufbereitung« können wir damit abhaken. Als Nächstes ändern wir die Funktionen unseres Lernsystems. Dabei fangen wir mit der Funktion predict() an.

      Da wir jetzt mehrere Eingabevariablen haben, müssen wir die Vorhersageformel von einer einfachen Geradengleichung in eine gewichtete Summe ändern:

      ŷ = x1 * w1 + x2 * w2 + x3 * w3 + ...

      Wahrscheinlich ist Ihnen aufgefallen, dass in dieser Formel etwas fehlt. Zur Vereinfachung habe ich vorübergehend den Bias b weggelassen. Er wird aber bald wieder zurück sein.

      Jetzt können wir die angegebene gewichtete Summe in eine mehrdimensionale Version von predict() umwandeln. In der eindimensionalen Version sah diese Formel wie folgt aus (hier ohne Bias):

      def predict(X, w):

      return X * w

      Die neue Version von predict() nimmt nach wie vor X und w entgegen, wobei diese Variablen jetzt aber mehr Dimensionen haben. Bisher war X ein Vektor aus m Elementen, wobei m der Anzahl der Beispiele entsprach. Jetzt ist es eine (m, n)-Matrix, wobei n die Anzahl der Eingabevariablen ist. In dem hier betrachteten Fall haben wir 30 Beispiele und drei Eingabevariablen, weshalb X eine (830, 3)-Matrix ist.

      Wie sieht es mit w aus? Pro Eingabevariable brauchen wir jetzt nicht nur ein x, sondern auch ein w. Anders als die x-Werte sind die w-Werte jedoch für jedes Beispiel gleich. Für die Gewichte können wir daher eine (n, 1)- oder eine (1, n)-Matrix verwenden. Wie wir gleich sehen werden, ist eine (n, 1)-Matrix besser geeignet, also eine Matrix mit einer einzigen Spalte und je einer Zeile pro Eingabevariable.

      Diese Matrix müssen wir nun initialisieren. Bisher haben wir w einfach mit 0 initialisiert, doch da w nun eine Matrix ist, müssen wir alle ihre Elemente auf 0 setzen. Dafür gibt es in NumPy die Funktion zeros():

      w = np.zeros((X.shape[1], 1))

      w.shape # => (3, 1)

      X.shape[0] gibt die Anzahl der Zeilen und X.shape[1] die Anzahl der Spalten in X an. Der vorstehende Code besagt also, dass w so viele Zeilen haben soll, wie es Spalten in X gibt, hier also drei.

      An dieser Stelle kommt nun die Matrizenmultiplikation ins Spiel. Schauen Sie sich noch einmal die gewichtete Summe an:

      ŷ = x1 * w1 + x2 * w2 + x3 * w3

      Wenn