Writing (and using) principal component analysis in matlab - matlab

I (hope to) obtain a matrix with data on different characteristics on rat calls (in the ultrasound). Variables include starting frequency, ending frequency, duration etc etc. The observations will include all the rat calls in my audio recording.
I want to use PCA to analyze my data, hopefully decorrelating any principal components that are not important to the structure of these calls and how they work, allowing me to group the calls up.
My problem is that while I have a basic understanding of how PCA works, I don't have an understanding of the finer points including how to implement this in Matlab.
I know you should standardise my data. All methods I have seen involve means adjusting by subtracting the mean. However some others also divide by the standard deviation or divide the transpose of the means adjusted data by the square root of N-1 (N being the number of variables).
I know with the standardised data, you can then find the covariance matrix, and extract the eigen values and vectors such as with using eig(cov(...)). some others use svd(...) instead. I still don't understand what this is and why it is important
I know there are different ways to implement PCA, but I don't like how I get different results for all of them.
There is even a pca(...) command also.
While reconstructing the data, some people multiply the means adjust data with the principal component data, others do the same but with the transpose of the principal component data
I just want to be able to analyse my data by plotting graphs of the principal components, and of the data (with the most insignificant principal components removed). I want to know about the variances of these eigen vectors and how much they represent the total variance of the data. I want to be able to fully exploit all the information PCA can allow me to get out
can anyone help?
=========================================================
This code seems to work based on pg 20 of http://people.maths.ox.ac.uk/richardsonm/SignalProcPCA.pdf
X = [105 103 103 66; 245 227 242 267; 685 803 750 586;...
147 160 122 93; 193 235 184 209; 156 175 147 139;...
720 874 566 1033; 253 265 171 143; 488 570 418 355;...
198 203 220 187; 360 365 337 334; 1102 1137 957 674;...
1472 1582 1462 1494; 57 73 53 47; 1374 1256 1572 1506;...
375 475 458 135; 54 64 62 41];
[M,N] = size(X);
mn = mean(X,2);
data = X - repmat(mn,1,N);
Y = data' / sqrt(N-1);
[~,S,PC] = svd(Y);
S = diag(S);
V = S .* S;
signals = PC' * data;
%plotting single PC1 on its own
figure;
plot(signals(1,:),zeros(1,size(signals,2)),'b.','markersize',15)
xlabel('PC1')
title('plotting single PC1 on its own')
%plotting PC1 against PC2
figure;
plot(signals(1,:),signals(2,:),'b.','markersize',15)
xlabel('PC1'),ylabel('PC2')
title('plotting PC1 against PC2')
figure;
plot(PC(:,1),PC(:,2),'m.','markersize',15)
xlabel('effect(PC1)'),ylabel('effect(PC2)')
but where is the standard deviation? how is the result different to
B=zscore(X);
[PC, D] = eig(cov(B));
D = diag(D);
cumsum(flipud(D)) / sum(D)
PC*B %(note how this says PC whereas above it says PC')
If the principal components are represented as columns, then I can remove the most insignificant eigen vectors by finding the smallest eigenvalue and setting its corresponding eigen vector column to a column of zeros.
How can either of these methods above be applied by using the pca(...) command and achieve THE SAME result? can anyone help explain this to me (and ideally show me how all of these can achieve the same results)?

Related

How to split the dataset into train/ validation / test with cvpartion?

I'm training NNs for classification. However, I only have 525 samples and approximately 300 predictor variables. I know I could try to reduce the number of variables, looking for the ones that are really more important, but this is not the point.
Currently I divide my data into training / validation / test, using validation for early stop during network training.
I want to use cross-validation in Matlab with the cvpartition function, however this function divides dataset in training / test. Is there any way to use cvpartition to split into training / validation / test?
c=cvpartition(t_class,'KFold',10,'Stratify', true)
K-fold cross validation partition
NumObservations: 525
NumTestSets: 10
TrainSize: 473 472 472 472 472 472 473 473 473 473
TestSize: 52 53 53 53 53 53 52 52 52 52
Coss-validation is only meant to have two sets, the one it is training on and the other it tests on and in the next iteration again. So cvpartition won't give you a split into three sets. You can now argue that the validation set os only a subset of the test set, so you use cvpartition again on this, making sure that you do not accidentally test on the whole test set (this doesn't work for corss-validation) or if you want to apply cross-validation, do it the other way around:
% 20% for validation
cvp = cvpartition(t_class,'HoldOut',0.2);
% extract the data set
t_class_Val = t_class(cvp.test);
% Dat_Val = Dat(cvp.test,:);
t_class_TrnTst = t_class(cvp.training);
% Dat_TrnTst = Dat(cvp.training,:);
% cross-validation for the rest
cvp2 = cvpartition(t_class_TrnTst,'KFold',10,'Stratify', true);
The other option is to code it yourself. You can randomize indices with randperm.

Create equally spaced data from sensor data to apply Fast Fourier Transform

I have the following sensor sample data:
Time(milliseconds) Data
------------------ -------------------
0 0.30865225195884705
60 0.14355185627937317
100 -0.16846869885921478
156 -0.2458019256591797
198 -0.19664153456687927
258 0.27148059010505676
305 -0.16949564218521118
350 -0.227480947971344
397 0.23532353341579437
458 0.20740140974521637
Which means at time 0 I have the value 0.30865225195884705 and at time 60 I have the value 0.14355185627937317 and so on.
As it is observed, data are not equally spaced which means I have data at different time stamps. I need this because I will apply Fast Fourier Transform to this signals.
Are there any methods or implementations so that I can create equally spaced data from my sensor data? (using MATLAB)

Matlab: Calculate vector lengths between different points on a rectangle

I am interested in creating a Matlab script that will consider a rectangle and allow me to calculate the length of vectors between one point and several other points placed along the perimeter of the rectangle. For example, calculating the length of all the vectors indicated in red on the image below, using point 9 as the origin.
This will need to include the ability to specify the location of each point and should be adaptable to rectangles with different dimensions. I would like to be able to calculate the vector lengths using any of the specified points as the origin. For example from point 1 to all other points on the perimeter.
I realize this is a potentially time consuming task so any help would be greatly appreciated, as I am a novice with Matlab. Look forward to seeing some ideas! Cheers.
Building on top of #ihcgeneva's post, I would avoid using loops all together and use bsxfun instead. The code by #ihcgeneva can be greatly simplified to:
xList = [1, 2, 3, 4, 5];
yList = [5, 4, 2, 2, 1];
rootPoint = 3; %The point you want as your 'base'
Distance = sqrt(sum(bsxfun(#minus, [xList; yList].', [xList(rootPoint) yList(rootPoint)]).^2, 2));
Note that there is no need to define the anonymous function d. In addition, there is also no need for a loop. With MATLAB, you are always encouraged to vectorize your code. What vectorization means is that there are certain functions in MATLAB that will accept an array or matrix of inputs and the function will operate on each entry individually. The output of these functions will give you an array or matrix of the same size that has each of those values having the function applied to those elements. It has been shown to be much faster over looping through each element in your array or matrix and applying the function to each element one at a time. It's mostly due to function call overhead. It would be more efficient to just call the function once rather than many times for as many elements as you want to apply the function to.
Now, the above code is quite a handful to absorb, but still pretty easy to understand once you get the hang of it. bsxfun stands for Binary Singleton Expansion Function. If we look inside the function, we are invoking the minus function between a single point in your rectangle found at the index rootPoint with all of the other co-ordinates in the rectangle. What we will do is place the co-ordinates into a 2D matrix where the first column denotes the x co-ordinate and the second column denotes the y co-ordinate. Next, what bsxfun is doing is that it duplicates the point located at rootPoint so that it is the same size as this 2D matrix. bsxfun will then do an element by element subtraction between this duplicated matrix with the original 2D matrix that you created.
This will perform the first part of the Euclidean distance where you subtract the corresponding dimensions. This creates an output 2D matrix where the first column is the subtraction of the x components and the second column is the subtraction of the y components. We then square each value in the matrix, then sum over the columns then take the square root, thus completing the Euclidean distance operation. #lhcgeneva has put you on the right track where the shortest distance between the point you are looking at with the other points in the rectangle is the Euclidean distance.
Now if you want to plot the lines from one point to another like you have in your image, you actually don't need to calculate the lengths at all. You just need to know where the points along the rectangle are located, show the image, then use plot and plot lines from each point in the rectangle to the source point. This looks very much like an IC Pin layout diagram, so I'm going to use one that I found on the Internet:
Let's use pin #3 as the source. I've also gone through the image and pin-pointed the location of the middle of each pin:
points = [49 84; 49 133; 49 178; 49 229; 49 277; 49 325; 49 372; 205 374; 205 325; 205 276; 205 228; 205 181; 205 131; 205 87];
The first column is the x or column co-ordinate while the second column is the y or row co-ordinate of where the centre is for each pin in this image. Now, all you have to do is show this image, use hold on to make sure that you can place multiple lines on the plot without it erasing, and plot lines from the source point to each point in the matrix:
im = imread('http://www.infraredremote.com/images/14-pin-IC.jpg');
imshow(im);
hold on;
points = [49 84; 49 133; 49 178; 49 229; 49 277; 49 325; 49 372; 205 374; 205 325; 205 276; 205 228; 205 181; 205 131; 205 87];
rootPoint = 3;
for idx = 1 : size(points, 1)
plot([points(rootPoint, 1) points(idx, 1)], [points(rootPoint, 2) points(idx, 2)], 'r', 'LineWidth', 5);
end
The above code loads in the image directly from the Internet. We then show the image with imshow then use hold on like we talked about before. Next, we choose our root point, which is pin 3, then we loop over all of the points and draw a line from the root point to each pin. We make the line red, as well as making the width of the line 5 pixels thick. In this case, we do need to loop over the points to make it easy. We can vectorize the plotting, but it will become a bit sophisticated given your knowledge of MATLAB so far.
In any case, this is what I get:
Edit
In your comments, you said you wanted to display the distances from the root point to each point in your rectangle. You can do this with a loop. Unfortunately when it comes to printing, there isn't a way to do it easily with vectorization, but looping just to print out statements should take very little time so we shouldn't worry about vectorization here.
As such, you can do something like this:
%// Define points along rectangle and root point
points = [49 84; 49 133; 49 178; 49 229; 49 277; 49 325; 49 372; 205 374; 205 325; 205 276; 205 228; 205 181; 205 131; 205 87];
rootPoint = 3;
%// Find distances
Distance = sqrt(sum(bsxfun(#minus, points, points(rootPoint,:)).^2, 2));
for idx = 1 : numel(Distance)
fprintf('Distance between reference point %d and point %d is %f\n', ...
rootPoint, idx, Distance(idx));
end
Note that I had to modify the code slightly with respect to the distances. Because our points are now in a 2D array, the core algorithm is still the same, but I had to get the points in a slightly different way. Specifically, I didn't need to construct the 2D matrix inside bsxfun as that was created already. I can also easily extract out the root point by getting all of the columns for a single row located at the row indexed by rootPoint. Next, we loop over each distance from the root point to each point in the rectangle and we simply print those out. This is the output I get:
Distance between reference point 3 and point 1 is 94.000000
Distance between reference point 3 and point 2 is 45.000000
Distance between reference point 3 and point 3 is 0.000000
Distance between reference point 3 and point 4 is 51.000000
Distance between reference point 3 and point 5 is 99.000000
Distance between reference point 3 and point 6 is 147.000000
Distance between reference point 3 and point 7 is 194.000000
Distance between reference point 3 and point 8 is 250.503493
Distance between reference point 3 and point 9 is 214.347848
Distance between reference point 3 and point 10 is 184.228119
Distance between reference point 3 and point 11 is 163.816971
Distance between reference point 3 and point 12 is 156.028843
Distance between reference point 3 and point 13 is 162.926364
Distance between reference point 3 and point 14 is 180.601772
This looks about right, and certainly makes sense as the distance between point 3 and itself (3rd row of the print-out) is 0.

Evaluate a 3D spline in Matlab

I'm struggling to find a solution to this problem since the last week and still got no result.
I have a 3d spline in matlab, necessarily defined (I can't change the representation) with the spap2 command, and I need to evaluate the spline itself given two coordinates (say x and y). I tried to use the fnval command with different sintaxes but with no success.
Example: I'd like to get the z at x=26, y=120 with the spline defined with
x=[13 56 90 67 89 43];
y=[112 156 136 144 144 128];
z=[63 95 48 78 77 15];
sp = spap2(4,4,1:length(x),[x; y; z]);
Could anyone help me?
Thank you very much!
A spline is an approximation. It does not need to go through the coordinates (x=26,y=120) at all. There is no immediate definition of what z value would be reasonable for these (x, y) values.
Your x values (independent values) are 1:length(x) and the output (dependent values) is [x;y;z].
For example fnval(sp, 1.5) gives a reasonable output.

Need to generate a cluster of points in k-dimensional space in MATLAB

The points generated should be something like this-
21 32 34 54 76 34
23 55 67 45 75 23.322
54 23 45 76 85.1 32
the above example is when k=6.
How can I generate such a cluster of say around 1000 points and vary the value of k and the radius of the cluster.
Is there any built-in function that can do this for me? I can use any other tool if needed.
Any help would be appreciated.
Have a look at ELKI. It comes with a quite flexible data generator for clustering datasets, and there is a 640d subspace clustering example somewhere on the wiki.
Consider using d for the dimensionality, as when you are talking about clusters k usually refers to the number of clusters (think of k-means ...)
I think you would need to write your own code for this. Supposing your center is at the origin, you have to pick k numbers, in sequence, with the constraint at every step that the sum of the squares of all the numbers upto (and including) it must not exceed the radius of the hypersphere squared. That is, the k th number squared must be less than or equal to the radius squared minus the sum of the squares of all previously picked numbers.
If you have the stats toolbox this is easy
http://www.mathworks.co.uk/help/toolbox/stats/kmeans.html
Otherwise, you can quite easily write the code yourself using Lloyds algorithm.