JustGlowing / minisom

:red_circle: MiniSom is a minimalistic implementation of the Self Organizing Maps
MIT License
1.43k stars 420 forks source link

How to visualize weights lattice? #119

Open mariajmolina opened 2 years ago

mariajmolina commented 2 years ago

Hello! I want to make a sammon plot of my trained SOM to view the location of the lattice nodes in order to determine whether the SOM is "twisted" or not. I have come across examples in the issues section of MiniSOM and example notebooks for hexagonal topology, but not for rectangular. Can someone please help with how the coordinates for the nodes would be extracted for the rectangular topology type SOM? Thanks for your help!

JustGlowing commented 2 years ago

Hi there, the method get_weights returns a matrix with the weight vector for each coordinate in the map. Once your som is trained they should be arranged in a good like pattern. I hope this helps.

mariajmolina commented 2 years ago

Thanks @JustGlowing !

Does this look correct to you below? Since the weights are multi-dimensional and I just want to see whether there is "twisting" occurring in the lattice, I took the mean across the 3rd dimension.

from minisom import MiniSom

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

#Training inputs for RGBcolors
colorss = [[0., 0., 0.],
          [0., 0., 1.],
          [0., 0., 0.5],
          [0.125, 0.529, 1.0],
          [0.33, 0.4, 0.67],
          [0.6, 0.5, 1.0],
          [0., 1., 0.],
          [1., 0., 0.],
          [0., 1., 1.],
          [1., 0., 1.],
          [1., 1., 0.],
          [1., 1., 1.],
          [.33, .33, .33],
          [.5, .5, .5],
          [.66, .66, .66]]

som = MiniSom(3, 3, 3, sigma=1.5, 
              learning_rate=2.5, topology='rectangular',
              neighborhood_function='gaussian')

som.train(colorss, 500, random_order=True, verbose=True)

# x-axis for plotting
xcoord = np.vstack([np.arange(0,3),
                    np.arange(0,3),
                    np.arange(0,3)])

# y-axis weight locations
ycoord = np.nanmean(som.get_weights(), axis=2)

plt.scatter(xcoord, ycoord, c='k')

plt.plot(xcoord[:,0],ycoord[:,0], c='k')

plt.plot(xcoord[:,1],ycoord[:,1], c='k')

plt.plot(xcoord[:,2],ycoord[:,2], c='k')

plt.plot(xcoord[0,:],ycoord[0,:], c='k')

plt.plot(xcoord[1,:],ycoord[1,:], c='k')

plt.plot(xcoord[2,:],ycoord[2,:], c='k')

plt.show()

And the resultant plot:

Screen Shot 2021-10-06 at 9 01 51 AM
JustGlowing commented 2 years ago

It's an interesting approach but I'm not sure the mean is reflective of the topology. Try with a 2D dataset first to have a feel. For higher dimensional data you can like at each subspace separately.

mariajmolina commented 2 years ago

Good point. After reading more into this today, I realized that Sammon mapping is a dimensionality reduction technique. I found a python implementation of sammon mapping here.

Here is an example of using it with minisom. Hopefully I am doing this correctly! Any comments welcome!

from minisom import MiniSom

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import sammon

#Training inputs for RGBcolors
colors = [[0., 0., 0.],
          [0., 0., 1.],
          [0., 0., 0.5],
          [0.125, 0.529, 1.0],
          [0.33, 0.4, 0.67],
          [0.6, 0.5, 1.0],
          [0., 1., 0.],
          [1., 0., 0.],
          [0., 1., 1.],
          [1., 0., 1.],
          [1., 1., 0.],
          [1., 1., 1.],
          [.33, .33, .33],
          [.5, .5, .5],
          [.66, .66, .66]]

colors = np.array(colors)

som = MiniSom(3, 3, 3, sigma=1.5, 
              learning_rate=2.5, topology='rectangular',
              neighborhood_function='gaussian')

som.train(colors, 500, random_order=True, verbose=True)

[y,E] = sammon.sammon(som.get_weights().reshape(3*3,3), 2)  # reshape lattice into two-dimensional array for sammon

plt.scatter(y[:,0], y[:,1], c='k')

plt.plot(y[:3,0], y[:3,1], c='k')

plt.plot(y[3:6,0], y[3:6,1], c='k')

plt.plot(y[6:9,0], y[6:9,1], c='k')

plt.plot(y[::3,0], y[::3,1], c='k')

plt.plot(y[1::3,0], y[1::3,1], c='k')

plt.plot(y[2::3,0], y[2::3,1], c='k')

plt.show()
Screen Shot 2021-10-06 at 5 49 01 PM
JustGlowing commented 2 years ago

It looks very good. I might add this example in the library if I managed to generalize the code that plots the lines.

mariajmolina commented 2 years ago

Sounds great. Glad that this helps!

JustGlowing commented 2 years ago

hi @mariajmolina

This example shows how to visualize the lattice in a 3D chart without using sammons to reduce the dimensionality:

https://colab.research.google.com/drive/1UnJKG3i0mvUiOJB2UPxaSDygwlcv34w0?usp=sharing

mariajmolina commented 2 years ago

Thank you! This is great!