Creating a loop in MATLAB to find means - matlab

So I have 2 matrices in MATLAB. If one of them is a 100 X 2 matrix, like this:
[a b]
[13 19]
[21 39]
[35 45]
ect. ect.
and the other matrix is a N X 1 matrix with values like this:
[1]
[3]
[5]
[7]
ect. ect.
What I'm trying to do is find the Mean value of all the elements from 'a' to 'b' of the 2nd matrix.
What I've got so far is this:
(If my first matrix is called: MATRIX1
second matrix is called: MATRIX2)
a= MATRIX1(1:1)
b= MATRIX1(1:2)
values = MATRIX2(a:b)
mean(values)
this gives me exactly what I want, the mean of the values from a to b.
But how do I create a loop so that I can do this automatically for all the rows in MATRIX 1?
Thanks!
Update:
I figured out how to get a loop, but now I'm not sure how to take all my values and make it into a 100 X 1 matrix. This is the code I used:
c= size(MATRIX1,1);
for k= 1:c;
a= MATRIX1(k,1);
b= MATRIX1(k,2);
values= MATRIX2(a:b);
d= mean(values)
end
with this, I get 100 values of d. How do I put these values into a 100 X 1 matrix?

Here's how to do this with a for loop:
nRows = size(MATRIX1,1);
meanValues = zeros(nRows,1);
for row = 1:nRows
meanValues(row) = mean(MATRIX2(MATRIX1(row,1):MATRIX1(row,2)));
end
Another way to do this is to use the function ARRAYFUN like so:
meanValues = arrayfun(#(a,b) mean(MATRIX2(a:b)),MATRIX1(:,1),MATRIX1(:,2));

Looks like I'm already beaten, but just for the sake of variety, another option using cellfun is:
cellfun(#(pair) mean(x(pair(1):pair(2))), num2cell(inds, 2))

You are almost there!
elems = 100
values = zeros(1, elems)
for row = 1:elems
a= MATRIX1(1:1)
b= MATRIX1(1:2)
values(row) = MATRIX2(a:b)
end
mean(values)

just for clarification you want something that takes the "a"th element in matrix 2 to the "b"th element and averages all of those values?
This should work:
[r c] = size(MATRIX1);
myMeans = zeros(r,1);
for i = 1:r
myMeans(i) = mean(MATRIX2(MATRIX1(i,1):MATRIX1(i,2)))
end
this will store all of the means for the rows in myMeans

Related

Assigning values to a matrix through vector addition from an adjacency matrix

Very new to Matlab, I usually use STATA.
I want to use the nchoosek fuction to get the sum of vectors in one matrix.
I have a 21x21 adjacency matrix, with either 0 or 1 as the inputs. I want to create a new matrix, that will give me a sum of inputs between all possible triads from the adjacency matrix.
The new matrix should look have four variables, indexes (i, j, k) - corresponding to each combination from the 21x21. And a final variable which is a sum of the inputs.
The code I have so far is:
C = nchoosek(21,3)
B = zeros(nchoosek(21,3), 4)
for i=1:C
for j=i+1:C
for k=j+1:C
B(?)=B(i, j, k, A(i)+A(j)+A(k)) #A is the 21x21 adj mat
end
end
end
I know my assignment statement is incorrect as I don't completed understand the indexing role of the ":" operator. Any help will be appreciated.
Thanks!
This might be what you want:
clear all
close all
clc
A = rand(21,21); % Replace this with actual A
rowNum = 0;
for i=1:21
for j=i+1:21
for k=j+1:21
rowNum = rowNum+1;
B(rowNum,:) = [i, j, k, sum(A(:,i)+A(:,j)+A(:,k))];
end
end
end
There are some points:
You loop for different combinations. the total number of combination is nchoosek(21,3) which you can check after 3 nested loop. Your code with for i=1:C was the first error since you're actually looping for different values of i and different values of j and k. So these just 21 values not more.
To avoid repeated combinations, it's enough to start new index after the previous one, which you've realized in your code.
There are other possible approaches such as vectorized format, but to stick to your approach, I used a counter: rowNum which is the loop counter and updated along the loop.
B(rowNum,:) means all element of rowNum'th row of the matrix B.
Below is an algorithm to find the triads in an adjacency matrix. It checks all possible triads and sums the values.
%basic adjacency matrix with two triads (1-2-5) (2-3-5)
A=[];
A(1,:) = [0 1 0 0 1];
A(2,:) = [1 0 1 0 1];
A(3,:) = [0 1 0 0 1];
A(4,:) = [0 0 0 0 1];
A(5,:) = [1 1 1 1 0];
A=A==1; %logical matrix
triads=nchoosek(1:5,3);
S=nan(size(triads,1),4);
for ct = 1:size(triads,1)
S(ct,1:3)=[A(triads(ct,1),triads(ct,2)),A(triads(ct,1),triads(ct,3)),A(triads(ct,2),triads(ct,3))];
S(ct,4)=sum(S(ct,1:3));
end
triads(find(S(:,4)==3),:)
ans =
1 2 5
2 3 5

matlab concatenating vectors

I'm new to MATLAB, and programming in general, and I am having difficulty accomplishing what I am sure is a very, very simple task:
I have a list of vectors v_i for i from 1 to n (n in some number), all of the same size k. I would like to create a vector v that is a "concatenation" (don't know if this is the correct terminology) of these vectors in increasing order: what I mean by this is that the first k entries of v are the k entries of v_1, the k+1 to 2k entries of v are the k entries of v_2 etc. etc. Thus v is a vector of length nk.
How should I create v?
To put this into context, here is function I've began writing (rpeakindex will just a vector, roughq would be the vector v I mentioned before):
function roughq = roughq(rpeakindex)
for i from 1 to size(rpeakindex) do
v_i = [rpeakindex(i)-30:1:rpeakindex(i)+90]
end
Any help is appreciated
Let's try two things.
First, for concatenating vectors there are a couple of methods here, but the simplest would be
h = horzcat(v_1, v_2);
The bigger problem is to enumerate all vectors with a "for" loop. If your v_n vectors are in a cell array, and they are in fact v{i}, then
h= [];
for j=1:n
h = horzcat(h, v{i});
end
Finally, if they only differ by name, then call them with
h=[];
for j=1:n
h= horzcat(h, eval(sprintf('v_%d',j));
end
Let the arrays (vectors) be:
v_1=1:10;
v_2=11:20;
v_3=21:30;
v_4=31:40;
and so on.
If they are few (e. g. 4), you can directly set then as input in the cat function:
v=cat(2,v_1,v_2,v_3,v_4)
or the horzcat function
v=horzcat(v_1,v_2,v_3,v_4)
otherwise you can use the eval function within a loop
v1=[];
for i=1:4
eval(['v1=[v1 v_' num2str(i) ']'])
end
Hope this helps.
Concatenating with horzcat is definitely an option, but since these vectors are being created in a function, it would be better to concatenate these vectors automatically in the function itself rather than write out horzcat(v1,v2,....vn) manually.
Given the function mentioned in the question, I would suggest something like this:
function v = roughq(rpeakindex)
v = zeros(121,length(rpeakindex)); %// create a 2D array of all zeros
for i = 1:size(rpeakindex)
v(:,i) = [rpeakindex(i)-30:1:rpeakindex(i)+90]; %// set result to ith column of v
end
v = v(:)'; %'//reshape v to be a single vector with the columns concatenated
end
Here's a simplified example of what's going on:
N = 3;
v = zeros(5,N);
for i = 1:N
v(:,i) = (1:5)*i;
end
v = v(:)';
Output:
v =
1 2 3 4 5 2 4 6 8 10 3 6 9 12 15
You may want to read up on MATLAB's colon operator to understand the v(:) syntax.
If you mean 2d matrix, you are using for holding vectors and each row hold vector v then you can simply use the reshape command in matlab like below:
V = [] ;
for i = 1:10
V(i,:) = randi (10,1 ,10) ;
end
V_reshpae = reshape (V, 1, numel(V)) ;

Search for 1-D sequence in multidimensional array in Matlab

I have an array with n dimensions, and I have a sequence along one dimension at a certain location on all other dimensions. How do I find the location of this sequence? Preferably without loops.
I use matlab. I know what dimension it should be in, but the sequence isnt necessarily there. Find and == dont work. I could make an nd find function using crosscorrelation but Im guessing this is already implemented and I just dont know what function to call.
example:
ND = rand(10,10,10,10);
V = ND(randi(10),randi(10),randi(10),:);
[I1, I2, I3] = find(ND==V);
Edit: The sequence to be found spans the entire dimension it is on, I did not mention this in my original formulation of the problem. Knedlsepp`s solution solves exactly the problem I had, but Luis' solution solves a more general problem for when the sequence doesn't necessarily span the entire dimension.
As there are multiple ways to interpret your question, I will clarify: This approach assumes a 1D sequence of size: numel(V) == size(ND, dimToSearch). So, for V = [1,2] and ND = [1,2,1,2] it is not applicable. If you want this functionality go with Luis Mendo's answer, if not this will likely be faster.
This will be a perfect opportunity to use bsxfun:
We start with some example data:
ND = rand(10,10,10,10);
V = ND(3,2,:,3);
If you don't have the vector V given in the correct dimension (in this case [1,1,10,1]) you can reshape it in the following way:
dimToSearch = 3;
Vdims = ones(1, ndims(ND));
Vdims(dimToSearch) = numel(V);
V = reshape(V, Vdims);
Now we generate a cell that will hold the indices of the matches:
I = cell(1, ndims(ND));
At this point we compute the size of ND if it were collapsed along the dimension dimToSearch (we compute dimToSearch according to V, as at this point it will have the correct dimensions):
dimToSearch = find(size(V)>1);
collapsedDims = size(ND);
collapsedDims(dimToSearch) = 1;
Finally the part where we actually look for the pattern:
[I{:}] = ind2sub(collapsedDims, find(all(bsxfun(#eq, ND, V), dimToSearch)));
This is done in the following way: bsxfun(#eq, ND, V) will implicitly repmat the array V so it has the same dimensions as ND and do an equality comparison. After this we do a check with all to see if all the entries in the dimension dimToSearch are equal. The calls to find and ind2sub will then generate the correct indices to your data.
Let d be the dimension along which to search. I'm assuming that the sought sequence V may be shorter than size(ND,d). So the sequence may appear once, more than once, or never along each dimension-d- "thread".
The following code uses num2cell to reshape ND into a cell array such that each dimension-d-thread is in a different cell. Then strfind is applied to each cell to determine matches with V, and the result is a cell array with the same dimensions as ND, but where the dimension d is a singleton. The contents of each cell tell the d-dimension-positions of the matches, if any.
Credit goes to #knedlsepp for his suggestion to use num2cell, which greatly simplified the code.
ND = cat(3, [1 2 1 2; 3 4 5 6],[2 1 0 5; 0 0 1 2] ); %// example. 2x4x2
V = 1:2; %// sought pattern. It doesn't matter if it's a row, or a column, or...
d = 2; %// dimension along which to search for pattern V
result = cellfun(#(x) strfind(x(:).', V(:).'), num2cell(ND,d), 'UniformOutput', 0);
This gives
ND(:,:,1) =
1 2 1 2
3 4 5 6
ND(:,:,2) =
2 1 0 5
0 0 1 2
V =
1 2
result{1,1,1} =
1 3 %// V appears twice (at cols 1 and 3) in 1st row, 1st slice
result{2,1,1} =
[] %// V doesn't appear in 2nd row, 1st slice
result{1,1,2} =
[] %// V appears appear in 1st row, 2nd slice
result{2,1,2} =
3 %// V appears once (at col 3) in 2nd row, 2nd slice
One not very optimal way of doing it:
dims = size(ND);
Vrep = repmat(V, [dims(1), dims(2), dims(3), 1]);
ND_V_dist = sqrt(sum(abs(ND.^2-Vrep.^2), 4));
iI = find(ND_V_dist==0);
[I1, I2, I3] = ind2sub([dims(1), dims(2), dims(3)], iI);

Group index vector from vector with nummer of elements in group

I want to create a vector containing the group identifier for each element from a vector containing the number of elements in each group.
Example:
E = [2 3 4]'
I am looking for a vector as follows:
I = [1 1 2 2 2 3 3 3 3]
I found one solution involving a loop:
I = [];
for e=1:size(E,1),
I = [I ; e*ones(E(e),1)];
end
But this doesn't seem very elegant. Any advice for improvements are welcome.
You are looking for run length decoding.
Try this
n = sum( E ); %// tot number of elelments
I = zeros( 1, n ); % //preallocate!
I(cumsum( [ 1 E(1:end-1) ] ) ) = 1;
I = cumsum( I )
See a running example at ideone.
Try this:
X = arrayfun(#(x) [1 zeros(1,x-1)], E, 'uni',0)
Y = cumsum( [X{:}] )
I had a similar problem. I think, without using a for-loop, it's not as simple as one could think.
Here is my solution:
I = cell2mat(arrayfun(#(x) repmat(x,E(x),1),1:numel(E),'UniformOutput',false)')
Some explanation:
x is the Index of E.
The array-function "iterates" from 1 to numel(E). repmat replicates the index x E(x) times.
The Output of the array-function is a 1x3-Cell array with vectors [11], [222] and [3333]. Because of the different vector sizes, I have to set the Uniformoutput to false. But I want to concatenate these nested vectors, so I use cell2mat(...)

vectorizing histogram on matrix rows in matlab

Hello I need to calculate a histogram for every row in a big matrix.
For the first row for example I get this:
AA = hist(symbolic_data(1,:), 1:8);
With symbolic_data(1,:)=[7 6 7 8 7], I get AA=[0 0 0 0 0 1 3 1].
Of course this is easy using a simple for loop, but my symbolic_data matrix is really big.
Is there a way to vectorize this.
I've been fiddling with bsxfun, but I can't make it work.
Any help would be much appreciated.
Thanks for your time.
From Matlab help:
N = hist(Y) bins the elements of Y into 10 equally spaced containers
and returns the number of elements in each container. If Y is a
matrix, hist works down the columns.
so:
AA = hist(symbolic_data', 1:8);
will do what you want
The answer by #Mercury is the way to go. But if you want to do it with bsxfun:
If you only have integer values, use
bin_centers = 1:8;
AA = squeeze(sum(bsxfun(#eq, permute(symbolic_data,[2 3 1]), bin_centers(:).')));
If the values are not necessarily integer:
bin_centers = 1:8;
AA = squeeze(sum( bsxfun(#le, permute(symbolic_data,[2 3 1]), bin_centers(:).'+.5) &...
bsxfun(#gt, permute(symbolic_data,[2 3 1]), bin_centers(:).'-.5) ));