Draw divisory MLP line together with chart in MATLAB - matlab

I need to plot the divisory line together with the graph below:
The code I used to train the MLP neural network is here:
circles = [1 1; 2 1; 2 2; 2 3; 2 4; 3 2; 3 3; 4 1; 4 2; 4 3];
crosses = [1 2; 1 3; 1 4; 2 5; 3 4; 3 5; 4 4; 5 1; 5 2; 5 3];
net = feedforwardnet(3);
net = train(net, circles, crosses);
plot(circles(:, 1), circles(:, 2), 'ro');
hold on
plot(crosses(:, 1), crosses(:, 2), 'b+');
hold off;
But I'd like to show the line separating the groups in the chart too. How do I proceed? Thanks in advance.

First off, you're not training your neural network properly. You'd have to use both circles and crosses as input samples into your neural network and the output will have to be a two neuron output where [1 0] as the output would denote that the circles class is what the classification should be and [0 1] is what the crosses classification would be.
In addition, each column is an input sample while each row is a feature. Therefore, you have to transpose both of these and make a larger input matrix. You'll also need to make your output labels in accordance with what we just talked about:
X = [circles.' crosses.'];
Y = [[ones(1, size(circles,1)); zeros(1, size(circles,1))] ...
[zeros(1, size(crosses,1)); ones(1, size(crosses,1))]];
Now train your network:
net = feedforwardnet(3);
net = train(net, X, Y);
Now, if you want to figure out which class each point belongs to, you simply take the largest neuron output and whichever one gave you the largest, that's the class it belongs to.
Now, to answer your actual question, there's no direct way to show the "lines" of separation with Neural Networks if you use the MATLAB toolbox. However, you can show regions of separation and maybe throw in some transparency so that you can overlay this on top of the figure.
To do this, define a 2D grid of coordinates that span your two classes but with a finer grain... say... 0.01. Run this through the neural network, see what the maximum output neuron is, then mark this accordingly on your figure.
Something like this comes to mind:
%// Generate test data
[ptX,ptY] = meshgrid(1:0.01:5, 1:0.01:5);
Xtest = [ptX(:).'; ptY(:).'];
%// See what the output labels are
out = sim(net, Xtest);
[~,classes] = max(out,[],1);
%// Now plot the regions
figure;
hold on;
%// Plot the first class region
plot(Xtest(1, classes == 1), Xtest(2, classes == 1), 'y.');
%// Add transparency
alpha(0.1);
%// Plot the second class region
plot(Xtest(1, classes == 2), Xtest(2, classes == 2), 'g.');
%// Add transparency
alpha(0.1);
%// Now add the points
plot(circles(:, 1), circles(:, 2), 'ro');
plot(crosses(:, 1), crosses(:, 2), 'b+');
The first two lines of code generate a bunch of test (x,y) points and ensures that they're in a 2 row input matrix as that is what the network inputs require. I use meshgrid for generating these points. Next, we use sim to simulate or put in inputs into the neural network. Once we do this, we will have two output neuron neural network responses per input point where we take a look at which output neuron gave us the largest response. If the first output gave us the largest response, we consider the input as belonging to the first class. If not, then it's the second class. This is facilitated by using max and looking at each column independently - one column per input sample and seeing which location gave us the maximum.
Once we do this, we create a new figure and plot the points that belonged to class 1, which is the circles, in yellow and the second class, which is the crosses, in green. I throw in some transparency to make sure we can see the regions with the points. After, I plot the points as normal using your code.
With the above code, I get this figure:
As you can see, your model has some classification inaccuracies. Specifically, there are three crosses that would be misclassified as circles. You'll have to play around with number of neurons in the hidden layer as well as perhaps using a different activation function but this certainly is enough to get you started.
Good luck!

Related

How to create a multi-layer perceptron in Matlab for a multi-class dataset

I want to create a double layered perceptron for an assignment.
It will act as a classifier for the Fisher iris data set.
I've come across the following problems while creating the network:
For a dataset like the above, can i setup the network with a single
input and pass the whole training matrix of n rows and 4 features as
an input value? Or, do i need to adjust the network to use 4 input
node, 1 for each feature, and pass the training matrix as an input
value?
Furthermore, how do I properly connect the layers with each other?
For instance, when i create a perceptron with 4 inputs using the
network command, I don't really understand what do the biasConnect, inputConnect and layerConnect actually do.
Lastly, how many outputs do i need to correctly classify one element?
Every example I've come across uses one output, but, will just one
suffice? Or, do I need one for each class?
Command used for creating the network mentioned at the second point:
net = network(4, 2, [1; 0], [1 1 1 1;0 0 0 0], [0 0; 1 0], [0 1]);
Let's start with network connections. The way the network function works is not intuitevely clear. In order to control if your input vectors describe the structure correctly, you can use view(net) :
Now let's discuss each parameter shortly:
numInputs - if your network will get only one input data set, you need to put 1 here.
numLayers - for the iris data set it's ok to use 2 here.
biasConnect - bias units are used to "increase" non-linearity between inputs and outputs. We want the network to be able to approximate complex non-linear functions, that is why it's a good idea to add bias units to both layers. So put here [1, 1].
inputConnect - the vector has dimensions numLayers-by-numInputs. It shows which inputs are connected to which layers. You have only one input connected to the first layer, so put [1;0] here.
layerConnect - the vector has dimensions numLayers-by-numLayers. You have two layers. The first layer is connected to the second one, but not to itself. There is no connection going from the second layer to the first one, and the second layer does not feed itself. Put [0 0; 1 0] here.
outputConnect - the vector has dimensions 1-by-numLayers and shows which layer is connected to the output. Put [0 1] here.
Here is our command and the corresponding graph:
net = network(1, 2, [1; 1], [1;0], [0 0; 1 0], [0 1]);
You can experiment with the parameters and the resulting structures can be very complex.
Network configuration
Now you need to configure the network. You can find all the parameters in the documentation, I will discribe here the most important:
It's important to set correct activation functions for the layers. By default the function is set to purelin. You may want to use here something like tansig or logsig.
You need to set the size of each layer. In your case I would use 5 or 7 units in the first layer. The size of the second layer should be equal to the number of output classes: 3 in your case.
The initialization functions for the weights and bias units should be set for each layer as well.
The resulting network looks like here:
Here is the code:
net = network(1, 2, [1; 1], [1;0], [0 0; 1 0], [0 1]);
net.adaptFcn = 'adaptwb';
net.divideFcn = 'dividerand'; %Set the divide function to dividerand (divide training data randomly).
net.performFcn = 'mse';
net.trainFcn = 'trainlm'; % set training function to trainlm (Levenberg-Marquardt backpropagation)
net.plotFcns = {'plotperform', 'plottrainstate', 'ploterrhist', 'plotconfusion', 'plotroc'};
%set Layer1
net.layers{1}.name = 'Layer 1';
net.layers{1}.dimensions = 7;
net.layers{1}.initFcn = 'initnw';
net.layers{1}.transferFcn = 'tansig';
%set Layer2
net.layers{2}.name = 'Layer 2';
net.layers{2}.dimensions = 3;
net.layers{2}.initFcn = 'initnw';
net.layers{2}.transferFcn = 'tansig';
[x,t] = iris_dataset; %load of the iris data set
net = train(net,x, t); %training
y = net(x); %prediction
view(net);
The confusion matrices look pretty good. So the network works well!
A little bit shoter way
If you want to use an already preinstalled network, you can use this code:
[x,t] = iris_dataset;
net = patternnet;
net = configure(net,x,t);
net = train(net,x,t); %training
view(net);
y = net(x); %predict

GMModel - how do I use this to predict a label's data?

I've made a GMModel using fitgmdist. The idea is to produce two gaussian distributions on the data and use that to predict their labels. How can I determine if a future data point fits into one of those distributions? Am I misunderstanding the purpose of a GMModel?
clear;
load C:\Users\Daniel\Downloads\data1 data;
% Mixed Gaussian
GMModel = fitgmdist(data(:, 1:4),2)
Produces
GMModel =
Gaussian mixture distribution with 2 components in 4 dimensions
Component 1:
Mixing proportion: 0.509709
Mean: 2.3254 -2.5373 3.9288 0.4863
Component 2:
Mixing proportion: 0.490291
Mean: 2.5161 -2.6390 0.8930 0.4833
Edit:
clear;
load C:\Users\Daniel\Downloads\data1 data;
% Mixed Gaussian
GMModel = fitgmdist(data(:, 1:4),2);
P = posterior(GMModel, data(:, 1:4));
X = round(P)
blah = X(:, 1)
dah = data(:, 5)
Y = max(mean(blah == dah), mean(~blah == dah))
I don't understand why you round the posterior values. Here is what I would do after fitting a mixture model.
P = posterior(GMModel, data(:, 1:4));
[~,Y] = max(P,[],2);
Now Y contains the labels that is index of which Gaussian the data belongs in-terms of maximum aposterior (MAP). Important thing to do is to align the labels before evaluating the classification error. Since renumbering might happen, i.e., Gaussian component 1 in the true might be component 2 in the clustering produced and so on. May be that why you are getting varying accuracy ranging from 51% accuracy to 95% accuracy, in addition to other subtle problems.

MATLAB's newrb for designing radial basis networks does not behave in accordance to the documentation. Why?

I'm trying to approximate various signals using radial basis networks. In particular, I make use of MATLAB's newrb.
My problem is that this function seems to behave incorrectly if I follow the description of newrb. As I understand it, it makes sense to transpose all arguments despite the documentation.
The following example hopefully illustrates my problem.
I create one period of a sine wave with 100 samples. I would like to approximate this sine wave by means of a radial basis network with maximally two hidden neurons. I have one input vector (t) and one target vector (s). Hence, according to the documentation, I should call newrb with two column vectors. However, the approximation is too good. In fact, the mean squared error is 0 which can't be true using only two neurons. Additionally, the visualization with view(net) shows not only one but 100 inputs if I use column vectors.
In the example, the vectors corresponding to the "correct" (according to the documentation) function call are indicated by _doc, the ones corresponding to the "incorrect" call by _not_doc.
Can anybody explain this behavior?
% one period sine signal with
% carrier frequency = 1, sampling frequency = 100
Ts = 1 / 100;
t = 2 * pi * (0:Ts:1-Ts); % size(t) = 1 100
s = sin(t); % size(s) = 1 100
% design radial basis network
MSE_goal = 0.0; % mean squared error goal, default value
spread = 1.0; % spread of readial basis functions, default value
max_neurons = 2; % maximum number of neurons, custom value
DF = 25; % number of neurons to add between displays, default value
net_not_doc = newrb( t , s , MSE_goal, spread, max_neurons, DF ); % row vectors
net_doc = newrb( t', s', MSE_goal, spread, max_neurons, DF ); % column vectors
% simulate network
approx_not_doc = sim( net_not_doc, t );
approx_doc = sim( net_doc, t' );
% plot
figure;
plot( t, s, 'DisplayName', 'Sine' );
hold on;
plot( t, approx_not_doc, 'r:', 'DisplayName', 'Approximation_{not doc}');
hold on;
plot( t, approx_doc', 'g:', 'DisplayName', 'Approximation_{doc}');
grid on;
legend show;
% view neural networks
view(net_not_doc);
view(net_doc);
Because I had the same problem myself, I'll try to give an answer for anyone who will stumble upon the same post.
As I figured the problem is not the transpose vectors. You can use your data as it is, without transposing anything.
The fact that you train your RBF network with vector t and then simulate with the same vector that you trained your network, is the reason why you have so perfect approximation. You test your network with the same values that you taught it.
If you realy want to test your network you must choose a different vector for testing. In your example I used this:
% simulate network
t_test = 2 * pi * ((1-Ts)/2:Ts:3-Ts);
approx_not_doc = sim( net_not_doc, t_test );
And now when you plot your results, you can observe that the points that have the same value as in your train vector are almost flawless. The rest have an unknown target because of the small number of neurons (as you expected).
Plot of t_test with approx_not_doc.
Now If you add more neurons (in this example I used 100), you can see that now the new network can predict, with the same test vector t_test, an unknown part of your function. Plot t_test with approx_not_doc for 100 neurons. Of course, if you try with different number of neurons and spread your results will vary.
Hope this will help anyone with the same problem.

How do I visualize n-dimensional features?

I have two matrices A and B. The size of A is 200*1000 double (here: 1000 represents 1000 different features). Matrix A belongs to group 1, where I use ones(200,1) as the label vector. The size of B is also 200*1000 double (here: 1000 also represents 1000 different features). Matrix B belongs to group 2, where I use -1*ones(200,1) as the label vector.
My question is how do I visualize matrices A and B so that I can clearly distinguish them based on the given groups?
I'm assuming each sample in your matrices A and B is determined by a row in either matrix. If I understand you correctly, you want to draw a series of 1000-dimensional vectors, which is impossible. We can't physically visualize anything beyond three dimensions.
As such, what I suggest you do is perform a dimensionality reduction to reduce your data so that each input is reduced to either 2 or 3 dimensions. Once you reduce your data, you can plot them normally and assign a different marker to each point, depending on what group they belonged to.
If you want to achieve this in MATLAB, use Principal Components Analysis, specifically the pca function in MATLAB, that calculates the residuals and the reprojected samples if you were to reproject them onto a lower dimensionality. I'm assuming you have the Statistics Toolbox... if you don't, then sorry this won't work.
Specifically, given your matrices A and B, you would do this:
[coeffA, scoreA] = pca(A);
[coeffB, scoreB] = pca(B);
numDimensions = 2;
scoreAred = scoreA(:,1:numDimensions);
scoreBred = scoreB(:,1:numDimensions);
The second output of pca gives you reprojected values and so you simply have to determine how many dimensions you want by extracting the first N columns, where N is the desired number of dimensions you want.
I chose 2 for now, and we can see what it looks like in 3 dimensions after. Once we have what we need for 2 dimensions, it's just a matter of plotting:
plot(scoreAred(:,1), scoreAred(:,2), 'rx', scoreBred(:,1), scoreBred(:,2), 'bo');
This will produce a plot where the samples from matrix A are with red crosses while the samples from matrix B are with blue circles.
Here's a sample run given completely random data:
rng(123); %// Set seed for reproducibility
A = rand(200,1000); B = rand(200,1000); %// Generate random data
%// Code as before
[coeffA, scoreA] = pca(A);
[coeffB, scoreB] = pca(B);
numDimensions = 2;
scoreAred = scoreA(:,1:numDimensions);
scoreBred = scoreB(:,1:numDimensions);
%// Plot the data
plot(scoreAred(:,1), scoreAred(:,2), 'rx', scoreBred(:,1), scoreBred(:,2), 'bo');
We get this:
If you want three dimensions, simply change numDimensions = 3, then change the plot code to use plot3:
plot3(scoreAred(:,1), scoreAred(:,2), scoreAred(:,3), 'rx', scoreBred(:,1), scoreBred(:,2), scoreBred(:,3), 'bo');
grid;
With those changes, this is what we get:

Smoothing out of rough plots

I want to draw some plots in Matlab.
Details: For class 1, p(x|c1) is uniform for x between [2, 4] with the parameters a = 1 and b = 4. For class 2, p(x|c2) is exponential with parameter lambda = 1. Besides p(c1) = p(c2) = 0.5 I would like to draw a sketch of the two class densities multiplied by P(c1) and P(c2) respectively, as
a function of x, clearly showing the optimal decision boundary (or boundaries).
I have the solution for this problem, this is what the writer did (and I want to get), but there's no Matlab code, so I want to do it all by myself.
And this is what I drew.
And this is the MATLAB code I wrote.
x=0:1:8;
pc1 = 0.5;
px_given_c1 = exppdf(x,1);
px_given_c2 = unifpdf(x,2,4);
figure;
plot(x,px_given_c1,'g','linewidth',3);
hold on;
plot(x,px_given_c2,'r','linewidth',3);
axis([0 8 0 0.5]);
legend('P(x|c_1)','P(x|c_2)');
figure;
plot(x,px_given_c1.*pc1,'g','linewidth',3);
hold on;
plot(x,px_given_c2.*(1-pc1),'r','linewidth',3);
axis([0 8 0 0.5]);
legend('P(x|c_1)P(c_1)','P(x|c_2)P(c_2)');
As you can see, they are almost smiliar, but I am having problem with this uniform distribution, which is drawn in red. How can I change it?
You should probably change x=0:1:8; to something like x=0:1e-3:8; or even x=linspace(0,8,1000); to have finer plotting. This increases number of points in vectors (and therefore line segments) Matlab will use to plot.
Explanation: Matlab works with line segments when it does plotting!
By writing x=0:1:8; you create vector [0 1 2 3 4 5 6 7 8] that is of length 9, and by applying exppdf and unifpdf respectively you create two vectors of the same length derived from original vector. So basically you get vectors [exppdf(0) exppdf(1) ... exppdf(8)] and [unifpdf(0) unifpdf(1) ... unifpdf(8)].
When you issue plot command afterwards Matlab plots only line segments (8 of them in this case because there are 9 points):
from (x(1), px_given_c1(1)) to (x(2), px_given_c1(2)),
...
from (x(8), px_given_c1(8)) to (x(9), px_given_c1(9)).