Find a sequence in time series with Matlab - matlab

I want to write a short Matlab function for finding the sequence values in a time series like this:
Ex: a = [0 0 0 1 0 0 1 1 0 1 1 1 1 0 0];
My_expected_result = 3 ;(as number 1 happens 3 time of sequences)
Thank you.

Here's a simple regexp-based solution to find the number of runs of ones:
result = numel(regexp(char(a+'0'), '1+'));
You can also use strfind, which works for numerical arrays (although that's not documented):
result = numel(strfind([0 a], [1 0]));
Or just diff:
result = sum(diff([a 0])<0);
If you have the Image Processing Toolbox, bwlabel can be used for the job too:
result = max(bwlabel(a));
or (thanks to #rahnema1 for this one):
[~, result] = bwlabel(a);

Related

How to deal with indexing involving three vectors?

I have the following three vectors:
trans_now=[1 2 4]; data2send=[1 0 0 1]; datasent=[0 0 0 0];
I want to set datasent to 1 for those nodes that are members of tran_now and whose data2send status is 1. e.g 4 is a member of trans_now and data2send(4) is 1 therefore datasent(4) should be set to 1.
I can do it using for loop and if statement as shown in the code below.
for i=1:length(trans_now)
if data2send(trans_now(i))==1
datasent(trans_now(i))=1;
end
end
However I want one liner code for this. The one liner code that I tried is
req_sent(req2send(trans_now)==1)=1;
But it doesn't work.
The output should set datasent vector to [1 0 0 1].
you could solve this in 2 ways:
1.
data_sent(trans_now) = data2send(trans_now)
the output is:
data_sent =
1 0 0 1
In this solution I assumed that all the initial values of data_sent are starting as 0 and that you need to assign it once.
2.
datasent(intersect(find(data2send == 1), trans_now)) = 1
output is:
data_sent =
1 0 0 1
In this solution no assumption is used and you assign only indices where data2send == 1 and also appear in trans_now

Extending ismember to cells

I have searched the forum and have not found enough info to help me solve this problem.
Consider the set (cell of vectors)
A = {[1],[1 2],[2],[1 2 3],[1 2 3 4],[1 3]}
I want to construct a matrix B that looks like
B = [1 1 0 1 1 1
0 1 0 1 1 0
0 1 1 1 1 0
0 0 0 1 1 0
0 0 0 0 1 0
0 0 0 1 1 1]
The matrix B specifies membership of vectors with respect to each other. That is, the first row looks at the first element in A, [1], and checks if it is a member of the other vectors, placing a 1 if it is a member and a 0 otherwise.
I can do this using two for loops: one over the elements of A, and another nested, for each element of A, that checks membership with respect to every other member of A.
I want to avoid using for loops. Is there a vectorized solution for obtaining B from A?
With cell arrays it's hard to avoid loops, or their cousin cellfun. This is how I would do it:
[ii, jj] = ndgrid(1:numel(A)); % indices of all possible pairs
result = cellfun(#(x,y) all(ismember(x,y)), A(ii), A(jj)); % see if all elements in the
% first are present in the second
Well you asked for it, so here's an almost* vectorized solution using bsxfun and permute -
lens = cellfun('length',A)
vals = [A{:}]
mask = bsxfun(#ge,lens,[1:max(vals)]')
a = nan(size(mask))
a(mask) = vals
matches = bsxfun(#eq,a,permute(a,[3,4,1,2]));
out = bsxfun(#eq,squeeze(sum(any(matches,3),1)),lens(:))
*: Almost because of the use of cellfun at the start with cellfun('length',A), but since its just getting the length of the cells there, so computationally would be negligible .
Also, please note that this approach would use a lot of memory resources, so might not be beneficial, but just respecting the requirements of a vectorized solution as much as possible!

Adding additional ones that surround other values of one in a vector in MATLAB

Given a vector of zeros and ones in MATLAB, where the zeros represent an event in time, I would like to add additional ones before and after the existing ones in order to capture additional variation.
Example: I would like to turn [0;0;1;0;0] into [0;1*;1;1*;0] where 1* are newly added ones.
Assuming A to be the input column vector -
%// Find all neighbouring indices with a window of [-1 1]
%// around the positions/indices of the existing ones
neigh_idx = bsxfun(#plus,find(A),[-1 1])
%// Select the valid indices and set them in A to be ones as well
A(neigh_idx(neigh_idx>=1 & neigh_idx<=numel(A))) = 1
Or use imdilate from Image Processing Toolbox with a vector kernel of ones of length 3 -
A = imdilate(A,[1;1;1])
You can do it convolving with [1 1 1], and setting to 1 all values greater than 0. This works for column or row vactors.
x = [0;0;1;0;0];
y = double(conv(x, [1 1 1],'same')>0)
Purely by logical indexing:
>> A = [0 1 1 0 0];
>> A([A(2:end) 0] == 1 | [0 A(1:end-1)] == 1) = 1;
>> disp(A);
A =
1 1 1 1 0
This probably merits an explanation. The fact that it's a 3 element local neighbourhood makes this easy. Essentially, take two portions of the input array:
Portion #1: A starting from the second element to the last element
Portion #2: A starting from the first element to the second-last element
We place the first portion into a new array and add 0 at the end of this array, and check to see which locations are equal to 1 in this new array. This essentially shifts the array A over to the left by 1. Whichever locations in this first portion are equal to 1, we set the corresponding locations in A to be 1. The same thing for the second portion where we are effectively shifting the array A over to the right by 1. To shift to the right by 1, we prepend a 0 at the beginning, then extract out the second portion of the array. Whichever locations in this second portion are equal to 1 are also set to 1.
At the end of this operation, you would essentially shift A to the left by 1 and save this as a separate array. Also, you would shift to the right by 1 and save this as another array. With these two, you simply overlap on top of the original to obtain the final result.
The benefit of this method over its predecessors in this post is that this doesn't require computations of any kind (bsxfun, conv, imdilate etc.) and purely relies on indexing into arrays and using logical operators1. This also handles boundary conditions and can work on either row or column vectors.
Some more examples with boundary cases
>> A = [0 0 1 1 0];
>> A([A(2:end) 0] == 1 | [0 A(1:end-1)] == 1) = 1
A =
0 1 1 1 1
>> A = [0 0 0 0 1];
>> A([A(2:end) 0] == 1 | [0 A(1:end-1)] == 1) = 1
A =
0 0 0 1 1
>> A = [1 0 1 0 1];
>> A([A(2:end) 0] == 1 | [0 A(1:end-1)] == 1) = 1
A =
1 1 1 1 1
1: This post is dedicated to Troy Haskin, one who believes that almost any question (including this one) can be answered by logical indexing.

Two FOR statements coupled into one

Is is possible to put two for statements into one statement. Something like
A = [ 0 0 0 5
0 2 0 0
1 3 0 0
0 0 4 0];
a=size(A);
b=size(A);
ind=0;
c=0;
for ({i=1:a},{j=1:b})
end
Your question is very broad, but one thing to consider is that in MATLAB you can often take advantage of linear indexing (instead of subscripting), without actually having to reshape the array. For example,
>> A = [ 0 0 0 5
0 2 0 0
1 3 0 0
0 0 4 0];
>> A(3,2)
ans =
3
>> A(7) % A(3+(2-1)*size(A,1))
ans =
3
You can often use this to your advantage in a for loop over all the elements:
for ii=1:numel(A),
A(ii) = A(ii) + 1; % or something more useful
end
Is the same as:
for ii=1:size(A,2),
for jj=1:size(A,1),
A(jj,ii) = A(jj,ii) + 1;
end
end
But to address your specific goal in this problem, as you stated in the comments ("I am storing the non zero elements in another matrix; with elements like the index number, value, row number and column number."), of making sparse matrix representation, it comes to this:
>> [i,j,s] = find(A);
>> [m,n] = size(A);
>> S = sparse(i,j,s,m,n)
S =
(3,1) 1
(2,2) 2
(3,2) 3
(4,3) 4
(1,4) 5
But that's not really relevant to the broader question.
Actually you can combine multiple loops into one for, however it would require you to loop over a vector containing all elements rather than the individual elements.
Here is a way to do it:
iRange = 1:2;
jRange = 1:3;
[iL jL] = ndgrid(iRange,jRange);
ijRange = [iL(:) jL(:)]';
for ij = ijRange
i = ij(1); j = ij(2);
end
Note that looping over the variables may be simpler, but perhaps this method has some advantages as well.
No
read this http://www.mathworks.com/help/matlab/matlab_prog/loop-control-statements.html
i also don't see any added value even if it was possible
No I don't think you can put two for loops in one line.
Depends on your operation, you may be able to reshape it and use one for loop. If you are doing something as simple as just printing out all elements,
B = reshape(A,a*b,1);
for i=1:a*b
c = B(i);
...
end

I Need help Numeric Comparison in matlab

I have one matrix called targets (1X4000); column 1 to 2000 contains double value 0 and column 2001 to 4000 contains double value 1
a)
i want to create a matrix called targets_1 where i want to check if the value is 0 then make the entry 1 so at the end of the day i must have a matrix with :column 1 to 2000 with value 1 and column 2001:4000 with value zero
b)
Same situation as above but this time i want to check if the value is 1 then make the entry 1 and if it is zero then make the entry zero; at the end; my new matrix targets_2 contains values: column 1 to 2000 with value zero and column 2001:4000 with value 1
i know how to use the strcmp function to make such checking with strings, but problem is that my original matrix is double and i dont know if there is such function like
setosaCmp = strcmp('setosa',species);
which could work with double (numbers); any help would be appreciated
Your question isn't very clear. It sounds like the following would satisfy your description:
targets_1 = 1 - targets;
targets_2 = targets;
targets1 = double(targets == 0);
targets2 = targets;
I'm basing this answer purely on the fact that you've mentioned setosaCmp = strcmp('setosa', species);. From this I'm guessing that
You have Statistics Toolbox, as setosa is a species of iris from the Fisher Iris dataset widely used in Statistics Toolbox demos, and
You have a variable containing class labels, and you'd like to construct some class indicator variables (i.e. a new variable for each class label, each of which is 1 when the item is in that class, and 0 when it's not).
Is that right? If not, please ignore me.
If I'm right, then I think the command you're looking for is dummyvar from Statistics Toolbox. Try this:
>> classLabels = [1, 2, 1, 2, 3, 1, 3];
>> dummyvar(classLabels)
ans =
1 0 0
0 1 0
1 0 0
0 1 0
0 0 1
1 0 0
0 0 1