[Einführung in die Informatik Teil 2: Versuchen Sie maschinelles Lernen] Lassen Sie uns die k-Mittelungsmethode in Java-Abstand zwischen Daten implementieren.

Einführung

Hallo, das ist Sumiyama Wasser.

Fortsetzung der vorherigen Sitzung. [Einführung in die Informatik Teil 1: Versuchen wir es mit maschinellem Lernen] Implementieren wir die k-Mittelungsmethode in Java - Über das Konzept der Koordinaten-

Beim letzten Mal habe ich das Konzept von Koordinaten ausprobiert, um Daten in einer Ebene oder einem Raum anzuordnen und in Java auszudrücken.

Dieses Mal werde ich über das Konzept der Entfernung zwischen Daten sprechen.

Umgebung

Ich habe in diesem Artikel über die Vorbereitung dieser Umgebung geschrieben. Hinweise zum Starten der Neuentwicklung mit IntelliJ + Gradle + SpringBoot + JUnit5 (Jupiter)

Wenn Sie noch einmal darüber nachdenken, wie groß ist die Entfernung?

Wie ich in Teil 0 erwähnt habe, möchte ich mit Clustering ** nahe Daten sammeln **, aber dann werde ich definieren, dass ** Daten nahe beieinander liegen **. wird gebraucht.

Zum Beispiel in dem in der Abbildung gezeigten Fall

image.png

Nun, es ist für das menschliche Auge offensichtlich, aber da es der Computer ist, der es berechnet, wird ** nah ** / ** fern ** numerisch ausgedrückt.

Verwenden Sie daher im Computer den Wert ** distance **,

―― Je größer der Abstandswert, desto weiter

Sie können numerisch wie folgt vergleichen [^ 1].

Verwenden Sie den euklidischen Abstand

Eigentlich gibt es so viele Möglichkeiten, die Entfernung zu berechnen, dass die Forschung von selbst durchgeführt werden kann, aber dieses Mal werde ich die ** euklidische Entfernung ** verwenden, die einfach zu berechnen und der Mechanismus visuell leicht zu verstehen ist.

Es hat einen großen Namen, aber kurz gesagt, es ist ein normaler Abstand **, der beim Messen zwischen zwei Punkten mit einem Lineal sichtbar wird. Es ist jedoch nicht möglich, den Computer ein Lineal für jede Daten verwenden zu lassen, daher wird es durch Berechnung berechnet.

image.png

Bitte sehen Sie die Abbildung. Erinnerst du dich an den Drei-Quadrat-Satz? Der Punkt ist, dass. Die Punkte an den Koordinaten [1,4] und die Punkte an den Koordinaten [5,1] sind die horizontale Richtung (das erste Element jeder Koordinate) und die vertikale Richtung (das zweite Element jeder Koordinate). ) Ist das Quadrat der Differenz, die Summe ist die Quadratwurzel und der Abstand ist 5.

Übrigens kann es beliebig erweitert werden, da es auf die gleiche Weise berechnet werden kann, unabhängig davon, ob es sich um 3D oder höher handelt.

Die Abstände in den drei Dimensionen [3,1,2] und [1,0,6] sind image.png Es wird sein. Wenn die Anzahl der Dimensionen zunimmt, ist es in Ordnung, wenn Sie die Anzahl der hinzuzufügenden Dimensionen erhöhen.

Lassen Sie uns implementieren

package net.tan3sugarless.clusteringsample.lib.data;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.ToString;
import lombok.Value;
import net.tan3sugarless.clusteringsample.exception.DimensionNotUnifiedException;
import net.tan3sugarless.clusteringsample.exception.NullCoordinateException;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 *Koordinatensatz auf dem euklidischen Distanzraum
 */
@Getter
@ToString
@EqualsAndHashCode
@Value
public class EuclideanSpace {

    private final List<List<Double>> points;
    private final int dimension;

    /**
     *Legen Sie eine Liste mit n-dimensionalen Koordinaten und Dimensionen fest
     *
     * @param points :Liste der n-dimensionalen Koordinaten
     * @throws DimensionNotUnifiedException :Ich habe eine Liste erstellt, in der die Abmessungen der Koordinaten nicht einheitlich sind
     * @throws NullCoordinateException      :Der numerische Wert der Koordinate enthielt null
     * @throws NullPointerException         :Übergebene Nulldaten oder Daten, die Nullelemente enthalten
     */
    public EuclideanSpace(List<List<Double>> points) {
        if (points.stream().mapToInt(List::size).distinct().count() > 1) {
            throw new DimensionNotUnifiedException();
        }
        if (points.stream().anyMatch(point -> point.stream().anyMatch(Objects::isNull))) {
            throw new NullCoordinateException();
        }

        this.points = points;
        this.dimension = points.stream().findFirst().map(List::size).orElse(0);
    }

    /**
     *Berechnen Sie den Abstand jeder in dieser Instanz gespeicherten Koordinate von einer beliebigen Koordinate
     *
     * @param target Koordinaten des Referenzpunkts, an dem Sie den Abstand von jeder Koordinate berechnen möchten
     * @Eine Liste der euklidischen Entfernungen vom Rückkehrziel
     * @throws DimensionNotUnifiedException :Ziel- und Instanzdimensionen sind unterschiedlich
     * @throws NullCoordinateException      :Ziel enthält null
     */
    public List<Double> distanceFromTarget(List<Double> target) {
        if (target.size() != dimension) {
            throw new DimensionNotUnifiedException();
        }

        if (target.stream().anyMatch(Objects::isNull)) {
            throw new NullCoordinateException();
        }

        return points.stream().map(point -> {
            double squareOfDistance = 0.0;
            for (int i = 0; i < target.size(); i++) {
                squareOfDistance += Math.pow(point.get(i) - target.get(i), 2);
            }

            return Math.sqrt(squareOfDistance);
        }).collect(Collectors.toList());
    }
}

Wir werden es in derselben Klasse wie [Letztes Mal] erstellen (https://qiita.com/tan3_sugarless/items/364bf63680018e722b4e).

Zunächst haben wir die Konstruktoren und Felder ein wenig geändert, um die Überprüfung der Dimensionen zu vereinfachen.

    private final int dimension;

Ich habe es möglich gemacht, Dimensionen im int-Feld zu speichern.

        this.dimension = points.stream().findFirst().map(List::size).orElse(0);

Es ist eine logische Ergänzung, um die Dimension der erfassten Daten zu berechnen.

Und hier ist die Methode, um die Entfernung tatsächlich zu berechnen. In der zukünftigen Implementierung möchte ich "den Abstand zwischen einem bestimmten Punkt und allen Koordinaten" berechnen, also sieht es so aus.

    /**
     *Berechnen Sie den Abstand jeder in dieser Instanz gespeicherten Koordinate von einer beliebigen Koordinate
     *
     * @param target Koordinaten des Referenzpunkts, an dem Sie den Abstand von jeder Koordinate berechnen möchten
     * @Eine Liste der euklidischen Entfernungen vom Rückkehrziel
     * @throws DimensionNotUnifiedException :Ziel- und Instanzdimensionen sind unterschiedlich
     * @throws NullCoordinateException      :Ziel enthält null
     */
    public List<Double> distanceFromTarget(List<Double> target) {
        if (target.size() != dimension) {
            throw new DimensionNotUnifiedException();
        }

        if (target.stream().anyMatch(Objects::isNull)) {
            throw new NullCoordinateException();
        }

        return points.stream().map(point -> {
            double squareOfDistance = 0.0;
            for (int i = 0; i < target.size(); i++) {
                squareOfDistance += Math.pow(point.get(i) - target.get(i), 2);
            }

            return Math.sqrt(squareOfDistance);
        }).collect(Collectors.toList());
    }

Plötzlich erscheint Math :: pow oder Math :: sqrt, aber pow ist eine Potenz und sqrt ist eine Methode, die eine Quadratwurzel hat. Mathematik ist eine Klasse, mit der Sie in Webdiensten und Geschäftsanwendungen nicht vertraut sind. Beachten Sie jedoch, dass sie häufig in arithmetischen Berechnungen verwendet wird.

Ich möchte so etwas tun, wenn es illustriert ist.

image.png

Und testen

package net.tan3sugarless.clusteringsample.lib.data;

import net.tan3sugarless.clusteringsample.exception.DimensionNotUnifiedException;
import net.tan3sugarless.clusteringsample.exception.NullCoordinateException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;

class EuclideanSpaceTest {

    //Ganz null,Himmel,1 Element,Mehrere Elemente
    //Jedes Element enthält null,Einschließlich Himmel,Alles leer(0 Dimension),1 Dimension,n Abmessungen
    //Enthält Nullkoordinaten in jedem Element,Einschließlich 0,Enthält keine Null
    //Dimensionsprüfung Alle gleichen Dimensionen,Unterschiedliche Abmessungen
    static Stream<Arguments> testConstructorProvider() {
        //@formatter:off
        return Stream.of(
                Arguments.of(null, new NullPointerException(), 0),
                Arguments.of(Collections.emptyList(), null, 0),
                Arguments.of(Arrays.asList(Arrays.asList(1.5, -2.1)), null, 2),
                Arguments.of(Arrays.asList(Arrays.asList(1.2, 0.1), Arrays.asList(0.0, 1.5)), null, 2),
                Arguments.of(Arrays.asList(null, Arrays.asList(0, 1.5), Arrays.asList(-0.9, 0.1)), new NullPointerException(), 0),
                Arguments.of(Arrays.asList(Arrays.asList(-0.9, 0.1), Arrays.asList(0.0, 1.5), Collections.emptyList()), new DimensionNotUnifiedException(), 0),
                Arguments.of(Arrays.asList(Collections.emptyList(), Collections.emptyList(), Collections.emptyList()), null, 0),
                Arguments.of(Arrays.asList(Arrays.asList(1.5), Arrays.asList(0.0), Arrays.asList(-2.2)), null, 1),
                Arguments.of(Arrays.asList(Arrays.asList(1.5, 2.2, -1.9), Arrays.asList(0.0, 0.0, 0.0), Arrays.asList(0.9, 5.0, 2.2)), null, 3),
                Arguments.of(Arrays.asList(Arrays.asList(1.5, null, -1.9), Arrays.asList(0.0, 0.0, 0.0), Arrays.asList(0.9, 5.0, 2.2)), new NullCoordinateException(), 0),
                Arguments.of(Arrays.asList(Arrays.asList(1.5, 2.1, -1.9), Arrays.asList(0.0, 0.0), Arrays.asList(0.9, 5.0, 2.2)), new DimensionNotUnifiedException(), 0),
                Arguments.of(Arrays.asList(Arrays.asList(2.1, -1.9), Arrays.asList(0, 0, 0), Arrays.asList(0.9, 5.0, 2.2)), new DimensionNotUnifiedException(), 0)
        );
        //@formatter:on
    }

    @ParameterizedTest
    @MethodSource("testConstructorProvider")
    @DisplayName("Testen des Konstruktors")
    void testConstructor(List<List<Double>> points, RuntimeException e, int dimension) {
        if (e == null) {
            Assertions.assertDoesNotThrow(() -> new EuclideanSpace(points));

            EuclideanSpace actual = new EuclideanSpace(points);
            Assertions.assertEquals(dimension, actual.getDimension());
        } else {
            Assertions.assertThrows(e.getClass(), () -> new EuclideanSpace(points));
        }
    }

    // points :0 Fälle/1/2 Fälle,0 Dimension/1 Dimension/2D, 0/Positiv/Negativ
    // target : null/Himmel/1 Dimension/2D,Einschließlich null/Nicht enthalten, 0/Positiv/Negativ/Gleiche Koordinaten
    static Stream<Arguments> testDistanceFromTargetProvider() {
        return Stream.of(
                //@formatter:off
                Arguments.of(Collections.emptyList(), Collections.emptyList(), null, Collections.emptyList()),
                Arguments.of(Collections.emptyList(), Arrays.asList(0.1), new DimensionNotUnifiedException(), Collections.emptyList()),
                Arguments.of(Arrays.asList(Collections.emptyList()), Collections.emptyList(), null, Arrays.asList(0.0)),
                Arguments.of(Arrays.asList(Collections.emptyList()), Arrays.asList(0.1), new DimensionNotUnifiedException(), Collections.emptyList()),
                Arguments.of(Arrays.asList(Arrays.asList(3.0)), Arrays.asList(1.0), null, Arrays.asList(2.0)),
                Arguments.of(Arrays.asList(Arrays.asList(3.0)), Arrays.asList(1.0, 2.0), new DimensionNotUnifiedException(), Collections.emptyList()),
                Arguments.of(Arrays.asList(Arrays.asList(-1.0, 0.0)), Arrays.asList(2.0, -4.0), null, Arrays.asList(5.0)),
                Arguments.of(Arrays.asList(Arrays.asList(-1.0, 0.0)), Arrays.asList(null, -4.0), new NullCoordinateException(), Collections.emptyList()),
                Arguments.of(Arrays.asList(Arrays.asList(-3.0, 0.0), Arrays.asList(0.0, -4.0)), Arrays.asList(0.0, -4.0), null, Arrays.asList(5.0, 0.0))
                //@formatter:on
        );
    }

    @ParameterizedTest
    @MethodSource("testDistanceFromTargetProvider")
    @DisplayName("Entfernungsberechnungstest")
    void testDistanceFromTarget(List<List<Double>> points, List<Double> target, RuntimeException e, List<Double> distances) {
        EuclideanSpace space = new EuclideanSpace(points);

        if (e == null) {
            Assertions.assertEquals(distances, space.distanceFromTarget(target));
        } else {
            Assertions.assertThrows(e.getClass(), () -> space.distanceFromTarget(target));
        }
    }
}

Die diesmal implementierte Version ist in dieser Version von GitHub veröffentlicht. https://github.com/tan3nonsugar/clusteringsample/releases/tag/v0.0.2

Vielen Dank, dass Sie so weit gelesen haben. Das nächste Mal werde ich über die Idee des "Schwerpunkts der Daten" sprechen. Dann ~ Noshi

[^ 1]: Genau genommen sollte ich zuerst die Unähnlichkeit / Ähnlichkeit erklären oder über die Unzufriedenheit sprechen, die der mathematischen Definition von Distanz entspricht, aber vorrangig einen Sinn bekommen. Ich werde es hier weglassen.

Recommended Posts

[Einführung in die Informatik Teil 2: Versuchen Sie maschinelles Lernen] Lassen Sie uns die k-Mittelungsmethode in Java-Abstand zwischen Daten implementieren.
[Einführung in die Informatik Teil 3: Versuchen wir es mit maschinellem Lernen] Implementieren wir die k-Mittelungsmethode im Java-Center of data set-
[Einführung in die Informatik Nr. 0: Versuchen Sie maschinelles Lernen] Lassen Sie uns die k-Mittelungsmethode in Java implementieren
[Einführung in die Informatik Teil 1: Versuchen wir es mit maschinellem Lernen] Implementieren wir die k-Mittelungsmethode in Java - Über das Konzept der Koordinaten -
Versuchen Sie, Yuma in Ruby zu implementieren
Versuchen Sie, Yuma in Java zu implementieren
Versuchen Sie, n-ary Addition in Java zu implementieren