Beim Versuch, maschinelles Lernen mit Java oder Scala durchzuführen, haben viele Leute erfahren, dass es kein cooles Grafiktool gibt und dass Python Matplotlib hat.
Aus diesem Grund habe ich Matplotlib4j erstellt, eine Bibliothek, mit der Sie Matplotlib von Java aus aufrufen können. Daher möchte ich sie vorstellen.
Hier ist ein Beispiel für Java. Natürlich kann es auch aus anderen JVM-Sprachen wie Scala und Kotlin verwendet werden. Ein Beispiel wird später beschrieben.
Fügen Sie zunächst Matplotlib4j zu dem Java-Projekt hinzu, in dem Sie Matplotlib verwenden möchten.
Fügen Sie für Maven die folgende Abhängigkeit hinzu.
Maven
<dependency>
<groupId>com.github.sh0nk</groupId>
<artifactId>matplotlib4j</artifactId>
<version>0.4.0</version>
</dependency>
In ähnlicher Weise sieht es für Gradle folgendermaßen aus:
Gradle
compile 'com.github.sh0nk:matplotlib4j:0.4.0'
Die Verwendung ähnelt der Matplotlib-API, sodass Sie sie intuitiv schreiben können. Erstellen Sie zuerst ein Plot-Objekt, fügen Sie ein beliebiges Diagramm hinzu, indem Sie die pyploy-Methode aufrufen, und rufen Sie schließlich die show () -Methode auf. Da es sich um ein Builder-Muster handelt, werden wir mithilfe der IDE-Vervollständigung Optionen dahinter hinzufügen.
Zeichnen wir als Ausgangspunkt ein Streudiagramm.
ScatterPlot
List<Double> x = NumpyUtils.linspace(-3, 3, 100);
List<Double> y = x.stream().map(xi -> Math.sin(xi) + Math.random()).collect(Collectors.toList());
Plot plt = Plot.create();
plt.plot().add(x, y, "o").label("sin");
plt.legend().loc("upper right");
plt.title("scatter");
plt.show();
Einige Numpy-Methoden, wie z. B. "linspace" und "meshgrid", werden als "NumpyUtils" -Klassen bereitgestellt, damit Sie Diagramme zeichnen können. Wir generieren x- und y-Daten für das Plotten im ersten Block. Hier wird der Sinuskurve ein zufälliger Wert gegeben. Erstellen Sie danach ein Plot-Objekt, fügen Sie das generierte x und y zur plot ()
-Methode hinzu und rufen Sie schließlichshow ()
auf, um das Diagramm zu zeichnen.
Dies entspricht in etwa der folgenden Python-Implementierung (fast, weil der Datengenerierungsteil von numpy streng unterschiedlich ist). Die Methoden heißen ähnlich und sind für Pythonista einfacher zu verwenden.
PythonScatterPlot
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-3, 3, 100)
y = np.sin(x) + np.random.rand(100)
plt.plot(x, y, "o", label="sin")
plt.legend(loc="upper right")
plt.title("scatter")
plt.show()
Mit dem obigen Java-Code können Sie das folgende Diagramm zeichnen.
Als nächstes zeichnen wir ein Konturdiagramm (Konturlinie).
ContourPlot
List<Double> x = NumpyUtils.linspace(-1, 1, 100);
List<Double> y = NumpyUtils.linspace(-1, 1, 100);
NumpyUtils.Grid<Double> grid = NumpyUtils.meshgrid(x, y);
List<List<Double>> zCalced = grid.calcZ((xi, yj) -> Math.sqrt(xi * xi + yj * yj));
Plot plt = Plot.create();
ContourBuilder contour = plt.contour().add(x, y, zCalced);
plt.clabel(contour)
.inline(true)
.fontsize(10);
plt.title("contour");
plt.show();
Sie können ein Histogramm auf die gleiche Weise zeichnen.
HistogramPlot
Random rand = new Random();
List<Double> x1 = IntStream.range(0, 1000).mapToObj(i -> rand.nextGaussian())
.collect(Collectors.toList());
List<Double> x2 = IntStream.range(0, 1000).mapToObj(i -> 4.0 + rand.nextGaussian())
.collect(Collectors.toList());
Plot plt = Plot.create();
plt.hist()
.add(x1).add(x2)
.bins(20)
.stacked(true)
.color("#66DD66", "#6688FF");
plt.xlim(-6, 10);
plt.title("histogram");
plt.show();
Matplotlib4j unterstützt auch das Speichern in Dateien. Das Speichern von Bilddateien ist praktisch für Anwendungsfälle ohne GUI, z. B. für die regelmäßige Verarbeitung des maschinellen Lernens auf dem Server.
Ähnlich wie bei der ursprünglichen Matplotlib wird das Bild mithilfe der Methode ".savefig ()" anstelle von ".show ()" in einer Datei gespeichert, anstatt das Plotfenster aufzurufen. Der einzige Unterschied besteht darin, dass auf ".savefig ()" "plt.executeSilently ()" folgt. (Dies ist als Beendigungsverarbeitung erforderlich, da der Befehl savefig auch durch eine Methodenkette verbunden ist.)
Random rand = new Random();
List<Double> x = IntStream.range(0, 1000).mapToObj(i -> rand.nextGaussian())
.collect(Collectors.toList());
Plot plt = Plot.create();
plt.hist().add(x).orientation(HistBuilder.Orientation.horizontal);
plt.ylim(-5, 5);
plt.title("histogram");
plt.savefig("/tmp/histogram.png ").dpi(200);
//Erforderlich, um die Datei auszugeben
plt.executeSilently();
Infolgedessen wird das folgende Bild ausgegeben.
Um Matplotlib4j verwenden zu können, müssen Sie Python mit installiertem Matplotlib verwenden. Standardmäßig verwendet Matplotlib4j Python, das sich im Pfad befindet, aber ich denke, es gibt viele Fälle, in denen Matplotlib nicht im Standard-Python des Systems installiert ist.
In diesem Fall können Sie mit pyenv oder pyenv-virtualenv zu einer Python-Umgebung mit installiertem Matplotlib wie Anaconda wechseln.
Um Python gemäß der Umgebung von Pyenv zu verwenden, geben Sie PythonConfig wie folgt an, wenn Sie ein Plot-Objekt erstellen.
pyenv
Plot plot = Plot.create(PythonConfig.pyenvConfig("Beliebiger pyenv-Umgebungsname"));
Ebenso können Sie den Umgebungsnamen von pyenv-virtualenv angeben.
pyenv-virtualenv
Plot plot = Plot.create(PythonConfig.pyenvVirtualenvConfig("Beliebiger pyenv-Umgebungsname", "Beliebiger Name der virtuellen Umgebung"));
Scala
Bei Verwendung von Scala kann das obige Beispiel des Streudiagramms wie folgt geschrieben werden. Beachten Sie zu diesem Zeitpunkt den Unterschied zwischen den Klassen Box / Unbox und List.
ScalaScatter
import scala.collection.JavaConverters._
val x = NumpyUtils.linspace(-3, 3, 100).asScala.toList
val y = x.map(xi => Math.sin(xi) + Math.random()).map(Double.box)
val plt = Plot.create()
plt.plot().add(x.asJava, y.asJava, "o")
plt.title("scatter")
plt.show()
Vor kurzem habe ich angefangen zu lesen "Deep Learning von Grund auf neu - Die Theorie und Implementierung von Deep Learning, das mit Python gelernt wurde", aber mit Python wie es ist Es macht keinen Spaß, es zu kopieren, deshalb habe ich beschlossen, es mit Scala zu implementieren, was ich in letzter Zeit sehr berührt habe. Ich konnte es wie einen Funktionstyp in Scala schreiben und war sehr zufrieden damit, aber erst als ich mich der Ausbreitung mit der steilsten Abstiegsmethode näherte, ging der Verlust überhaupt nicht zurück, gibt es nicht irgendwo einen Fehler? Ich bin in die Situation geraten.
Natürlich denke ich, dass es in solchen Fällen eine gängige Praxis ist, die Sie durch Verdicken des Tests verstehen können, aber zuerst möchte ich die Grafik schnell wie im Buch anzeigen und sehen, was passiert. Aber mit Scala gibt es kein cooles Grafikwerkzeug ... Die Implementierung des Grafikwerkzeugs von Grund auf ist jedoch zu schrecklich ... Deshalb habe ich mich für Matplotlib entschieden, das mit Python vertraut ist, und das war der Grund für die Erstellung der Bibliothek.
Matplotlib4j ruft Matplotlib in Form der Generierung von Python-Code ohne Verwendung von JNI oder Jython auf. Zuerst dachte ich, ich würde es mit Jython implementieren, aber in erster Linie unterstützt die Python-Version nur bis zu 2.7, und numpy kann nicht verwendet werden, daher hängt es davon ab. Ich habe beschlossen, diesen Weg aufzugeben, weil Matplotlib auch nicht funktioniert.
Es gibt auch eine Bibliothek, mit der CPython aus Java-Code verwendet werden kann. Dies ist ein Kandidat, da sowohl Python3 als auch Numpy verwendet werden können. Um JNI verwenden zu können, wird eine umgebungsabhängige Bibliothek separat installiert. Auf der Python-Seite muss die Bibliothek von pip aus installiert werden, sodass es zu lange dauert, sie nur zum Zeichnen eines Diagramms zu verwenden. Immerhin habe ich beschlossen, es unabhängig von diesen Bibliotheken zu implementieren.
Da es über eine Datei ausgeführt wird, muss natürlich festgelegt werden, wie Variablen übergeben und der Rückgabewert verwendet werden sollen. Ist die Leistung in Ordnung? Ich mache mir darüber Sorgen. Da der Zweck nur darin besteht, Diagramme zu zeichnen, können die Grundfunktionen glücklicherweise durch einseitige Ausgabe in eine Datei erfüllt werden, und ich denke, dass einige Wartezeiten für die Leistung innerhalb des zulässigen Bereichs liegen.
Recommended Posts