How to use several loops to make calculations in a matrix? - matlab

I have a 9 x 682 matrix (A). Every 36 columns correspond to a new variable (17 variable in total). For each variable (36 columns), I want to calculate the mean of every 6th column (i.e. mean of columns 1, 7, 13, 19, 31 and so on for each block of 36 columns.
I am stuck with the use of several For loops.
A_averaged = zeros(9,102);
for i = 1:36:length(A)
for j = i:i+35
for k = j:6:j+1
A_averaged(:,k) = mean(A(:,k), 2);
end
end
end
Any help is much appreciated.

To vectorize this, I would reshape your data in a smart way, select the columns you want, and then compute the mean.
% Reshape data to 3D with dimensions: 9 x 36 x (nGroups)
B = reshape(A, size(A, 1), 36, []);
% Now grab the columns of each chunk you want
C = B(:, 1:6:end, :);
% Now compute the mean along the first dimension and squeeze the result
result = squeeze(mean(C, 1));
You can do this in one line with the following:
result = squeeze(mean(reshape(A(:, 1:6:end), size(A, 1), 6, []), 1))
If you instead want the mean of all rows and columns, you can reshape your data into 45 x nGroups and compute the mean along the first dimension
result = mean(reshape(C, [], size(C, 3)), 1);
As a side note, your initial dimensions of 9 x 682 are not actually divisible by 36 columns. Did you mean 9 x 612?

Related

Average matrices in a cell array within a structure Matlab

In Matlab I have a structure AVG of size 1 x 6 which has one field averageNEST that is a cell array also of size 1 x 6.
Each averageNEST contains matrices of varying sizes (in one dimension), so for example
AVG(1).averageNEST{1,1} is of size 281 x 3 x 19 and
AVG(1).averageNEST{1,2} is of size 231 x 3 x 19
The 2nd and 3rd dimensions of the matrices are always 3 and 19, it is only the first dimension that can change.
I want to average over all the matrices contained within AVG(1).averageNEST and obtain one matrix of size X x 3 x 19 where X is the size of the smallest matrix in AVG(1).averageNEST.
Then I want to do this for all 6 averageNEST in AVG - so have a separate averaged matrix for AVG(1), AVG(2) ... AVG(6).
I have tried multiple things including trying to concatenate matrices using the following code:
for i=1:6
min_epoch = epoch + 1;
for ii=1:19
averageNEST(:,:,ii) = [AVG(i).averageNEST(1:min_epoch,:,ii)];
end
end
and then average this but it doesn't work and now I'm really confused about what I'm doing!
Can anyone help?
I am not sure if I understand what you want to do. If you want to keep only the elements up to the size of the the smallest matrix and then average those matrices you can do the following:
averageNEST = cell(size(AVG));
for iAVG = 1:numel(AVG)
nests = AVG(iAVG).averageNEST;
minsize = min(cellfun(#(x) size(x,1), nests));
reducednests = cellfun(#(y) y(1:minsize, :, :), nests, 'UniformOutput', false);
averageNEST{iAVG} = sum(cat(4, reducednests{:}), 4) / numel(nests);
end

Very Basic Matlab Plot

So, I want to plot some points like this (sorry for my pathetic drawing):
So, simply I have some points for the corresponding numbers in x, and I want to plot them based on their values on Y-axis.
I also need to connect the mean of each column (the Y indices) with a straight line, like viz.
Edit: This means say the column with X index 5 has average of 5.6, 10 has 4.5 etc. I want a curve to connect average values of each column. The blue line is connecting the averages of each column.
I wrote a code that fails with the following error:
Error using scatter (line 62)
X and Y must be vectors of the same length.
Here is the code:
x = [5,10,15,20];
scatter(4, data_tab.Bitsi);
hold on
scatter(8, data_tab.Bitsa);
scatter(12, data_tab.Bitsb);
scatter(16, data_tab.Bitsc);
scatter(20, data_tab.Bitsd);
Each of the columns for 5, 10 ... has 4 values as well.
How do I do it?
Thanks.
This is not an elegant solution but it plots what you want
a = rand(1,4);
mean_a = mean(a);
b = rand(1,4);
mean_b = mean(b);
c = rand(1,4);
mean_c = mean(c);
d = rand(1,4);
mean_d = mean(d);
e = rand(1,4);
mean_e = mean(e);
means_array = [mean_a mean_b mean_c mean_d mean_e];
x = [5,10,15,20];
scatter([4 4 4 4], a);
hold on
scatter([8 8 8 8], b);
scatter([12 12 12 12], c);
scatter([16 16 16 16], d);
scatter([20 20 20 20], e);
plot([4 8 12 16 20], means_array);
The problem with your code was that you weren´t supplying the same number of elements in the x and y vectors of the scatter function

Shifting repeating rows to a new column in a matrix

I am working with a n x 1 matrix, A, that has repeating values inside it:
A = [0;1;2;3;4; 0;1;2;3;4; 0;1;2;3;4; 0;1;2;3;4]
which correspond to an n x 1 matrix of B values:
B = [2;4;6;8;10; 3;5;7;9;11; 4;6;8;10;12; 5;7;9;11;13]
I am attempting to produce a generalised code to place each repetition into a separate column and store it into Aa and Bb, e.g.:
Aa = [0 0 0 0 Bb = [2 3 4 5
1 1 1 1 4 5 6 7
2 2 2 2 6 7 8 9
3 3 3 3 8 9 10 11
4 4 4 4] 10 11 12 13]
Essentially, each repetition from A and B needs to be copied into the next column and then deleted from the first column
So far I have managed to identify how many repetitions there are and copy the entire column over to the next column and then the next for the amount of repetitions there are but my method doesn't shift the matrix rows to columns as such.
clc;clf;close all
A = [0;1;2;3;4;0;1;2;3;4;0;1;2;3;4;0;1;2;3;4];
B = [2;4;6;8;10;3;5;7;9;11;4;6;8;10;12;5;7;9;11;13];
desiredCol = 1; %next column to go to
destinationCol = 0; %column to start on
n = length(A);
for i = 2:1:n-1
if A == 0;
A = [ A(:, 1:destinationCol)...
A(:, desiredCol+1:destinationCol)...
A(:, desiredCol)...
A(:, destinationCol+1:end) ];
end
end
A = [...] retrieved from Move a set of N-rows to another column in MATLAB
Any hints would be much appreciated. If you need further explanation, let me know!
Thanks!
Given our discussion in the comments, all you need is to use reshape which converts a matrix of known dimensions into an output matrix with specified dimensions provided that the number of elements match. You wish to transform a vector which has a set amount of repeating patterns into a matrix where each column has one of these repeating instances. reshape creates a matrix in column-major order where values are sampled column-wise and the matrix is populated this way. This is perfect for your situation.
Assuming that you already know how many "repeats" you're expecting, we call this An, you simply need to reshape your vector so that it has T = n / An rows where n is the length of the vector. Something like this will work.
n = numel(A); T = n / An;
Aa = reshape(A, T, []);
Bb = reshape(B, T, []);
The third parameter has empty braces and this tells MATLAB to infer how many columns there will be given that there are T rows. Technically, this would simply be An columns but it's nice to show you how flexible MATLAB can be.
If you say you already know the repeated subvector, and the number of times it repeats then it is relatively straight forward:
First make your new A matrix with the repmat function.
Then remap your B vector to the same size as you new A matrix
% Given that you already have the repeated subvector Asub, and the number
% of times it repeats; An:
Asub = [0;1;2;3;4];
An = 4;
lengthAsub = length(Asub);
Anew = repmat(Asub, [1,An]);
% If you can assume that the number of elements in B is equal to the number
% of elements in A:
numberColumns = size(Anew, 2);
newB = zeros(size(Anew));
for i = 1:numberColumns
indexStart = (i-1) * lengthAsub + 1;
indexEnd = indexStart + An;
newB(:,i) = B(indexStart:indexEnd);
end
If you don't know what is in your original A vector, but you do know it is repetitive, if you assume that the pattern has no repeats you can use the find function to find when the first element is repeated:
lengthAsub = find(A(2:end) == A(1), 1);
Asub = A(1:lengthAsub);
An = length(A) / lengthAsub
Hopefully this fits in with your data: the only reason it would not is if your subvector within A is a pattern which does not have unique numbers, such as:
A = [0;1;2;3;2;1;0; 0;1;2;3;2;1;0; 0;1;2;3;2;1;0; 0;1;2;3;2;1;0;]
It is worth noting that from the above intuitively you would have lengthAsub = find(A(2:end) == A(1), 1) - 1;, But this is not necessary because you are already effectively taking the one off by only looking in the matrix A(2:end).

Get even/odd indices of a matrix - MATLAB

I have following problem:
I have a given matrix of let's say 4x4.
How can I get the indices of the following combinations:
row odd and column odd
row odd and column even
row even and column odd
row even and column even
For example if I have the matrix:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
'row odd and column odd' would be the indices of 1, 3, 9, 11...
'row odd and column even' would be the indices of 2, 4, 10, 12...
'row even and column odd' would be the indices of 5, 7, 13, 15...
and 'row even and column even' would be indices of 6, 8, 14, 16...
Also, is it possible to combine those operations so e.g. I get the indices for 'row odd and column odd' and 'row even and column even'?
Thank you!
It's pretty easy to do with indexing:
Odd rows and odd columns
B = A(1:2:end, 1:2:end);
Odd rows and even columns
B = A(1:2:end, 2:2:end);
Even rows and odd columns
B = A(2:2:end, 1:2:end);
Even rows and even columns
B = A(2:2:end, 2:2:end);
The above assumes that you want the actual matrix values themselves. It's a bit confusing as your matrix elements are the same as linear indexing values themselves. If you want to determine the actual column major indices to access the matrix, you can generate a vector from 1 to N where N is the total number of elements in your matrix, then reshape this matrix into the desired size that you want. After, use the same logic above to get the actual linear indices:
N = numel(A);
B = reshape(1:N, size(A,1), size(A,2));
ind = B(1:2:end, 1:2:end); %// For odd rows, odd columns
%// Repeat for the other ones...
Now, given your comment, you want to create a new matrix that will store only these extracted matrix values while making all of the other elements zero. If you want to do this, simply pre-allocate a matrix of zeroes, then copy over those values to extract using the computed indices into the new matrix. In other words:
N = numel(A);
B = reshape(1:N, size(A,1), size(A,2));
ind = B(1:2:end, 1:2:end); %// For odd rows, odd columns - Change to suit your tastes
out = zeros(size(A));
out(ind(:)) = A(ind(:));
If you want to combine the indices like having odd row - odd column, and even row - even column, just compute two sets of indices, concatenate them into a single vector and do the same syntax like before. Therefore:
N = numel(A);
B = reshape(1:N, size(A,1), size(A,2));
ind = B(1:2:end, 1:2:end); %// For odd rows, odd columns
ind2 = B(2:2:end, 2:2:end); %// For even rows, even columns
ind = [ind(:); ind2(:)];
out = zeros(size(A));
out(ind) = A(ind);
Code
N = size(A,1); %// Get size of input matrix A
case1_ind = bsxfun(#plus,[1:2:N]',(0:N/2-1)*2*N)
case2_ind = case1_ind + N
case3_ind = case1_ind + 1
case4_ind = case3_ind + N
Note: These outputs are indices. So, to get the actual outputs, use these as indices.
To combine indices for case 1 and case 4, just concatenate -
case14comb_ind = [case1_ind ; case4_ind]
Edit :
%// To copy onto some other matrix of the same size as A, do this for case 1
new_matrix = zeros(size(A))
new_matrix(case1_ind(:)) = A(case1_ind(:))
Repeat this for the other cases too.

Matlab: Extracting Nth element of a matrix, while maintaining the original order of matrix

I am attempting to set up some code to extract certain elements of a matrix, and keeping only these values in another matrix, in the order they were extracted.
Example: If I have a random 1X20 matrix, but want only every Nth = 5th element beginning with 4 and 5, I would want it to construct a new matrix (1x8) consisting only of 4, 5, 9, 10, 14, 15, 19, 20.
What I have so far is:
r = rand(1,20);
n = 5;
a = r(4 : n : end);
b = r(5 : n : end);
So instead of two separate matrices, I instead want one matrix in its original chronological order (again, a 1x8 matrix consisting of the elements in the order of 4,5,9,10,14,15,19,20). Essentially, I'd like to be able to do this for any number of values while still maintaining the original order the elements were in.
Create all the indices to index into r separately for indices starting with 4 and 5 and then sort them to keep the order of elements as it was originally in r.
So, this should work -
ab = r(sort([4:n:numel(r) 5:n:numel(r)]))
A more generic solution for a variable number of starting values:
% example
A = 1:20;
% starting values and number of values to skip
a = [4,5];
n = 5;
% index vector
idx = bsxfun(#plus,a',(0:numel(A)/n-1)*n)
% indexing
result = A(idx(:))
returns:
idx(:)' = 4 5 9 10 14 15 19 20
Another example:
A = 1:40;
a = [3,4,7];
n = 10;
idx = bsxfun(#plus,a',(0:numel(A)/n-1)*n)
returns:
idx(:)' = 3 4 7 13 14 17 23 24 27 33 34 37
You can do it using ndgrid (this idea is taken from the code of kron, which does more or less what you want but with products instead of sums):
a = [4 5]; %// initial values
M = 20; %// maximum value
s = 5; %// step
[ii jj] = ndgrid(a,0:s:M-max(a));
ind = (ii(:)+jj(:)).';