Find indices where array changes - matlab

I have an array something like this:
[0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 0 0 0 1 1 ... ]
I want to find the indices where 0 changes to 1 and 1 changes to 0. So for the following array:
changes = [5 10 14 17 20]
I know how to use find and a vector predicate expression like find(A > 3) to search for simpler conditions, but this has me stuck. I could write a big loop and do it, but I feel there must be something built-in or otherwise easier to achieve the same thing.

A very simple approach which works with all values as start would be:
changes = find(diff(value))+1;
This will also return the expected result changes = [5 10 14 17 20].

Figured out a solution.
find(circshift(value, [0, 1]) ~= value)
For my application, the array is guaranteed to begin and end with 0s, otherwise it will not work properly.

Dennis K's solution works for your binary data. If you wish to find transitions in general, I recommend Run Length Encoding. I don't think MATLAB has a builtin, but (shameless plug), you can use seqle .

Related

matlab transform logical index to range

Couldn't find a quick answer for this, it seems super simple but I don't get it. I want do the following transformation (for this example using my imaginary function transform):
a=[0 0 0 1 0 0 0 0];
b=(-1:2); %rule to transform for every true value in [a], -1:2 should be true
transform(a,b) %should output [0 0 1 1 1 1 0 0]
a=[0 0 0 1 0 0 0 0 1 1 0 0 0]; %another example
transform(a,b) %should output [0 0 1 1 1 1 0 1 1 1 1 1 0];
Is there an quick way of doing this transform, maybe using logical operators?
edit: I tried
a(find(a)'+(-1:2))=1 %requires matlab>2016 if I'm not mistaken, otherwise replace + sign with bsxfun(#plus,...)
but I'm looking for a possible function that does this without changing a and without using find (since using find kind of defeats the purpose of using logical matrices/indexing in the first place)
If you have the Image Processing Toolbox you can use imdilate:
nh(max(abs([b(1),b(end)]))+1+b) = true;
result = imdilate(a, nh);
I found an elegant oneliner that should solve your problem:
b=(-1:2)
a(find(a) + b(:)) = 1;
Hope it helps!

Count the number of the first zero elements

I would line to find the number of the first consecutive zero elements. For example in [0 0 1 -5 3 0] we have two zero consecutive elements that appear first in the vector.
could you please suggest a way without using for loops?
V=[0 0 1 -5 3 0] ;
k=find(V);
Number_of_first_zeros=k(1)-1;
Or,
Number_of_first_zeros=find(V,1,'first')-1;
To solve #The minion comment (if that was the purpose):
Number_of_first_zeros=find(V(find(~V,1,'first'):end),1,'first')-find(~V,1,'first');
Use a logical array to find the zeros and then look at where the zeros and ones are alternating.
V=[1 2 0 0 0 3 5123];
diff(V==0)
ans =
0 1 0 0 -1 0
Create sample data
V=[1 2 0 0 0 3 5123];
Find the zeros. The result will be a logical array where 1 represents the location of the zeros
D=V==0
D =
0 0 1 1 1 0 0
Take the difference of that array. 1 would then represent the start and -1 would represent the end.
T= diff(D)
ans =
0 1 0 0 -1 0
find(T==1) would give you the start and find(T==-1) would give you the end. The first index+1 of T==1 would be the start of the first set of zeros and the first index of T==-1 would be the end of the first set of zeros.
You could find position the first nonzero element using find.
I=find(A, 1);
The number of leading zeros is then I-1.
My solution is quite complex yet it doesn't use the loops and it does the trick. I am pretty sure, that there is a more direct approach.
Just in case no one else posts a working solution here my idea.
x=[1 2 4 0 20 0 10 1 23 45];
x1=find(x==0);
if numel(x1)>1
x2=[x1(2:end), 0];
x3=x2-x1;
y=find(x3~=1);
y(1)
elseif numel(x1)==1
display(1)
else
display('No zero found')
end
x is the dataset. x1 contains the index of all zero elements. x2 contains all those indices except the first one (because matrix dimensions must agree, one zero is added. x3 is the difference between the index and the previous index of zeros in your dataset. Now I find all those differences which are not 1 (do not correspond to sequences of zeros) and the first index (of this data is the required result. The if case is needed in case you have only one or no zero at all.
I'm assuming your question is the following: for the following vector [0 0 1 -5 3 0], I would like to find the index of the first element of a pair of 0 values. Is this correct? Therefore, the desired output for your vector would be '1'?
To extend the other answers to find any such pairs, not just 0 0 (eg. 0 1, 0 2, 3 4 etc), then this might help.
% define the pattern
ptrn = [ 0 0 ];
difference = ptrn(2) - ptrn(1)
V = [0 0 1 -5 3 0 0 2 3 4 0 0 1 0 0 0]
x = diff(V) == difference
indices = find(x)
indices =
1 6 11 14 15

How to create Adjacency Matrix for dataset in Matlab?

i am a new user of matlab and need help in creating adjacency matrix from a data set.
dataset is in the following pattern
A=[
0 1
0 2
0 5
1 2
1 3
1 4
2 3
2 5
3 1
3 4
3 5
4 0
4 2
5 2
5 4
];
the adjacency matrix for above will be
M= 0 1 1 0 0 1
0 0 1 1 1 0
0 0 0 1 0 1
0 1 0 0 1 1
1 0 1 0 0 0
0 0 1 0 1 0
i need code to perform the above task in matlab
You could use sparse. Please take a look at that function, give your problem a try, and then check by hovering the mouse over the following rectangle:
full(sparse(A(:,1)+1, A(:,2)+1, 1))
Welcome to SO! Please read the following guide on how to ask good questions.
To elaborate on #Ankur's comment, please also take a look at this Open letter to students with homework problems: "...If your question is just a copy paste of homework problem, expect it to be downvoted, closed, and deleted - potentially in quite short order."
What you need to do is pretty straight-forward:
First you preallocate your M matrix, using either M=zeros(6); or M(6,6)=0; (this option assumes M does not exist).
Next thing you should note is that MATLAB uses "1-based indexing", which means that you can't use the indices in A as-is and you first need to increment them by 1.
After incrementing the indices, we see that "A+1" contains the coordinates of M that should have a 1 in them (I noticed that the adjacency matrix is asymmetric in your case). From here it's a matter of accessing the correct cells, and this can be done using sub2ind(...).
Finally, the code to generate M is:
M=zeros(6);
M(sub2ind(size(M), A(:,1)+1, A(:,2)+1))=1;
I don't understand your matrix A, but supposing that A is of the same dimensions as the sought adjacency matrix M, and that you simply want to keep all the zero entries as "0", but want to make the positive entries equal to "1", then just do:
M = (A>0)
As pointed out in a comment by #Dev-iL above, this is a "problem of how to modify values of a matrix in known positions. It doesn't really involve adjacency..."

Find specific occurrences within a vector in MATLAB, without for-loop?

I have a problem that seems to be simple but maybe I am missing something. Let us say I have: vector = [10:1:19];. I have another vector, want = [11 16 19]; I simply want a way in which a command will return for me, the indicies at which 11, 16, and 19 occur in vector. In other words, I want to have returned, 2, 7, and 10. What command might do this? I cannot use find, (because dimensions do not match), so is there another way?
In reality the length of vector and want will be long, so a for loop will not do.
Use intersect:
[C, i_vector, i_want] = intersect(vector, want)
C is the common elements in both vectors. i_vector would be the common set indices in vector and i_want is the matching set indices in want vector.
Alternatively, you can use ismember.
To get the element of vector present in want:
vector(ismember(vector,want))
ans =
11 16 19
To get their indexes:
find(ismember(vector,want))
ans =
2 7 10
or just:
[tf, loc] = ismember(vector,want)
tf =
0 1 0 0 0 0 1 0 0 1
loc =
0 1 0 0 0 0 2 0 0 3
where tf indicates for each element of vector whether it is present in want, and loc indicate the corresponding indexes in want.

Constrain values in matlab

If i have a simple array in matlab, say:
a = [0 1 2 3 4 5 6 0 0]
How do i constrain the values in that array (if for example i want the maximum value to be 1, so to get to:
a = [0 1 1 1 1 1 1 0 0]
What would be the simplest, most efficient way to do that?
a(a>1) = 1;
This would do what you're asking... you can follow the same pattern for other constraints.
Edit: commenter is correct, fixed.
a > 0
or
min(a, 1)
(Tested in Octave.)
Try:
arrayfun(#(x) min(1,x),a)
For the max value and substitute max(val,x) for the min.