You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2020/06/28 22:57:46 UTC
[commons-math] 05/08: MATH-1548: Move standard quality measures of
a SOM into class "NeuronSquareMesh2D".
This is an automated email from the ASF dual-hosted git repository.
erans pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-math.git
commit 28e5b802fe0b406cfba5605d1537acb0e327d177
Author: Gilles Sadowski <gi...@gmail.com>
AuthorDate: Fri Jun 26 18:05:12 2020 +0200
MATH-1548: Move standard quality measures of a SOM into class "NeuronSquareMesh2D".
All these indicators are usually computed in order to evaluate the quality of a SOM:
Computing them separately is inefficient when the number of samples becomes large.
---
.../ml/neuralnet/twod/NeuronSquareMesh2D.java | 239 +++++++++++++++++++++
.../math4/ml/neuralnet/twod/util/HitHistogram.java | 85 --------
.../ml/neuralnet/twod/util/QuantizationError.java | 78 -------
.../twod/util/TopographicErrorHistogram.java | 93 --------
.../neuralnet/twod/util/UnifiedDistanceMatrix.java | 81 ++-----
.../ml/neuralnet/twod/NeuronSquareMesh2DTest.java | 40 ++++
6 files changed, 292 insertions(+), 324 deletions(-)
diff --git a/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/NeuronSquareMesh2D.java b/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/NeuronSquareMesh2D.java
index 3a5a126..17055da 100644
--- a/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/NeuronSquareMesh2D.java
+++ b/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/NeuronSquareMesh2D.java
@@ -20,6 +20,7 @@ package org.apache.commons.math4.ml.neuralnet.twod;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
+import java.util.Collection;
import java.io.Serializable;
import java.io.ObjectInputStream;
@@ -30,6 +31,10 @@ import org.apache.commons.math4.ml.neuralnet.FeatureInitializer;
import org.apache.commons.math4.ml.neuralnet.Network;
import org.apache.commons.math4.ml.neuralnet.Neuron;
import org.apache.commons.math4.ml.neuralnet.SquareNeighbourhood;
+import org.apache.commons.math4.ml.neuralnet.MapRanking;
+import org.apache.commons.math4.ml.neuralnet.twod.util.LocationFinder;
+import org.apache.commons.math4.ml.distance.DistanceMeasure;
+import org.apache.commons.math4.ml.distance.EuclideanDistance;
/**
* Neural network with the topology of a two-dimensional surface.
@@ -340,6 +345,17 @@ public class NeuronSquareMesh2D
}
/**
+ * Computes various {@link DataVisualization indicators} of the quality
+ * of the representation of the given {@code data} by this map.
+ *
+ * @param data Features.
+ * @return a new instance holding quality indicators.
+ */
+ public DataVisualization computeQualityIndicators(Iterable<double[]> data) {
+ return DataVisualization.from(copy(), data);
+ }
+
+ /**
* Computes the location of a neighbouring neuron.
* Returns {@code null} if the resulting location is not part
* of the map.
@@ -625,4 +641,227 @@ public class NeuronSquareMesh2D
featuresList);
}
}
+
+ /**
+ * Miscellaneous indicators of the map quality:
+ * <ul>
+ * <li>Hit histogram</li>
+ * <li>Quantization error</li>
+ * <li>Topographic error</li>
+ * <li>Unified distance matrix</li>
+ * </ul>
+ */
+ public static class DataVisualization {
+ /** Distance function. */
+ private static final DistanceMeasure DISTANCE = new EuclideanDistance();
+ /** Total number of samples. */
+ private final int numberOfSamples;
+ /** Hit histogram. */
+ private final double[][] hitHistogram;
+ /** Quantization error. */
+ private final double[][] quantizationError;
+ /** Mean quantization error. */
+ private final double meanQuantizationError;
+ /** Topographic error. */
+ private final double[][] topographicError;
+ /** Mean topographic error. */
+ private final double meanTopographicError;
+ /** U-matrix. */
+ private final double[][] uMatrix;
+
+ /**
+ * @param numberOfSamples Number of samples.
+ * @param hitHistogram Hit histogram.
+ * @param quantizationError Quantization error.
+ * @param topographicError Topographic error.
+ * @param uMatrix U-matrix.
+ */
+ private DataVisualization(int numberOfSamples,
+ double[][] hitHistogram,
+ double[][] quantizationError,
+ double[][] topographicError,
+ double[][] uMatrix) {
+ this.numberOfSamples = numberOfSamples;
+ this.hitHistogram = hitHistogram;
+ this.quantizationError = quantizationError;
+ meanQuantizationError = hitWeightedMean(quantizationError, hitHistogram);
+ this.topographicError = topographicError;
+ meanTopographicError = hitWeightedMean(topographicError, hitHistogram);
+ this.uMatrix = uMatrix;
+ }
+
+ /**
+ * @param map Map
+ * @param data Data.
+ * @return the metrics.
+ */
+ static DataVisualization from(NeuronSquareMesh2D map,
+ Iterable<double[]> data) {
+ final LocationFinder finder = new LocationFinder(map);
+ final MapRanking rank = new MapRanking(map, DISTANCE);
+ final Network net = map.getNetwork();
+ final int nR = map.getNumberOfRows();
+ final int nC = map.getNumberOfColumns();
+
+ // Hit bins.
+ final int[][] hitCounter = new int[nR][nC];
+ // Hit bins.
+ final double[][] hitHistogram = new double[nR][nC];
+ // Quantization error bins.
+ final double[][] quantizationError = new double[nR][nC];
+ // Topographic error bins.
+ final double[][] topographicError = new double[nR][nC];
+ // U-matrix.
+ final double[][] uMatrix = new double[nR][nC];
+
+ int numSamples = 0;
+ for (double[] sample : data) {
+ ++numSamples;
+
+ final List<Neuron> winners = rank.rank(sample, 2);
+ final Neuron best = winners.get(0);
+ final Neuron secondBest = winners.get(1);
+
+ final LocationFinder.Location locBest = finder.getLocation(best);
+ final int rowBest = locBest.getRow();
+ final int colBest = locBest.getColumn();
+ // Increment hit counter.
+ hitCounter[rowBest][colBest] += 1;
+
+ // Aggregate quantization error.
+ quantizationError[rowBest][colBest] += DISTANCE.compute(sample, best.getFeatures());
+
+ // Aggregate topographic error.
+ if (!net.getNeighbours(best).contains(secondBest)) {
+ // Increment count if first and second best matching units
+ // are not neighbours.
+ topographicError[rowBest][colBest] += 1;
+ }
+ }
+
+ for (int r = 0; r < nR; r++) {
+ for (int c = 0; c < nC; c++) {
+ final Neuron neuron = map.getNeuron(r, c);
+ final Collection<Neuron> neighbours = net.getNeighbours(neuron);
+ final double[] features = neuron.getFeatures();
+ double uDistance = 0;
+ int neighbourCount = 0;
+ for (Neuron n : neighbours) {
+ ++neighbourCount;
+ uDistance += DISTANCE.compute(features, n.getFeatures());
+ }
+
+ final int hitCount = hitCounter[r][c];
+ if (hitCount != 0) {
+ hitHistogram[r][c] = hitCount / (double) numSamples;
+ quantizationError[r][c] /= hitCount;
+ topographicError[r][c] /= hitCount;
+ uMatrix[r][c] = uDistance / neighbourCount;
+ }
+ }
+ }
+
+ return new DataVisualization(numSamples,
+ hitHistogram,
+ quantizationError,
+ topographicError,
+ uMatrix);
+ }
+
+ /**
+ * @return the total number of samples.
+ */
+ public final int getNumberOfSamples() {
+ return numberOfSamples;
+ }
+
+ /**
+ * @return the quantization error.
+ * Each bin will contain the average of the distances between samples
+ * mapped to the corresponding unit and the weight vector of that unit.
+ * @see #getMeanQuantizationError()
+ */
+ public double[][] getQuantizationError() {
+ return copy(quantizationError);
+ }
+
+ /**
+ * @return the topographic error.
+ * Each bin will contain the number of data for which the first and
+ * second best matching units are not adjacent in the map.
+ * @see #getMeanTopographicError()
+ */
+ public double[][] getTopographicError() {
+ return copy(topographicError);
+ }
+
+ /**
+ * @return the hits histogram (normalized).
+ * Each bin will contain the number of data for which the corresponding
+ * neuron is the best matching unit.
+ */
+ public double[][] getNormalizedHits() {
+ return copy(hitHistogram);
+ }
+
+ /**
+ * @return the U-matrix.
+ * Each bin will contain the average distance between a unit and all its
+ * neighbours will be computed (and stored in the pixel corresponding to
+ * that unit of the 2D-map). The number of neighbours taken into account
+ * depends on the network {@link org.apache.commons.math4.ml.neuralnet.SquareNeighbourhood
+ * neighbourhood type}.
+ */
+ public double[][] getUMatrix() {
+ return copy(uMatrix);
+ }
+
+ /**
+ * @return the mean (hit-weighted) quantization error.
+ * @see #getQuantizationError()
+ */
+ public double getMeanQuantizationError() {
+ return meanQuantizationError;
+ }
+
+ /**
+ * @return the mean (hit-weighted) topographic error.
+ * @see #getTopographicError()
+ */
+ public double getMeanTopographicError() {
+ return meanTopographicError;
+ }
+
+ /**
+ * @param orig Source.
+ * @return a deep copy of the original array.
+ */
+ private static double[][] copy(double[][] orig) {
+ final double[][] copy = new double[orig.length][];
+ for (int i = 0; i < orig.length; i++) {
+ copy[i] = orig[i].clone();
+ }
+
+ return copy;
+ }
+
+ /**
+ * @param metrics Metrics.
+ * @param normalizedHits Hits histogram (normalized).
+ * @return the hit-weighted mean of the given {@code metrics}.
+ */
+ private double hitWeightedMean(double[][] metrics,
+ double[][] normalizedHits) {
+ double mean = 0;
+ final int rows = metrics.length;
+ final int cols = metrics[0].length;
+ for (int i = 0; i < rows; i++) {
+ for (int j = 0; j < cols; j++) {
+ mean += normalizedHits[i][j] * metrics[i][j];
+ }
+ }
+
+ return mean;
+ }
+ }
}
diff --git a/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/HitHistogram.java b/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/HitHistogram.java
deleted file mode 100644
index a88fa1d..0000000
--- a/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/HitHistogram.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.math4.ml.neuralnet.twod.util;
-
-import org.apache.commons.math4.ml.neuralnet.MapRanking;
-import org.apache.commons.math4.ml.neuralnet.Neuron;
-import org.apache.commons.math4.ml.neuralnet.twod.NeuronSquareMesh2D;
-import org.apache.commons.math4.ml.distance.DistanceMeasure;
-
-/**
- * Computes the hit histogram.
- * Each bin will contain the number of data for which the corresponding
- * neuron is the best matching unit.
- * @since 3.6
- */
-public class HitHistogram implements MapDataVisualization {
- /** Distance. */
- private final DistanceMeasure distance;
- /** Whether to compute relative bin counts. */
- private final boolean normalizeCount;
-
- /**
- * @param normalizeCount Whether to compute relative bin counts.
- * If {@code true}, the data count in each bin will be divided by the total
- * number of samples.
- * @param distance Distance.
- */
- public HitHistogram(boolean normalizeCount,
- DistanceMeasure distance) {
- this.normalizeCount = normalizeCount;
- this.distance = distance;
- }
-
- /** {@inheritDoc} */
- @Override
- public double[][] computeImage(NeuronSquareMesh2D map,
- Iterable<double[]> data) {
- final int nR = map.getNumberOfRows();
- final int nC = map.getNumberOfColumns();
-
- final LocationFinder finder = new LocationFinder(map);
- final MapRanking rank = new MapRanking(map.getNetwork(), distance);
-
- // Totla number of samples.
- int numSamples = 0;
- // Hit bins.
- final double[][] hit = new double[nR][nC];
-
- for (double[] sample : data) {
- final Neuron best = rank.rank(sample, 1).get(0);
-
- final LocationFinder.Location loc = finder.getLocation(best);
- final int row = loc.getRow();
- final int col = loc.getColumn();
- hit[row][col] += 1;
-
- ++numSamples;
- }
-
- if (normalizeCount) {
- for (int r = 0; r < nR; r++) {
- for (int c = 0; c < nC; c++) {
- hit[r][c] /= numSamples;
- }
- }
- }
-
- return hit;
- }
-}
diff --git a/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/QuantizationError.java b/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/QuantizationError.java
deleted file mode 100644
index f2bc9de..0000000
--- a/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/QuantizationError.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.math4.ml.neuralnet.twod.util;
-
-import org.apache.commons.math4.ml.neuralnet.MapRanking;
-import org.apache.commons.math4.ml.neuralnet.Neuron;
-import org.apache.commons.math4.ml.neuralnet.twod.NeuronSquareMesh2D;
-import org.apache.commons.math4.ml.distance.DistanceMeasure;
-
-/**
- * Computes the quantization error histogram.
- * Each bin will contain the average of the distances between samples
- * mapped to the corresponding unit and the weight vector of that unit.
- * @since 3.6
- */
-public class QuantizationError implements MapDataVisualization {
- /** Distance. */
- private final DistanceMeasure distance;
-
- /**
- * @param distance Distance.
- */
- public QuantizationError(DistanceMeasure distance) {
- this.distance = distance;
- }
-
- /** {@inheritDoc} */
- @Override
- public double[][] computeImage(NeuronSquareMesh2D map,
- Iterable<double[]> data) {
- final int nR = map.getNumberOfRows();
- final int nC = map.getNumberOfColumns();
-
- final LocationFinder finder = new LocationFinder(map);
- final MapRanking rank = new MapRanking(map.getNetwork(), distance);
-
- // Hit bins.
- final int[][] hit = new int[nR][nC];
- // Error bins.
- final double[][] error = new double[nR][nC];
-
- for (double[] sample : data) {
- final Neuron best = rank.rank(sample, 1).get(0);
-
- final LocationFinder.Location loc = finder.getLocation(best);
- final int row = loc.getRow();
- final int col = loc.getColumn();
- hit[row][col] += 1;
- error[row][col] += distance.compute(sample, best.getFeatures());
- }
-
- for (int r = 0; r < nR; r++) {
- for (int c = 0; c < nC; c++) {
- final int count = hit[r][c];
- if (count != 0) {
- error[r][c] /= count;
- }
- }
- }
-
- return error;
- }
-}
diff --git a/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/TopographicErrorHistogram.java b/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/TopographicErrorHistogram.java
deleted file mode 100644
index 758e672..0000000
--- a/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/TopographicErrorHistogram.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.commons.math4.ml.neuralnet.twod.util;
-
-import java.util.List;
-import org.apache.commons.math4.ml.neuralnet.MapRanking;
-import org.apache.commons.math4.ml.neuralnet.Neuron;
-import org.apache.commons.math4.ml.neuralnet.Network;
-import org.apache.commons.math4.ml.neuralnet.twod.NeuronSquareMesh2D;
-import org.apache.commons.math4.ml.distance.DistanceMeasure;
-
-/**
- * Computes the topographic error histogram.
- * Each bin will contain the number of data for which the first and
- * second best matching units are not adjacent in the map.
- * @since 3.6
- */
-public class TopographicErrorHistogram implements MapDataVisualization {
- /** Distance. */
- private final DistanceMeasure distance;
- /** Whether to compute relative bin counts. */
- private final boolean relativeCount;
-
- /**
- * @param relativeCount Whether to compute relative bin counts.
- * If {@code true}, the data count in each bin will be divided by the total
- * number of samples mapped to the neuron represented by that bin.
- * @param distance Distance.
- */
- public TopographicErrorHistogram(boolean relativeCount,
- DistanceMeasure distance) {
- this.relativeCount = relativeCount;
- this.distance = distance;
- }
-
- /** {@inheritDoc} */
- @Override
- public double[][] computeImage(NeuronSquareMesh2D map,
- Iterable<double[]> data) {
- final int nR = map.getNumberOfRows();
- final int nC = map.getNumberOfColumns();
-
- final LocationFinder finder = new LocationFinder(map);
- final Network net = map.getNetwork();
- final MapRanking rank = new MapRanking(net, distance);
-
- // Hit bins.
- final int[][] hit = new int[nR][nC];
- // Error bins.
- final double[][] error = new double[nR][nC];
-
- for (double[] sample : data) {
- final List<Neuron> p = rank.rank(sample, 2);
- final Neuron best = p.get(0);
-
- final LocationFinder.Location loc = finder.getLocation(best);
- final int row = loc.getRow();
- final int col = loc.getColumn();
- hit[row][col] += 1;
-
- if (!net.getNeighbours(best).contains(p.get(1))) {
- // Increment count if first and second best matching units
- // are not neighbours.
- error[row][col] += 1;
- }
- }
-
- if (relativeCount) {
- for (int r = 0; r < nR; r++) {
- for (int c = 0; c < nC; c++) {
- error[r][c] /= hit[r][c];
- }
- }
- }
-
- return error;
- }
-}
diff --git a/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/UnifiedDistanceMatrix.java b/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/UnifiedDistanceMatrix.java
index 0fa2002..9fa9318 100644
--- a/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/UnifiedDistanceMatrix.java
+++ b/src/main/java/org/apache/commons/math4/ml/neuralnet/twod/util/UnifiedDistanceMatrix.java
@@ -17,59 +17,36 @@
package org.apache.commons.math4.ml.neuralnet.twod.util;
-import java.util.Collection;
import org.apache.commons.math4.ml.neuralnet.Neuron;
-import org.apache.commons.math4.ml.neuralnet.Network;
import org.apache.commons.math4.ml.neuralnet.twod.NeuronSquareMesh2D;
import org.apache.commons.math4.ml.distance.DistanceMeasure;
/**
* <a href="http://en.wikipedia.org/wiki/U-Matrix">U-Matrix</a>
* visualization of high-dimensional data projection.
+ * The 8 individual inter-units distances will be
+ * {@link #computeImage(NeuronSquareMesh2D) computed}. They will be
+ * stored in additional pixels around each of the original units of the
+ * 2D-map. The additional pixels that lie along a "diagonal" are shared
+ * by <em>two</em> pairs of units: their value will be set to the average
+ * distance between the units belonging to each of the pairs. The value
+ * zero will be stored in the pixel corresponding to the location of a
+ * unit of the 2D-map.
+ *
* @since 3.6
+ * @see NeuronSquareMesh2D.DataVisualization#getUMatrix()
*/
public class UnifiedDistanceMatrix implements MapVisualization {
- /** Whether to show distance between each pair of neighbouring units. */
- private final boolean individualDistances;
/** Distance. */
private final DistanceMeasure distance;
/**
- * Simple constructor.
- *
- * @param individualDistances If {@code true}, the 8 individual
- * inter-units distances will be {@link #computeImage(NeuronSquareMesh2D)
- * computed}. They will be stored in additional pixels around each of
- * the original units of the 2D-map. The additional pixels that lie
- * along a "diagonal" are shared by <em>two</em> pairs of units: their
- * value will be set to the average distance between the units belonging
- * to each of the pairs. The value zero will be stored in the pixel
- * corresponding to the location of a unit of the 2D-map.
- * <br>
- * If {@code false}, only the average distance between a unit and all its
- * neighbours will be computed (and stored in the pixel corresponding to
- * that unit of the 2D-map). In that case, the number of neighbours taken
- * into account depends on the network's
- * {@link org.apache.commons.math4.ml.neuralnet.SquareNeighbourhood
- * neighbourhood type}.
* @param distance Distance.
*/
- public UnifiedDistanceMatrix(boolean individualDistances,
- DistanceMeasure distance) {
- this.individualDistances = individualDistances;
+ public UnifiedDistanceMatrix(DistanceMeasure distance) {
this.distance = distance;
}
- /** {@inheritDoc} */
- @Override
- public double[][] computeImage(NeuronSquareMesh2D map) {
- if (individualDistances) {
- return individualDistances(map);
- } else {
- return averageDistances(map);
- }
- }
-
/**
* Computes the distances between a unit of the map and its
* neighbours.
@@ -81,7 +58,8 @@ public class UnifiedDistanceMatrix implements MapVisualization {
* @param map Map.
* @return an image representing the individual distances.
*/
- private double[][] individualDistances(NeuronSquareMesh2D map) {
+ @Override
+ public double[][] computeImage(NeuronSquareMesh2D map) {
final int numRows = map.getNumberOfRows();
final int numCols = map.getNumberOfColumns();
@@ -174,37 +152,4 @@ public class UnifiedDistanceMatrix implements MapVisualization {
return uMatrix;
}
-
- /**
- * Computes the distances between a unit of the map and its neighbours.
- *
- * @param map Map.
- * @return an image representing the average distances.
- */
- private double[][] averageDistances(NeuronSquareMesh2D map) {
- final int numRows = map.getNumberOfRows();
- final int numCols = map.getNumberOfColumns();
- final double[][] uMatrix = new double[numRows][numCols];
-
- final Network net = map.getNetwork();
-
- for (int i = 0; i < numRows; i++) {
- for (int j = 0; j < numCols; j++) {
- final Neuron neuron = map.getNeuron(i, j);
- final Collection<Neuron> neighbours = net.getNeighbours(neuron);
- final double[] features = neuron.getFeatures();
-
- double d = 0;
- int count = 0;
- for (Neuron n : neighbours) {
- ++count;
- d += distance.compute(features, n.getFeatures());
- }
-
- uMatrix[i][j] = d / count;
- }
- }
-
- return uMatrix;
- }
}
diff --git a/src/test/java/org/apache/commons/math4/ml/neuralnet/twod/NeuronSquareMesh2DTest.java b/src/test/java/org/apache/commons/math4/ml/neuralnet/twod/NeuronSquareMesh2DTest.java
index 693f59b..55732a7 100644
--- a/src/test/java/org/apache/commons/math4/ml/neuralnet/twod/NeuronSquareMesh2DTest.java
+++ b/src/test/java/org/apache/commons/math4/ml/neuralnet/twod/NeuronSquareMesh2DTest.java
@@ -25,6 +25,9 @@ import java.io.ObjectOutputStream;
import java.util.Collection;
import java.util.Set;
import java.util.HashSet;
+import java.util.List;
+import java.util.stream.StreamSupport;
+import java.util.stream.Collectors;
import org.apache.commons.math4.exception.NumberIsTooSmallException;
import org.apache.commons.math4.exception.OutOfRangeException;
@@ -872,4 +875,41 @@ public class NeuronSquareMesh2DTest {
Assert.assertTrue(fromMap.contains(n));
}
}
+
+ @Test
+ public void testDataVisualization() {
+ final FeatureInitializer[] initArray = { init };
+ final NeuronSquareMesh2D map = new NeuronSquareMesh2D(3, true,
+ 3, true,
+ SquareNeighbourhood.VON_NEUMANN,
+ initArray);
+
+ // Trivial test: Use neurons' features as data.
+
+ final List<double[]> data = StreamSupport.stream(map.spliterator(), false)
+ .map(n -> n.getFeatures())
+ .collect(Collectors.toList());
+ final NeuronSquareMesh2D.DataVisualization v = map.computeQualityIndicators(data);
+
+ final int numRows = map.getNumberOfRows();
+ final int numCols = map.getNumberOfColumns();
+
+ // Test hits.
+ final double[][] hits = v.getNormalizedHits();
+ final double expectedHits = 1d / (numRows * numCols);
+ for (int i = 0; i < numRows; i++) {
+ for (int j = 0; j < numCols; j++) {
+ Assert.assertEquals(expectedHits, hits[i][j], 0d);
+ }
+ }
+
+ // Test quantization error.
+ final double[][] qe = v.getQuantizationError();
+ final double expectedQE = 0;
+ for (int i = 0; i < numRows; i++) {
+ for (int j = 0; j < numCols; j++) {
+ Assert.assertEquals(expectedQE, qe[i][j], 0d);
+ }
+ }
+ }
}