pyclustering  0.10.1
pyclustring is a Python, C++ data mining library.
som.py
1 """!
2 
3 @brief Neural Network: Self-Organized Feature Map
4 @details Implementation based on paper @cite article::nnet::som::1, @cite article::nnet::som::2.
5 
6 @authors Andrei Novikov (pyclustering@yandex.ru)
7 @date 2014-2020
8 @copyright BSD-3-Clause
9 
10 """
11 
12 import math
13 import random
14 
15 import matplotlib.pyplot as plt
16 
17 import pyclustering.core.som_wrapper as wrapper
18 
19 from pyclustering.core.wrapper import ccore_library
20 
21 from pyclustering.utils import euclidean_distance_square
22 from pyclustering.utils.dimension import dimension_info
23 
24 from enum import IntEnum
25 
26 
27 class type_conn(IntEnum):
28  """!
29  @brief Enumeration of connection types for SOM.
30 
31  @see som
32 
33  """
34 
35 
36  grid_four = 0
37 
38 
39  grid_eight = 1
40 
41 
42  honeycomb = 2
43 
44 
45  func_neighbor = 3
46 
47 
48 class type_init(IntEnum):
49  """!
50  @brief Enumeration of initialization types for SOM.
51 
52  @see som
53 
54  """
55 
56 
57  random = 0
58 
59 
60  random_centroid = 1
61 
62 
63  random_surface = 2
64 
65 
66  uniform_grid = 3
67 
68 
70  """!
71  @brief Represents SOM parameters.
72 
73  """
74 
75  def __init__(self):
76  """!
77  @brief Creates SOM parameters.
78 
79  """
80 
81 
82  self.init_type = type_init.uniform_grid
83 
84 
85  self.init_radius = None
86 
87 
88  self.init_learn_rate = 0.1
89 
90 
91  self.adaptation_threshold = 0.001
92 
93 
94  self.random_state = None
95 
96 
97 class som:
98  """!
99  @brief Represents self-organized feature map (SOM).
100  @details The self-organizing feature map (SOM) method is a powerful tool for the visualization of
101  of high-dimensional data. It converts complex, nonlinear statistical relationships between
102  high-dimensional data into simple geometric relationships on a low-dimensional display.
103 
104  @details `ccore` option can be specified in order to control using C++ implementation of pyclustering library. By
105  default C++ implementation is on. C++ implementation improves performance of the self-organized feature
106  map.
107 
108  Example:
109  @code
110  import random
111 
112  from pyclustering.utils import read_sample
113  from pyclustering.nnet.som import som, type_conn, type_init, som_parameters
114  from pyclustering.samples.definitions import FCPS_SAMPLES
115 
116  # read sample 'Lsun' from file
117  sample = read_sample(FCPS_SAMPLES.SAMPLE_LSUN)
118 
119  # create SOM parameters
120  parameters = som_parameters()
121 
122  # create self-organized feature map with size 7x7
123  rows = 10 # five rows
124  cols = 10 # five columns
125  structure = type_conn.grid_four; # each neuron has max. four neighbors.
126  network = som(rows, cols, structure, parameters)
127 
128  # train network on 'Lsun' sample during 100 epouchs.
129  network.train(sample, 100)
130 
131  # simulate trained network using randomly modified point from input dataset.
132  index_point = random.randint(0, len(sample) - 1)
133  point = sample[index_point] # obtain randomly point from data
134  point[0] += random.random() * 0.2 # change randomly X-coordinate
135  point[1] += random.random() * 0.2 # change randomly Y-coordinate
136  index_winner = network.simulate(point)
137 
138  # check what are objects from input data are much close to randomly modified.
139  index_similar_objects = network.capture_objects[index_winner]
140 
141  # neuron contains information of encoded objects
142  print("Point '%s' is similar to objects with indexes '%s'." % (str(point), str(index_similar_objects)))
143  print("Coordinates of similar objects:")
144  for index in index_similar_objects: print("\tPoint:", sample[index])
145 
146  # result visualization:
147  # show distance matrix (U-matrix).
148  network.show_distance_matrix()
149 
150  # show density matrix (P-matrix).
151  network.show_density_matrix()
152 
153  # show winner matrix.
154  network.show_winner_matrix()
155 
156  # show self-organized map.
157  network.show_network()
158  @endcode
159 
160  There is a visualization of 'Target' sample that was done by the self-organized feature map:
161  @image html target_som_processing.png
162 
163  """
164 
165  @property
166  def size(self):
167  """!
168  @brief Return size of self-organized map that is defined by total number of neurons.
169 
170  @return (uint) Size of self-organized map (number of neurons).
171 
172  """
173 
174  if self.__ccore_som_pointer is not None:
175  self._size = wrapper.som_get_size(self.__ccore_som_pointer)
176 
177  return self._size
178 
179  @property
180  def weights(self):
181  """!
182  @brief Return weight of each neuron.
183 
184  @return (list) Weights of each neuron.
185 
186  """
187 
188  if self.__ccore_som_pointer is not None:
189  self._weights = wrapper.som_get_weights(self.__ccore_som_pointer)
190 
191  return self._weights
192 
193  @property
194  def awards(self):
195  """!
196  @brief Return amount of captured objects by each neuron after training.
197 
198  @return (list) Amount of captured objects by each neuron.
199 
200  @see train()
201 
202  """
203 
204  if self.__ccore_som_pointer is not None:
205  self._award = wrapper.som_get_awards(self.__ccore_som_pointer)
206 
207  return self._award
208 
209  @property
210  def capture_objects(self):
211  """!
212  @brief Returns indexes of captured objects by each neuron.
213  @details For example, a network with size 2x2 has been trained on a sample with five objects. Suppose neuron #1
214  won an object with index `1`, neuron #2 won objects `0`, `3`, `4`, neuron #3 did not won anything and
215  finally neuron #4 won an object with index `2`. Thus, for this example we will have the following
216  output `[[1], [0, 3, 4], [], [2]]`.
217 
218  @return (list) Indexes of captured objects by each neuron.
219 
220  """
221 
222  if self.__ccore_som_pointer is not None:
223  self._capture_objects = wrapper.som_get_capture_objects(self.__ccore_som_pointer)
224 
225  return self._capture_objects
226 
227  def __init__(self, rows, cols, conn_type=type_conn.grid_eight, parameters=None, ccore=True):
228  """!
229  @brief Constructor of self-organized map.
230 
231  @param[in] rows (uint): Number of neurons in the column (number of rows).
232  @param[in] cols (uint): Number of neurons in the row (number of columns).
233  @param[in] conn_type (type_conn): Type of connection between oscillators in the network (grid four, grid eight, honeycomb, function neighbour).
234  @param[in] parameters (som_parameters): Other specific parameters.
235  @param[in] ccore (bool): If True simulation is performed by CCORE library (C++ implementation of pyclustering).
236 
237  """
238 
239  # some of these parameters are required despite core implementation, for example, for network visualization.
240  self._cols = cols
241 
242  self._rows = rows
243 
244  self._size = cols * rows
245 
246  self._conn_type = conn_type
247 
248  self._data = None
249 
250  self._neighbors = None
251 
252  self._local_radius = 0.0
253 
254  self._learn_rate = 0.0
255 
256  self.__ccore_som_pointer = None
257 
258  self._params = parameters or som_parameters()
259 
260  if self._params.init_radius is None:
261  self._params.init_radius = self.__initialize_initial_radius(rows, cols)
262 
263  if (ccore is True) and ccore_library.workable():
264  self.__ccore_som_pointer = wrapper.som_create(rows, cols, conn_type, self._params)
265 
266  else:
267  # location
268  self._location = self.__initialize_locations(rows, cols)
269 
270  # default weights
271  self._weights = [[0.0]] * self._size
272 
273  # awards
274  self._award = [0] * self._size
275 
276  # captured objects
277  self._capture_objects = [[] for i in range(self._size)]
278 
279  # distances - calculate and store them only during training
280  self._sqrt_distances = None
281 
282  # connections
283  if conn_type != type_conn.func_neighbor:
284  self._create_connections(conn_type)
285 
286  def __del__(self):
287  """!
288  @brief Destructor of the self-organized feature map.
289 
290  """
291 
292  if self.__ccore_som_pointer is not None:
293  wrapper.som_destroy(self.__ccore_som_pointer)
294 
295  def __len__(self):
296  """!
297  @brief Returns size of the network that defines by amount of neuron in it.
298 
299  @return (uint) Size of self-organized map (amount of neurons).
300 
301  """
302 
303  return self._size
304 
305  def __getstate__(self):
306  """
307  @brief Returns state of SOM network that can be used to store network.
308 
309  """
310  if self.__ccore_som_pointer is not None:
312  return self.__get_dump_from_python(True)
313 
314  return self.__get_dump_from_python(False)
315 
316  def __setstate__(self, som_state):
317  """
318  @brief Set state of SOM network that can be used to load network.
319 
320  """
321  if som_state['ccore'] is True and ccore_library.workable():
322  self.__upload_dump_to_ccore(som_state['state'])
323  else:
324  self.__upload_dump_to_python(som_state['state'])
325 
326  def __initialize_initial_radius(self, rows, cols):
327  """!
328  @brief Initialize initial radius using map sizes.
329 
330  @param[in] rows (uint): Number of neurons in the column (number of rows).
331  @param[in] cols (uint): Number of neurons in the row (number of columns).
332 
333  @return (list) Value of initial radius.
334 
335  """
336 
337  if (cols + rows) / 4.0 > 1.0:
338  return 2.0
339 
340  elif (cols > 1) and (rows > 1):
341  return 1.5
342 
343  else:
344  return 1.0
345 
346  def __initialize_locations(self, rows, cols):
347  """!
348  @brief Initialize locations (coordinates in SOM grid) of each neurons in the map.
349 
350  @param[in] rows (uint): Number of neurons in the column (number of rows).
351  @param[in] cols (uint): Number of neurons in the row (number of columns).
352 
353  @return (list) List of coordinates of each neuron in map.
354 
355  """
356 
357  location = list()
358  for i in range(rows):
359  for j in range(cols):
360  location.append([float(i), float(j)])
361 
362  return location
363 
364  def __initialize_distances(self, size, location):
365  """!
366  @brief Initialize distance matrix in SOM grid.
367 
368  @param[in] size (uint): Amount of neurons in the network.
369  @param[in] location (list): List of coordinates of each neuron in the network.
370 
371  @return (list) Distance matrix between neurons in the network.
372 
373  """
374  sqrt_distances = [[[] for i in range(size)] for j in range(size)]
375  for i in range(size):
376  for j in range(i, size, 1):
377  dist = euclidean_distance_square(location[i], location[j])
378  sqrt_distances[i][j] = dist
379  sqrt_distances[j][i] = dist
380 
381  return sqrt_distances
382 
383  def _create_initial_weights(self, init_type):
384  """!
385  @brief Creates initial weights for neurons in line with the specified initialization.
386 
387  @param[in] init_type (type_init): Type of initialization of initial neuron weights (random, random in center of the input data, random distributed in data, ditributed in line with uniform grid).
388 
389  """
390 
391  dim_info = dimension_info(self._data)
392 
393  step_x = dim_info.get_center()[0]
394  if self._rows > 1:
395  step_x = dim_info.get_width()[0] / (self._rows - 1)
396 
397  step_y = 0.0
398  if dim_info.get_dimensions() > 1:
399  step_y = dim_info.get_center()[1]
400  if self._cols > 1:
401  step_y = dim_info.get_width()[1] / (self._cols - 1)
402 
403  # generate weights (topological coordinates)
404  random.seed(self._params.random_state)
405 
406  # Uniform grid.
407  if init_type == type_init.uniform_grid:
408  # Predefined weights in line with input data.
409  self._weights = [[[] for i in range(dim_info.get_dimensions())] for j in range(self._size)]
410  for i in range(self._size):
411  location = self._location[i]
412  for dim in range(dim_info.get_dimensions()):
413  if dim == 0:
414  if self._rows > 1:
415  self._weights[i][dim] = dim_info.get_minimum_coordinate()[dim] + step_x * location[dim]
416  else:
417  self._weights[i][dim] = dim_info.get_center()[dim]
418 
419  elif dim == 1:
420  if self._cols > 1:
421  self._weights[i][dim] = dim_info.get_minimum_coordinate()[dim] + step_y * location[dim]
422  else:
423  self._weights[i][dim] = dim_info.get_center()[dim]
424  else:
425  self._weights[i][dim] = dim_info.get_center()[dim]
426 
427  elif init_type == type_init.random_surface:
428  # Random weights at the full surface.
429  self._weights = [
430  [random.uniform(dim_info.get_minimum_coordinate()[i], dim_info.get_maximum_coordinate()[i]) for i in
431  range(dim_info.get_dimensions())] for _ in range(self._size)]
432 
433  elif init_type == type_init.random_centroid:
434  # Random weights at the center of input data.
435  self._weights = [[(random.random() + dim_info.get_center()[i]) for i in range(dim_info.get_dimensions())]
436  for _ in range(self._size)]
437 
438  else:
439  # Random weights of input data.
440  self._weights = [[random.random() for i in range(dim_info.get_dimensions())] for _ in range(self._size)]
441 
442  def _create_connections(self, conn_type):
443  """!
444  @brief Create connections in line with input rule (grid four, grid eight, honeycomb, function neighbour).
445 
446  @param[in] conn_type (type_conn): Type of connection between oscillators in the network.
447 
448  """
449 
450  self._neighbors = [[] for index in range(self._size)]
451 
452  for index in range(0, self._size, 1):
453  upper_index = index - self._cols
454  upper_left_index = index - self._cols - 1
455  upper_right_index = index - self._cols + 1
456 
457  lower_index = index + self._cols
458  lower_left_index = index + self._cols - 1
459  lower_right_index = index + self._cols + 1
460 
461  left_index = index - 1
462  right_index = index + 1
463 
464  node_row_index = math.floor(index / self._cols)
465  upper_row_index = node_row_index - 1
466  lower_row_index = node_row_index + 1
467 
468  if (conn_type == type_conn.grid_eight) or (conn_type == type_conn.grid_four):
469  if upper_index >= 0:
470  self._neighbors[index].append(upper_index)
471 
472  if lower_index < self._size:
473  self._neighbors[index].append(lower_index)
474 
475  if (conn_type == type_conn.grid_eight) or (conn_type == type_conn.grid_four) or (
476  conn_type == type_conn.honeycomb):
477  if (left_index >= 0) and (math.floor(left_index / self._cols) == node_row_index):
478  self._neighbors[index].append(left_index)
479 
480  if (right_index < self._size) and (math.floor(right_index / self._cols) == node_row_index):
481  self._neighbors[index].append(right_index)
482 
483  if conn_type == type_conn.grid_eight:
484  if (upper_left_index >= 0) and (math.floor(upper_left_index / self._cols) == upper_row_index):
485  self._neighbors[index].append(upper_left_index)
486 
487  if (upper_right_index >= 0) and (math.floor(upper_right_index / self._cols) == upper_row_index):
488  self._neighbors[index].append(upper_right_index)
489 
490  if (lower_left_index < self._size) and (math.floor(lower_left_index / self._cols) == lower_row_index):
491  self._neighbors[index].append(lower_left_index)
492 
493  if (lower_right_index < self._size) and (math.floor(lower_right_index / self._cols) == lower_row_index):
494  self._neighbors[index].append(lower_right_index)
495 
496  if conn_type == type_conn.honeycomb:
497  if (node_row_index % 2) == 0:
498  upper_left_index = index - self._cols
499  upper_right_index = index - self._cols + 1
500 
501  lower_left_index = index + self._cols
502  lower_right_index = index + self._cols + 1
503  else:
504  upper_left_index = index - self._cols - 1
505  upper_right_index = index - self._cols
506 
507  lower_left_index = index + self._cols - 1
508  lower_right_index = index + self._cols
509 
510  if (upper_left_index >= 0) and (math.floor(upper_left_index / self._cols) == upper_row_index):
511  self._neighbors[index].append(upper_left_index)
512 
513  if (upper_right_index >= 0) and (math.floor(upper_right_index / self._cols) == upper_row_index):
514  self._neighbors[index].append(upper_right_index)
515 
516  if (lower_left_index < self._size) and (math.floor(lower_left_index / self._cols) == lower_row_index):
517  self._neighbors[index].append(lower_left_index)
518 
519  if (lower_right_index < self._size) and (math.floor(lower_right_index / self._cols) == lower_row_index):
520  self._neighbors[index].append(lower_right_index)
521 
522  def _competition(self, x):
523  """!
524  @brief Calculates neuron winner (distance, neuron index).
525 
526  @param[in] x (list): Input pattern from the input data set, for example it can be coordinates of point.
527 
528  @return (uint) Returns index of neuron that is winner.
529 
530  """
531 
532  index = 0
533  minimum = euclidean_distance_square(self._weights[0], x)
534 
535  for i in range(1, self._size, 1):
536  candidate = euclidean_distance_square(self._weights[i], x)
537  if candidate < minimum:
538  index = i
539  minimum = candidate
540 
541  return index
542 
543  def _adaptation(self, index, x):
544  """!
545  @brief Change weight of neurons in line with won neuron.
546 
547  @param[in] index (uint): Index of neuron-winner.
548  @param[in] x (list): Input pattern from the input data set.
549 
550  """
551 
552  dimension = len(self._weights[0])
553 
554  if self._conn_type == type_conn.func_neighbor:
555  for neuron_index in range(self._size):
556  distance = self._sqrt_distances[index][neuron_index]
557 
558  if distance < self._local_radius:
559  influence = math.exp(-(distance / (2.0 * self._local_radius)))
560 
561  for i in range(dimension):
562  self._weights[neuron_index][i] = self._weights[neuron_index][
563  i] + self._learn_rate * influence * (
564  x[i] - self._weights[neuron_index][i])
565 
566  else:
567  for i in range(dimension):
568  self._weights[index][i] = self._weights[index][i] + self._learn_rate * (x[i] - self._weights[index][i])
569 
570  for neighbor_index in self._neighbors[index]:
571  distance = self._sqrt_distances[index][neighbor_index]
572  if distance < self._local_radius:
573  influence = math.exp(-(distance / (2.0 * self._local_radius)))
574 
575  for i in range(dimension):
576  self._weights[neighbor_index][i] = self._weights[neighbor_index][
577  i] + self._learn_rate * influence * (
578  x[i] - self._weights[neighbor_index][i])
579 
580  def train(self, data, epochs, autostop=False):
581  """!
582  @brief Trains self-organized feature map (SOM).
583 
584  @param[in] data (list): Input data - list of points where each point is represented by list of features, for example coordinates.
585  @param[in] epochs (uint): Number of epochs for training.
586  @param[in] autostop (bool): Automatic termination of learning process when adaptation is not occurred.
587 
588  @return (uint) Number of learning iterations.
589 
590  """
591 
592  self._data = data
593 
594  if self.__ccore_som_pointer is not None:
595  return wrapper.som_train(self.__ccore_som_pointer, data, epochs, autostop)
596 
597  self._sqrt_distances = self.__initialize_distances(self._size, self._location)
598 
599  for i in range(self._size):
600  self._award[i] = 0
601  self._capture_objects[i].clear()
602 
603  # weights
604  self._create_initial_weights(self._params.init_type)
605 
606  previous_weights = None
607 
608  for epoch in range(1, epochs + 1):
609  # Depression term of coupling
610  self._local_radius = (self._params.init_radius * math.exp(-(epoch / epochs))) ** 2
611  self._learn_rate = self._params.init_learn_rate * math.exp(-(epoch / epochs))
612 
613  # Clear statistics
614  if autostop:
615  for i in range(self._size):
616  self._award[i] = 0
617  self._capture_objects[i].clear()
618 
619  for i in range(len(self._data)):
620  # Step 1: Competition:
621  index = self._competition(self._data[i])
622 
623  # Step 2: Adaptation:
624  self._adaptation(index, self._data[i])
625 
626  # Update statistics
627  if (autostop is True) or (epoch == epochs):
628  self._award[index] += 1
629  self._capture_objects[index].append(i)
630 
631  # Check requirement of stopping
632  if autostop:
633  if previous_weights is not None:
634  maximal_adaptation = self._get_maximal_adaptation(previous_weights)
635  if maximal_adaptation < self._params.adaptation_threshold:
636  return epoch
637 
638  previous_weights = [item[:] for item in self._weights]
639 
640  return epochs
641 
642  def simulate(self, input_pattern):
643  """!
644  @brief Processes input pattern (no learining) and returns index of neuron-winner.
645  Using index of neuron winner catched object can be obtained using property capture_objects.
646 
647  @param[in] input_pattern (list): Input pattern.
648 
649  @return (uint) Returns index of neuron-winner.
650 
651  @see capture_objects
652 
653  """
654 
655  if self.__ccore_som_pointer is not None:
656  return wrapper.som_simulate(self.__ccore_som_pointer, input_pattern)
657 
658  return self._competition(input_pattern)
659 
660  def _get_maximal_adaptation(self, previous_weights):
661  """!
662  @brief Calculates maximum changes of weight in line with comparison between previous weights and current weights.
663 
664  @param[in] previous_weights (list): Weights from the previous step of learning process.
665 
666  @return (double) Value that represents maximum changes of weight after adaptation process.
667 
668  """
669 
670  dimension = len(self._data[0])
671  maximal_adaptation = 0.0
672 
673  for neuron_index in range(self._size):
674  for dim in range(dimension):
675  current_adaptation = previous_weights[neuron_index][dim] - self._weights[neuron_index][dim]
676 
677  if current_adaptation < 0:
678  current_adaptation = -current_adaptation
679 
680  if maximal_adaptation < current_adaptation:
681  maximal_adaptation = current_adaptation
682 
683  return maximal_adaptation
684 
685  def get_winner_number(self):
686  """!
687  @brief Calculates number of winner at the last step of learning process.
688 
689  @return (uint) Number of winner.
690 
691  """
692 
693  if self.__ccore_som_pointer is not None:
694  self._award = wrapper.som_get_awards(self.__ccore_som_pointer)
695 
696  winner_number = 0
697  for i in range(self._size):
698  if self._award[i] > 0:
699  winner_number += 1
700 
701  return winner_number
702 
704  """!
705  @brief Shows gray visualization of U-matrix (distance matrix).
706 
707  @see get_distance_matrix()
708 
709  """
710  distance_matrix = self.get_distance_matrix()
711 
712  plt.imshow(distance_matrix, cmap=plt.get_cmap('hot'), interpolation='kaiser')
713  plt.title("U-Matrix")
714  plt.colorbar()
715  plt.show()
716 
718  """!
719  @brief Calculates distance matrix (U-matrix).
720  @details The U-Matrix visualizes based on the distance in input space between a weight vector and its neighbors on map.
721 
722  @return (list) Distance matrix (U-matrix).
723 
724  @see show_distance_matrix()
725  @see get_density_matrix()
726 
727  """
728  if self.__ccore_som_pointer is not None:
729  self._weights = wrapper.som_get_weights(self.__ccore_som_pointer)
730 
731  if self._conn_type != type_conn.func_neighbor:
732  self._neighbors = wrapper.som_get_neighbors(self.__ccore_som_pointer)
733 
734  distance_matrix = [[0.0] * self._cols for i in range(self._rows)]
735 
736  for i in range(self._rows):
737  for j in range(self._cols):
738  neuron_index = i * self._cols + j
739 
740  if self._conn_type == type_conn.func_neighbor:
741  self._create_connections(type_conn.grid_eight)
742 
743  for neighbor_index in self._neighbors[neuron_index]:
744  distance_matrix[i][j] += euclidean_distance_square(self._weights[neuron_index],
745  self._weights[neighbor_index])
746 
747  distance_matrix[i][j] /= len(self._neighbors[neuron_index])
748 
749  return distance_matrix
750 
751  def show_density_matrix(self, surface_divider=20.0):
752  """!
753  @brief Show density matrix (P-matrix) using kernel density estimation.
754 
755  @param[in] surface_divider (double): Divider in each dimension that affect radius for density measurement.
756 
757  @see show_distance_matrix()
758 
759  """
760  density_matrix = self.get_density_matrix(surface_divider)
761 
762  plt.imshow(density_matrix, cmap=plt.get_cmap('hot'), interpolation='kaiser')
763  plt.title("P-Matrix")
764  plt.colorbar()
765  plt.show()
766 
767  def get_density_matrix(self, surface_divider=20.0):
768  """!
769  @brief Calculates density matrix (P-Matrix).
770 
771  @param[in] surface_divider (double): Divider in each dimension that affect radius for density measurement.
772 
773  @return (list) Density matrix (P-Matrix).
774 
775  @see get_distance_matrix()
776 
777  """
778 
779  if self.__ccore_som_pointer is not None:
780  self._weights = wrapper.som_get_weights(self.__ccore_som_pointer)
781 
782  density_matrix = [[0] * self._cols for i in range(self._rows)]
783  dimension = len(self._weights[0])
784 
785  dim_max = [float('-Inf')] * dimension
786  dim_min = [float('Inf')] * dimension
787 
788  for weight in self._weights:
789  for index_dim in range(dimension):
790  if weight[index_dim] > dim_max[index_dim]:
791  dim_max[index_dim] = weight[index_dim]
792 
793  if weight[index_dim] < dim_min[index_dim]:
794  dim_min[index_dim] = weight[index_dim]
795 
796  radius = [0.0] * len(self._weights[0])
797  for index_dim in range(dimension):
798  radius[index_dim] = (dim_max[index_dim] - dim_min[index_dim]) / surface_divider
799 
800 
801  for point in self._data:
802  for index_neuron in range(len(self)):
803  point_covered = True
804 
805  for index_dim in range(dimension):
806  if abs(point[index_dim] - self._weights[index_neuron][index_dim]) > radius[index_dim]:
807  point_covered = False
808  break
809 
810  row = int(math.floor(index_neuron / self._cols))
811  col = index_neuron - row * self._cols
812 
813  if point_covered is True:
814  density_matrix[row][col] += 1
815 
816  return density_matrix
817 
819  """!
820  @brief Show a winner matrix where each element corresponds to neuron and value represents
821  amount of won objects from input data-space at the last training iteration.
822 
823  @see show_distance_matrix()
824 
825  """
826 
827  if self.__ccore_som_pointer is not None:
828  self._award = wrapper.som_get_awards(self.__ccore_som_pointer)
829 
830  (fig, ax) = plt.subplots()
831  winner_matrix = [[0] * self._cols for _ in range(self._rows)]
832 
833  for i in range(self._rows):
834  for j in range(self._cols):
835  neuron_index = i * self._cols + j
836 
837  winner_matrix[i][j] = self._award[neuron_index]
838  ax.text(i, j, str(winner_matrix[i][j]), va='center', ha='center')
839 
840  ax.imshow(winner_matrix, cmap=plt.get_cmap('cool'), interpolation='none')
841  ax.grid(True)
842 
843  plt.title("Winner Matrix")
844  plt.show()
845 
846  def show_network(self, awards=False, belongs=False, coupling=True, dataset=True, marker_type='o'):
847  """!
848  @brief Shows neurons in the dimension of data.
849 
850  @param[in] awards (bool): If True - displays how many objects won each neuron.
851  @param[in] belongs (bool): If True - marks each won object by according index of neuron-winner (only when
852  dataset is displayed too).
853  @param[in] coupling (bool): If True - displays connections between neurons (except case when function neighbor
854  is used).
855  @param[in] dataset (bool): If True - displays inputs data set.
856  @param[in] marker_type (string): Defines marker that is used to denote neurons on the plot.
857 
858  """
859 
860  if self.__ccore_som_pointer is not None:
861  self._size = wrapper.som_get_size(self.__ccore_som_pointer)
862  self._weights = wrapper.som_get_weights(self.__ccore_som_pointer)
863  self._neighbors = wrapper.som_get_neighbors(self.__ccore_som_pointer)
864  self._award = wrapper.som_get_awards(self.__ccore_som_pointer)
865 
866  dimension = len(self._weights[0])
867 
868  fig = plt.figure()
869 
870  # Check for dimensions
871  if (dimension == 1) or (dimension == 2):
872  axes = fig.add_subplot(111)
873  elif dimension == 3:
874  axes = fig.gca(projection='3d')
875  else:
876  raise NotImplementedError('Impossible to show network in data-space that is differ from 1D, 2D or 3D.')
877 
878  if (self._data is not None) and (dataset is True):
879  for x in self._data:
880  if dimension == 1:
881  axes.plot(x[0], 0.0, 'b|', ms=30)
882 
883  elif dimension == 2:
884  axes.plot(x[0], x[1], 'b.')
885 
886  elif dimension == 3:
887  axes.scatter(x[0], x[1], x[2], c='b', marker='.')
888 
889  # Show neurons
890  for index in range(self._size):
891  color = 'g'
892  if self._award[index] == 0:
893  color = 'y'
894 
895  if dimension == 1:
896  axes.plot(self._weights[index][0], 0.0, color + marker_type)
897 
898  if awards:
899  location = '{0}'.format(self._award[index])
900  axes.text(self._weights[index][0], 0.0, location, color='black', fontsize=10)
901 
902  if belongs and self._data is not None:
903  location = '{0}'.format(index)
904  axes.text(self._weights[index][0], 0.0, location, color='black', fontsize=12)
905  for k in range(len(self._capture_objects[index])):
906  point = self._data[self._capture_objects[index][k]]
907  axes.text(point[0], 0.0, location, color='blue', fontsize=10)
908 
909  if dimension == 2:
910  axes.plot(self._weights[index][0], self._weights[index][1], color + marker_type)
911 
912  if awards:
913  location = '{0}'.format(self._award[index])
914  axes.text(self._weights[index][0], self._weights[index][1], location, color='black', fontsize=10)
915 
916  if belongs and self._data is not None:
917  location = '{0}'.format(index)
918  axes.text(self._weights[index][0], self._weights[index][1], location, color='black', fontsize=12)
919  for k in range(len(self._capture_objects[index])):
920  point = self._data[self._capture_objects[index][k]]
921  axes.text(point[0], point[1], location, color='blue', fontsize=10)
922 
923  if (self._conn_type != type_conn.func_neighbor) and (coupling is True):
924  for neighbor in self._neighbors[index]:
925  if neighbor > index:
926  axes.plot([self._weights[index][0], self._weights[neighbor][0]],
927  [self._weights[index][1], self._weights[neighbor][1]],
928  'g', linewidth=0.5)
929 
930  elif dimension == 3:
931  axes.scatter(self._weights[index][0], self._weights[index][1], self._weights[index][2], c=color,
932  marker=marker_type)
933 
934  if (self._conn_type != type_conn.func_neighbor) and (coupling != False):
935  for neighbor in self._neighbors[index]:
936  if neighbor > index:
937  axes.plot([self._weights[index][0], self._weights[neighbor][0]],
938  [self._weights[index][1], self._weights[neighbor][1]],
939  [self._weights[index][2], self._weights[neighbor][2]],
940  'g-', linewidth=0.5)
941 
942  plt.title("Network Structure")
943  plt.grid()
944  plt.show()
945 
946  def __get_dump_from_python(self, ccore_usage):
947  return {'ccore': ccore_usage,
948  'state': {'cols': self._cols,
949  'rows': self._rows,
950  'size': self._size,
951  'conn_type': self._conn_type,
952  'neighbors': self._neighbors,
953  'local_radius': self._local_radius,
954  'learn_rate': self._learn_rate,
955  'params': self._params,
956  'location': self._location,
957  'weights': self._weights,
958  'award': self._award,
959  'capture_objects': self._capture_objects}}
960 
961  def __download_dump_from_ccore(self):
962  self._location = self.__initialize_locations(self._rows, self._cols)
963  self._weights = wrapper.som_get_weights(self.__ccore_som_pointer)
964  self._award = wrapper.som_get_awards(self.__ccore_som_pointer)
965  self._capture_objects = wrapper.som_get_capture_objects(self.__ccore_som_pointer)
966 
967  def __upload_common_part(self, state_dump):
968  self._cols = state_dump['cols']
969  self._rows = state_dump['rows']
970  self._size = state_dump['size']
971  self._conn_type = state_dump['conn_type']
972  self._neighbors = state_dump['neighbors']
973  self._local_radius = state_dump['local_radius']
974  self._learn_rate = state_dump['learn_rate']
975  self._params = state_dump['params']
976  self._neighbors = None
977 
978  def __upload_dump_to_python(self, state_dump):
979  self.__ccore_som_pointer = None
980 
981  self.__upload_common_part(state_dump)
982 
983  self._location = state_dump['location']
984  self._weights = state_dump['weights']
985  self._award = state_dump['award']
986  self._capture_objects = state_dump['capture_objects']
987 
988  self._location = self.__initialize_locations(self._rows, self._cols)
990 
991  def __upload_dump_to_ccore(self, state_dump):
992  self.__upload_common_part(state_dump)
993  self.__ccore_som_pointer = wrapper.som_create(self._rows, self._cols, self._conn_type, self._params)
994  wrapper.som_load(self.__ccore_som_pointer, state_dump['weights'], state_dump['award'],
995  state_dump['capture_objects'])
pyclustering.nnet.som.som._location
_location
Definition: som.py:268
pyclustering.nnet.som.som_parameters.adaptation_threshold
adaptation_threshold
Condition that defines when the learining process should be stopped.
Definition: som.py:91
pyclustering.nnet.som.som.show_winner_matrix
def show_winner_matrix(self)
Show a winner matrix where each element corresponds to neuron and value represents amount of won obje...
Definition: som.py:818
pyclustering.nnet.som.som._weights
_weights
Definition: som.py:189
pyclustering.nnet.som.som.__upload_dump_to_ccore
def __upload_dump_to_ccore(self, state_dump)
Definition: som.py:991
pyclustering.nnet.som.som.__upload_common_part
def __upload_common_part(self, state_dump)
Definition: som.py:967
pyclustering.nnet.som.type_conn
Enumeration of connection types for SOM.
Definition: som.py:27
pyclustering.nnet.som.som
Represents self-organized feature map (SOM).
Definition: som.py:97
pyclustering.nnet.som.som_parameters.random_state
random_state
Seed for random state (by default is None, current system time is used).
Definition: som.py:94
pyclustering.nnet.som.som._data
_data
Definition: som.py:248
pyclustering.nnet.som.som.__len__
def __len__(self)
Returns size of the network that defines by amount of neuron in it.
Definition: som.py:295
pyclustering.nnet.som.som._params
_params
Definition: som.py:258
pyclustering.nnet.som.som._create_connections
def _create_connections(self, conn_type)
Create connections in line with input rule (grid four, grid eight, honeycomb, function neighbour).
Definition: som.py:442
pyclustering.nnet.som.som.size
def size(self)
Return size of self-organized map that is defined by total number of neurons.
Definition: som.py:166
pyclustering.nnet.som.som._rows
_rows
Definition: som.py:242
pyclustering.nnet.som.som.show_density_matrix
def show_density_matrix(self, surface_divider=20.0)
Show density matrix (P-matrix) using kernel density estimation.
Definition: som.py:751
pyclustering.nnet.som.som._conn_type
_conn_type
Definition: som.py:246
pyclustering.nnet.som.som._award
_award
Definition: som.py:205
pyclustering.nnet.som.som.__initialize_locations
def __initialize_locations(self, rows, cols)
Initialize locations (coordinates in SOM grid) of each neurons in the map.
Definition: som.py:346
pyclustering.nnet.som.som_parameters.init_radius
init_radius
Initial radius.
Definition: som.py:85
pyclustering.nnet.som.som._adaptation
def _adaptation(self, index, x)
Change weight of neurons in line with won neuron.
Definition: som.py:543
pyclustering.nnet.som.som.train
def train(self, data, epochs, autostop=False)
Trains self-organized feature map (SOM).
Definition: som.py:580
pyclustering.nnet.som.som._get_maximal_adaptation
def _get_maximal_adaptation(self, previous_weights)
Calculates maximum changes of weight in line with comparison between previous weights and current wei...
Definition: som.py:660
pyclustering.nnet.som.som._cols
_cols
Definition: som.py:240
pyclustering.nnet.som.som.weights
def weights(self)
Return weight of each neuron.
Definition: som.py:180
pyclustering.nnet.som.som.__upload_dump_to_python
def __upload_dump_to_python(self, state_dump)
Definition: som.py:978
pyclustering.nnet.som.som.__download_dump_from_ccore
def __download_dump_from_ccore(self)
Definition: som.py:961
pyclustering.nnet.som.som_parameters.__init__
def __init__(self)
Creates SOM parameters.
Definition: som.py:75
pyclustering.nnet.som.som.get_density_matrix
def get_density_matrix(self, surface_divider=20.0)
Calculates density matrix (P-Matrix).
Definition: som.py:767
pyclustering.nnet.som.som.__initialize_initial_radius
def __initialize_initial_radius(self, rows, cols)
Initialize initial radius using map sizes.
Definition: som.py:326
pyclustering.nnet.som.som.show_distance_matrix
def show_distance_matrix(self)
Shows gray visualization of U-matrix (distance matrix).
Definition: som.py:703
pyclustering.nnet.som.som.__init__
def __init__(self, rows, cols, conn_type=type_conn.grid_eight, parameters=None, ccore=True)
Constructor of self-organized map.
Definition: som.py:227
pyclustering.nnet.som.som.get_distance_matrix
def get_distance_matrix(self)
Calculates distance matrix (U-matrix).
Definition: som.py:717
pyclustering.nnet.som.som.__initialize_distances
def __initialize_distances(self, size, location)
Initialize distance matrix in SOM grid.
Definition: som.py:364
pyclustering.nnet.som.som._capture_objects
_capture_objects
Definition: som.py:223
pyclustering.nnet.som.som.show_network
def show_network(self, awards=False, belongs=False, coupling=True, dataset=True, marker_type='o')
Shows neurons in the dimension of data.
Definition: som.py:846
pyclustering.nnet.som.som_parameters.init_learn_rate
init_learn_rate
Rate of learning.
Definition: som.py:88
pyclustering.nnet.som.som._create_initial_weights
def _create_initial_weights(self, init_type)
Creates initial weights for neurons in line with the specified initialization.
Definition: som.py:383
pyclustering.nnet.som.som._neighbors
_neighbors
Definition: som.py:250
pyclustering.nnet.som.som._local_radius
_local_radius
Definition: som.py:252
pyclustering.nnet.som.som._competition
def _competition(self, x)
Calculates neuron winner (distance, neuron index).
Definition: som.py:522
pyclustering.nnet.som.type_init
Enumeration of initialization types for SOM.
Definition: som.py:48
pyclustering.nnet.som.som.__del__
def __del__(self)
Destructor of the self-organized feature map.
Definition: som.py:286
pyclustering.nnet.som.som.__getstate__
def __getstate__(self)
Definition: som.py:305
pyclustering.nnet.som.som_parameters
Represents SOM parameters.
Definition: som.py:69
pyclustering.nnet.som.som._learn_rate
_learn_rate
Definition: som.py:254
pyclustering.utils
Utils that are used by modules of pyclustering.
Definition: __init__.py:1
pyclustering.nnet.som.som.get_winner_number
def get_winner_number(self)
Calculates number of winner at the last step of learning process.
Definition: som.py:685
pyclustering.nnet.som.som.__setstate__
def __setstate__(self, som_state)
Definition: som.py:316
pyclustering.nnet.som.som._sqrt_distances
_sqrt_distances
Definition: som.py:280
pyclustering.nnet.som.som.__ccore_som_pointer
__ccore_som_pointer
Definition: som.py:256
pyclustering.nnet.som.som.simulate
def simulate(self, input_pattern)
Processes input pattern (no learining) and returns index of neuron-winner.
Definition: som.py:642
pyclustering.nnet.som.som._size
_size
Definition: som.py:175
pyclustering.nnet.som.som_parameters.init_type
init_type
Defines an initialization way for neuron weights (random, random in center of the input data,...
Definition: som.py:82
pyclustering.nnet.som.som.capture_objects
def capture_objects(self)
Returns indexes of captured objects by each neuron.
Definition: som.py:210
pyclustering.nnet.som.som.__get_dump_from_python
def __get_dump_from_python(self, ccore_usage)
Definition: som.py:946
pyclustering.nnet.som.som.awards
def awards(self)
Return amount of captured objects by each neuron after training.
Definition: som.py:194