MATH-1270

SOFM visualization: Unified distance matrix.


Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/5e28d11b
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/5e28d11b
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/5e28d11b

Branch: refs/heads/MATH_3_X
Commit: 5e28d11b17c3e1aae2d344cef70aee18ef05a43b
Parents: 4ac5a9d
Author: Gilles <er...@apache.org>
Authored: Fri Sep 11 00:49:55 2015 +0200
Committer: Gilles <er...@apache.org>
Committed: Fri Sep 11 00:49:55 2015 +0200

----------------------------------------------------------------------
 .../twod/util/UnifiedDistanceMatrix.java        | 202 +++++++++++++++++++
 1 file changed, 202 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-math/blob/5e28d11b/src/main/java/org/apache/commons/math3/ml/neuralnet/twod/util/UnifiedDistanceMatrix.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/math3/ml/neuralnet/twod/util/UnifiedDistanceMatrix.java
 
b/src/main/java/org/apache/commons/math3/ml/neuralnet/twod/util/UnifiedDistanceMatrix.java
new file mode 100644
index 0000000..3f56260
--- /dev/null
+++ 
b/src/main/java/org/apache/commons/math3/ml/neuralnet/twod/util/UnifiedDistanceMatrix.java
@@ -0,0 +1,202 @@
+/*
+ * 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.math3.ml.neuralnet.twod.util;
+
+import java.util.Collection;
+import org.apache.commons.math3.ml.neuralnet.Neuron;
+import org.apache.commons.math3.ml.neuralnet.Network;
+import org.apache.commons.math3.ml.neuralnet.twod.NeuronSquareMesh2D;
+import org.apache.commons.math3.ml.distance.DistanceMeasure;
+
+/**
+ * <a href="http://en.wikipedia.org/wiki/U-Matrix";>U-Matrix</a>
+ * visualization of high-dimensional data projection.
+ */
+public class UnifiedDistanceMatrix implements MapVisualization {
+    /** Whether to show distance between each pair of neighbouring units. */
+    private final boolean individualDistances;
+    /** Distance. */
+    private final DistanceMeasure distance;
+
+    /**
+     * @param boolean 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 value zero will be stored in the
+     * pixel corresponding to the location of a unit of the 2D-map.
+     * 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.math3.ml.neuralnet.SquareNeighbourhood
+     * neighbourhood type}.
+     * @param distance Distance.
+     */
+    public UnifiedDistanceMatrix(boolean individualDistances,
+                                 DistanceMeasure distance) {
+        this.individualDistances = individualDistances;
+        this.distance = distance;
+    }
+
+    /** {@inheritDoc} */
+    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.
+     * The image will contain more pixels than the number of neurons
+     * in the given {@code map} because each neuron has 8 neighbours.
+     * The value zero will be stored in the pixels corresponding to
+     * the location of a map unit.
+     *
+     * @param map Map.
+     * @return an image representing the individual distances.
+     */
+    private double[][] individualDistances(NeuronSquareMesh2D map) {
+        final int numRows = map.getNumberOfRows();
+        final int numCols = map.getNumberOfColumns();
+
+        final double[][] uMatrix = new double[numRows * 2 + 1][numCols * 2 + 
1];
+
+        for (int i = 0; i < numRows; i++) {
+            // Current unit's row index in result image.
+            final int iR = 2 * i + 1;
+
+            for (int j = 0; j < numCols; j++) {
+                // Current unit's column index in result image.
+                final int jR = 2 * j + 1;
+
+                final double[] current = map.getNeuron(i, j).getFeatures();
+                Neuron neighbour;
+
+                // Top-left neighbour.
+                neighbour = map.getNeuron(i, j,
+                                          
NeuronSquareMesh2D.HorizontalDirection.LEFT,
+                                          
NeuronSquareMesh2D.VerticalDirection.UP);
+                if (neighbour != null) {
+                    uMatrix[iR - 1][jR - 1] = distance.compute(current,
+                                                               
neighbour.getFeatures());
+                }
+
+                // Top-center neighbour.
+                neighbour = map.getNeuron(i, j,
+                                          
NeuronSquareMesh2D.HorizontalDirection.CENTER,
+                                          
NeuronSquareMesh2D.VerticalDirection.UP);
+                if (neighbour != null) {
+                    uMatrix[iR - 1][jR] = distance.compute(current,
+                                                           
neighbour.getFeatures());
+                }
+
+                // Top-right neighbour.
+                neighbour = map.getNeuron(i, j,
+                                          
NeuronSquareMesh2D.HorizontalDirection.RIGHT,
+                                          
NeuronSquareMesh2D.VerticalDirection.UP);
+                if (neighbour != null) {
+                    uMatrix[iR - 1][jR + 1] = distance.compute(current,
+                                                               
neighbour.getFeatures());
+                }
+
+                // Left neighbour.
+                neighbour = map.getNeuron(i, j,
+                                          
NeuronSquareMesh2D.HorizontalDirection.LEFT,
+                                          
NeuronSquareMesh2D.VerticalDirection.CENTER);
+                if (neighbour != null) {
+                    uMatrix[iR][jR - 1] = distance.compute(current,
+                                                           
neighbour.getFeatures());
+                }
+
+                // Right neighbour.
+                neighbour = map.getNeuron(i, j,
+                                          
NeuronSquareMesh2D.HorizontalDirection.RIGHT,
+                                          
NeuronSquareMesh2D.VerticalDirection.CENTER);
+                if (neighbour != null) {
+                    uMatrix[iR][jR + 1] = distance.compute(current,
+                                                           
neighbour.getFeatures());
+                }
+
+                // Bottom-left neighbour.
+                neighbour = map.getNeuron(i, j,
+                                          
NeuronSquareMesh2D.HorizontalDirection.LEFT,
+                                          
NeuronSquareMesh2D.VerticalDirection.DOWN);
+                if (neighbour != null) {
+                    uMatrix[iR + 1][jR - 1] = distance.compute(current,
+                                                               
neighbour.getFeatures());
+                }
+
+                // Bottom-center neighbour.
+                neighbour = map.getNeuron(i, j,
+                                          
NeuronSquareMesh2D.HorizontalDirection.CENTER,
+                                          
NeuronSquareMesh2D.VerticalDirection.DOWN);
+                if (neighbour != null) {
+                    uMatrix[iR + 1][jR] = distance.compute(current,
+                                                           
neighbour.getFeatures());
+                }
+
+                // Bottom-right neighbour.
+                neighbour = map.getNeuron(i, j,
+                                          
NeuronSquareMesh2D.HorizontalDirection.RIGHT,
+                                          
NeuronSquareMesh2D.VerticalDirection.DOWN);
+                if (neighbour != null) {
+                    uMatrix[iR + 1][jR + 1] = distance.compute(current,
+                                                               
neighbour.getFeatures());
+                }
+            }
+        }
+
+        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;
+    }
+}

Reply via email to