function W = som(a,k,nrruns,eta,h) %SOM Simple routine computing a Self-Organizing Map (SOM) % % W = SOM(X,K) % % Train a 2D SOM on dataset X. In K the size of the map is defined. The % map can maximally be 2D. When K contains just a single value, it is % assumed that a 1D map should be trained. The output of the mapping % contains the (negative) distances to all neurons. To obtain the index % of the closest neuron, do A*W*LABELD. % % W = SOM(X,K,NRRUNS,ETA,H) % % Train the SOM for NRRUNS iterations, using learning rate ETA and a % Gaussian neighborhood function with width H*sqrt(MAXD), where MAXD % is the maximum distance in the dataset X. % % There is the extra feature, that NRRUNS, ETA and H can be vectors, % such that it can be run several iterations using larger ETA and H, % and after that with smaller values. % % Default: K=[5 5], NRRUNS = [20 40 40], ETA = [0.5 0.3 0.1], % H = [0.6 0.2 0.01]; % % SEE ALSO (PRTools Guide) % PCAM, PRKMEANS, PRPLOTSOM, PREX_SOM % Copyright: D. Tax, davidt@ph.tn.tudelft.nl % Faculty of Applied Physics, Delft University of Technology % P.O. Box 5046, 2600 GA Delft, The Netherlands if nargin <5 | isempty(h) h = [0.6 0.2 0.01]; end if nargin <4 | isempty(eta) eta = [0.5 0.3 0.1]; end if nargin <3 | isempty(nrruns) nrruns = [20 40 40]; end if nargin < 2| isempty(k), k = [5 5]; end if nargin < 1 | isempty(a) W = prmapping(mfilename,{k,nrruns,eta,h}); W = setname(W,'Self-organising Map'); return end if ~ismapping(k) %training a = testdatasize(a); x = +a; % use all the data! [nrx,dim] = size(x); % Set up the map size: if length(k)<2 % add a dummy dimension k = [k; 1]; end % Some magic parameters: % The training consist of several runs, each differ in the width of % the neighborhood width, the learning rate and the number of SOM % updates: Dmax = distm(x,x); Dmax = max(Dmax(:)); h = h*sqrt(Dmax); % (this should probably be something which can be set by the user) % Initialize the map w = 0.2*rand(k(1)*k(2),dim)+repmat(+mean(x),k(1)*k(2),1); % Run the different types of updates: for r1=1:length(nrruns) % Set up the neighbourhood: W = zeros(k(1),k(2)); for i=1:k(1) for j=1:k(2) W(i,j) = exp(-((i-1)^2+(j-1)^2)/h(r1)); end end % Do the real SOM training: for r2 = 1:nrruns(r1) %fprintf('%d/%d\t',r2,nrruns(r1)); % Go randomly along the objects: I = randperm(nrx); for i=1:nrx % Find the winner: [mD,mI] = min(distm(w,x(I(i),:)),[],1); wx = rem(mI-1,k(1))+1; wy = floor((mI-1)/k(1))+1; % Update all weights: for j=1:k(1)*k(2) jx = rem(j-1,k(1))+1; jy = floor((j-1)/k(1))+1; w(j,:) = w(j,:) + eta(r1)*W(abs(jx-wx)+1,abs(jy-wy)+1)*... (x(I(i),:)-w(j,:)); end end end end clear W; % And save all useful data: V.k = k; %(only used for plotting later...) V.neurons = w; W = prmapping(mfilename,'trained',V,(1:prod(k))',dim,prod(k)); W = setname(W,'Self-organising Map'); else W = getdata(k); %unpack m = size(a,1); % compute the distance to the nearest neuron in the map: %[mD,out] = min(distm(+a,W.w),[],2); D = distm(+a,W.neurons); % only compute the distances % Output a dataset with the negative distances: W = setdat(a,-D,k); end