Put elements of a 1D vector into a 3D matrix using another matrix of positions - matlab

I have a vector of data points which were saved from a 3D array by some other program in one big list. The vector is nk elements long. nk = nx*ny*nz where nx, ny and nz are the dimensions of the original 3D array.
The position of a data point in the original array is stored in a (nk x 3) array, arranged with each row (position(k,:)) giving the (i,j,k) position of the corresponding data point.
I can't use reshape on my data array as the position vector is not simple (it depends on some stuff to do with how the data was generated - it isn't completely random - but I won't necessarily know what it looks like beforehand).
If the nk vector is called 'data', the nk x 3 position array is called 'position' and the output array is called 'data_reshaped' then currently I am doing the following:
for k = 1:nk
data_reshaped(position(k,1),position(k,2),position(k,3)) = data(k);
end
This is really slow - is there some faster method without knowing much about what 'position' looks like?

You could use sub2ind function:
data_reshaped = zeros(nx, ny, nz);
data_reshaped( sub2ind([nx ny nz], position(:,1), ...
position(:,2), ...
position(:,3)) ) = data;

Related

Creating Multi Dimesnional Array from 1D array in Matlab?

Hello I am trying to create a simple array that contains a '10' 3x3 matrices. So I tried to create a 1D matrix that has 1 x 10 values. Then I tried assigning a 3x3 matrix in to each of the 10 slots in the 1D matrix. I am quite sure my syntax is wrong and matlab (I don't think allows this) but I couldn't find too much info to pre assign such array and I just started learning about matlab. Here is my attempt:
big_array = zeros(1,10) # creates 1x10 1d array
for i = 1:10
big_array(i) = zeros(3,3); #supposedly? assign 3x3 matrix in to each of the 10 slots
end
big_array # received an error
If you know that you want an array of 10 3x3 matrices, you would typically want to use a multidimensional array from the start.
big_array = zeros(10,3,3);
You can access the i'th matrix using big_array(i,:,:).
If you really do want a one-dimensional array of 3x3 matrices, you need to use a cell array.
big_array = {};
for i = 1:10
big_array{i} = zeros(3,3);
end
big_array
You can now access the i'th matrix using big_array{i}.
A small clarification - If all your slots must contain submatrices with the same size, then you can use very simple expression:
big_array = zeros(3,3,10) % (first dimension - rows, second dimension - columns, third dimension - bands or arrays)

Convert an Array from Spherical to Cartesian Coordinates in MATLAB

I am working in MATLAB with a formula which indexes points on a unit sphere in spherical coordinates.
[i, j] = ndgrid(1:N_theta, 1:N_phi);
theta = (i-1)*2*pi/N_theta;
phi = (j)*pi/(N_phi+1);
r = 1;
b = [theta(:).'; phi(:).'; r * ones(1,numel(theta))];
Let's assume I choose particular values for N_theta and N_phi and that each point has a position vector in spherical coordinates, where the first component is theta, the second component is phi and the third component is r. Running the formula then creates an array (I've called it b) which takes the position vector for each of the N points and slots them all next to each other to make a 3xN matrix.
I essentially just need to take that array and convert it so it's the same array with the vectors all next to each other but now the position vectors are in Cartesian coordinates (we could call the new array B).
I have looked up the sph2cart function in MATLAB which is designed for that purpose but I'm not sure if I am using it correctly and am hoping someone could point it what I am doing wrong. I have tried this, for example
B=sph2cart(b(1,:),b(2,:),b(3,:));
and
B = sph2cart(theta,phi,r);
but they both create matrices which are too small, so something is obviously going wrong.

Subtract vector from 3d array

Say if I have a 3d array:
lat = 45:49;
lon = -116:-110;
b = rand(5,7,12);
where the first dimension represents the latitude, the second dimension represents the longitude and the third row represents the data. I aim to plot this 3d data on a map using the mapping toolbox. But, before doing this, I would like to find the difference between the data in 'b' and the following vector:
vals = [2.3,5,6.8,5.4,3.3,12,1.5,4.6,9.8,82,3.3,1];
Specifically, for each spatial data point that I have in my mapped data I owuld like to calculate the mean absolute error between that vector and the data at each point in b. If these were two normal vectors I would use:
mae = mean(abs(bv - vals))
but I'm not sure how this can be done with the 3d array. Eventually, I aim to map this mean absolute error to see how it varies spatially. Can anyone suggest how this can be done in matlab?
Use bsxfun for this (it's more efficient than repmat):
V = permute(vals, [1,3,2]) %// Make sure that the dimesions 'align' correctly. i.e. 12 elements must go in the thrid dimension to match b
mae = mean(abs(bsxfun(#minus, b, V)),3)
As MATLAB does not support broadcasting, you need to create a matrix the same size as b with the repeated values of vals. To be able to do that, first you need to change vals to a shape of 1x1x12 and then repeat it 5x7 times. You can do that with
values=repmat(permute(vals,[1 3 2]),[5 7 1]);
now you can
mae = mean(abs(bv - values))

Dimensionality reduction in Matlab

I want to reduce the dimension of data to ndim dimensions in MATLAB. I am using pcares to reduce dimension but the result (i.e. residuals,reconstructed) has the same dimensions as the data and not ndim. How can I project the residuals to ndim dimensions only.
[residuals,reconstructed] = pcares(X,ndim)
Sample code
MU = [0 0];
SIGMA = [4/3 2/3; 2/3 4/3];
X = mvnrnd(MU,SIGMA,1000);
[residuals,reconstructed] = pcares(X,1)
Now I expect the residuals to have 1 dimensions i.e. the data X projected to prime component as I specified it as pcares(X,1). But here both residuals and reconstructed have the same of 2.
pcares is doing its job. If you read the documentation, you call the function this way:
[RESIDUALS,RECONSTRUCTED] = pcares(X,NDIM);
RESIDUALS returns the residuals for each data point by retaining the first NDIM dimensions of your data and RECONSTRUCTED is the reconstructed data using the first NDIM principal components.
If you want the actual projection vectors, you need to use pca instead. You'd call it this way:
[coeff,score] = pca(x);
In fact, this is what pcares does under the hood but it also reconstructs the data for you using the above outputs. coeff returns the principal coefficients for your data while score returns the actual projection vectors themselves. score is such that each column is a single projection vector. It should be noted that these are ordered with respect to dominance as you'd expect with PCA... and so the first column is the most dominant direction, second column second dominant direction, etc.
Once you call the above, you simply index into coeff and score to retain whatever components you want. In your case, you just want the first component, and so do this:
c = coeff(1);
s = score(:,1);
If you want to reconstruct the data given your projection vectors, referring to the second last line of code, it's simply:
[coeff,score] = pca(x);
n = size(X,1);
ndim = 1; %// For your case
reconstructed = repmat(mean(X,1),n,1) + score(:,1:ndim)*coeff(:,1:ndim)';
The above is basically what pcares does under the hood.

How to create matrix of nearest neighbours from dataset using matrix of indices - matlab

I have an Nx2 matrix of data points where each row is a data point. I also have an NxK matrix of indices of the K nearest neighbours from the knnsearch function. I am trying to create a matrix that contains in each row the data point followed by the K neighbouring data points, i.e. for K = 2 we would have something like [data1, neighbour1, neighbour2] for each row.
I have been messing round with loops and attempting to index with matrices but to no avail, the fact that each datapoint is 1x2 is confusing me.
My ultimate aim is to calculate gradients to train an RBF network in a similar manner to:
D = (x_dist - y_dist)./(y_dist+(y_dist==0));
temp = y';
neg_gradient = -2.*sum(kron(D, ones(1,2)) .* ...
(repmat(y, 1, ndata) - repmat((temp(:))', ndata, 1)), 1);
neg_gradient = (reshape(neg_gradient, net.nout, ndata))';
You could use something along those lines:
K = 2;
nearest = knnsearch(data, data, 'K', K+1);%// Gets point itself and K nearest ones
mat = reshape(data(nearest.',:).',[],N).'; %// Extracts the coordinates
We generate data(nearest.',:) to get a 3*N-by-2 matrix, where every 3 consecutive rows are the points that correspond to each other. We transpose this to get the xy-coordinates into the same column. (MATLAB is column major, i.e. values in a column are stored consecutively). Then we reshape the data, so every column contains the xy-coordinates of the rows of nearest. So we only need to transpose once more in the end.