001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.math3.ml.neuralnet.twod.util; 019 020import org.apache.commons.math3.ml.neuralnet.MapUtils; 021import org.apache.commons.math3.ml.neuralnet.Neuron; 022import org.apache.commons.math3.ml.neuralnet.twod.NeuronSquareMesh2D; 023import org.apache.commons.math3.ml.distance.DistanceMeasure; 024import org.apache.commons.math3.exception.NumberIsTooSmallException; 025 026/** 027 * Visualization of high-dimensional data projection on a 2D-map. 028 * The method is described in 029 * <quote> 030 * <em>Using Smoothed Data Histograms for Cluster Visualization in Self-Organizing Maps</em> 031 * <br> 032 * by Elias Pampalk, Andreas Rauber and Dieter Merkl. 033 * </quote> 034 * @since 3.6 035 */ 036public class SmoothedDataHistogram implements MapDataVisualization { 037 /** Smoothing parameter. */ 038 private final int smoothingBins; 039 /** Distance. */ 040 private final DistanceMeasure distance; 041 /** Normalization factor. */ 042 private final double membershipNormalization; 043 044 /** 045 * @param smoothingBins Number of bins. 046 * @param distance Distance. 047 */ 048 public SmoothedDataHistogram(int smoothingBins, 049 DistanceMeasure distance) { 050 this.smoothingBins = smoothingBins; 051 this.distance = distance; 052 053 double sum = 0; 054 for (int i = 0; i < smoothingBins; i++) { 055 sum += smoothingBins - i; 056 } 057 058 this.membershipNormalization = 1d / sum; 059 } 060 061 /** 062 * {@inheritDoc} 063 * 064 * @throws NumberIsTooSmallException if the size of the {@code map} 065 * is smaller than the number of {@link #SmoothedDataHistogram(int,DistanceMeasure) 066 * smoothing bins}. 067 */ 068 public double[][] computeImage(NeuronSquareMesh2D map, 069 Iterable<double[]> data) { 070 final int nR = map.getNumberOfRows(); 071 final int nC = map.getNumberOfColumns(); 072 073 final int mapSize = nR * nC; 074 if (mapSize < smoothingBins) { 075 throw new NumberIsTooSmallException(mapSize, smoothingBins, true); 076 } 077 078 final LocationFinder finder = new LocationFinder(map); 079 080 // Histogram bins. 081 final double[][] histo = new double[nR][nC]; 082 083 for (double[] sample : data) { 084 final Neuron[] sorted = MapUtils.sort(sample, 085 map.getNetwork(), 086 distance); 087 for (int i = 0; i < smoothingBins; i++) { 088 final LocationFinder.Location loc = finder.getLocation(sorted[i]); 089 final int row = loc.getRow(); 090 final int col = loc.getColumn(); 091 histo[row][col] += (smoothingBins - i) * membershipNormalization; 092 } 093 } 094 095 return histo; 096 } 097}