Find indices of blocks of 0s that are continuous [duplicate] - arrays

This question already has answers here:
Finding islands of zeros in a sequence
(6 answers)
Closed 6 years ago.
I have a vector and I want to find the indices of blocks of 0s that are continuous for at least 3 times.
y = [1 1 1 0 1 1 0 0 0 1 1 1 0 1 0 1 0 0 1 0 0 0 0 1 1];
So in this case, the blocks should be [0 0 0] from 7-9 and [0 0 0 0] from 20-23. The output should give me the indices, something like [7, 9] and [20,23], or even better, change these blocks of 0s to a single NAN to become:
[1 1 1 0 1 1 NAN 1 1 1 0 1 0 1 0 0 1 NAN 1 1]
Thanks!

What you can do is:
Pad the vector with 1 on each side.
Use find and diff to find where the vector changes from 1 to 0 (diff = -1)
Use find and diff to find where the vector changes from 0 to 1 (diff = 1)
Find the duration of each interval by subtracting the values in 3 by the values in 2 (and add 1)
Create a logical vector with true where the duration is >= 3, and use that vector to find the start indices (from the values found in point 2).
Set the value of each of the start indices to NaN
Set the value of start indices + 1 : end indices to [].
And you're set to go!
It actually took a lot more time writing the explanation than it took to write the code. It's quite a nice exercise to learn some basic MATLAB so I'll leave it to you. Good luck!

Related

How can I create a new matrix that from the other's elements?

I want to pick out the elements which are
(2*pi*k),
where k=0,1,2,3... which means integer, and fill them (i1) into the other matrix.
But my problem is, I don't know how to make "k" be row. (By the way, dividends and divisors are float, so I need to find the approximations and see them as 2*pi*k).
My code, only can find the elements which are (2*pi*k), but can't order them like if k=1, then it will be put into k=1 row; if k=2, then the element should be put into k=2 row.
For example,
A = [2*pi 6 3 4;0.5*pi 0 2;3.1 7 4 8;2*pi 7 2 9;2.6 4*pi 6*pi 0]
I want the output to be
B = [0 2*pi 4*pi 6*pi;0 2*pi NaN NaN;NaN 2*pi NaN NaN]
This is my code:
k=0;
for m=380:650;
for n=277:600;
if abs((rem(abs(i(m,n)),(2*PI)))-(PI))>=3.11;
k=k+1;
B(m,k)=i1(m,n);
end
end
k=0;
end
It can find what I want but they seem not to be ordered the way I want.
As others, I'm a bit unsure what you want. Here's how I understood it and would code it:
check whether (2*pi*k) is contained in A, you want a numerical approach
output binary result
here's the code:
testPI=#(k) (2*pi*k); %generates 2*pi*k, where k is up to the user
A = [2*pi 6 3 4;0.5*pi 0 2 0;3.1 7 4 8;2*pi 7 2 9;2.6 4*pi 6*pi 0]; %A from example (fixed dimension error)
ismember(A,f(1:10)) %test if k=1:10 is contained in A
ans =
5×4 logical array
1 0 0 0
0 0 0 0
0 0 0 0
1 0 0 0
0 1 1 0
Adapt 1:10 to any value you'd like. Of course this only works if k is within reasonable range, otherwise this approach is suboptimal

How to see if an array is contained (in the same order) of another array in matlab?

I have an array A of 1s and 0s and want to see if the larger array of bits B contains those bits in that exact order?
Example: A= [0 1 1 0 0 0 0 1]
B= [0 1 0 0 1 1 0 0 0 0 1 0 1 0 1]
would be true as A is contained in B
Most solutions I have found only determine if a value IS contained in another matrix, this is no good here as it is already certain that both matrices will be 1s and 0s
Thanks
One (albeit unusual) option, since you're dealing with integer values, is to convert A and B to character arrays and use the contains function:
isWithin = contains(char(B), char(A));
There are some obtuse vectorized ways to to do this, but by far the easiest, and likely just as efficient, is to use a loop with a sliding window,
A = [0 1 1 0 0 0 0 1];
B = [0 1 0 0 1 1 0 0 0 0 1 0 1 0 1];
vec = 0:(numel(A)-1);
for idx = 1:(numel(B)-numel(A)-1)
if all(A==B(idx+vec))
fprintf('A is contained in B\n');
break; % exit the loop as soon as 1 match is found
end
end
Or if you want to know the location(s) in B (of potentially multiple matches) then,
A = [0 1 1 0 0 0 0 1];
B = [0 1 0 0 1 1 0 0 0 0 1 0 1 0 1];
C = false(1,numel(B)-numel(A)-1);
vec = 0:(numel(A)-1);
for idx = 1:numel(C)
C(idx) = all(A==B(idx+vec));
end
if any(C)
fprintf('A is contained in B\n');
end
In this case
>> C
C =
1×6 logical array
0 0 0 1 0 0
You can use the cross-correlation between two signals for this, as a measure of local similarity.
For achieving good results, you need to shift A and B so that you don't have the value 0 any more. Then compute the correlation between the two of them with conv (keeping in mind that the convolution is the cross-correlation with one signal flipped), and normalize with the energy of A so that you get a perfect match whenever you get the value 1:
conv(B-0.5, flip(A)-0.5, 'valid')/sum((A-0.5).^2)
In the normalization term, flipping is removed as it does not change the value.
It gives:
[0 -0.5 0.25 1 0 0 -0.25 0]
4th element is 1, so starting from index equal to 4 you get a perfect match.

How can I calculate the length of groups of consecutive ones in binary vector? [duplicate]

This question already has answers here:
How to count number of 1 and 0 in the matrix?
(1 answer)
Finding islands of zeros in a sequence
(6 answers)
Closed 7 years ago.
I have a series of binary vectors (time x 1) in which 1s represent a connection between two variables at a given point in time. The connections between the two variables are sporadic, and I would like to know how 'long' each connection between the two variables exists for.
e.g. if the vector for a given set of variables is:
[0 0 1 1 1 0 0 0 1 0 0 1 1 1 1 1 1 1 ]
Then I would like to create a new variable which contains the length of contiguous 1s in each instance. From the above example, the new variable would look like this:
[3,1,7]
As the first time that a 1 arose, it was there for 3 consecutive time points, whereas the next time it was only there for 1 time point and finally, the connection was in the data for 7 consecutive time points.
If there is a good way to solve this, I'd love some help.
Cheers
Mac
diff and cumsum give a good pair!
a = [0 0 1 1 1 0 0 0 1 0 0 1 1 1 1 1 1 1 ]
b = cumsum([a 0])
c = diff( [0 b(diff([a 0]) == -1) ] )
%// or
c = diff( [0 b(~(diff([a 0]) + 1)) ] )
c =
3 1 7

Average of dynamic row range

I have a table of rows which consist of zeros and numbers like this:
A B C D E F G H I J K L M N
0 0 0 4 3 1 0 1 0 2 0 0 0 0
0 1 0 1 4 0 0 0 0 0 1 0 0 0
9 5 7 9 10 7 2 3 6 4 4 0 1 0
I want to calculate an average of the numbers including zeros, but starting from the first nonzero value and put it into column after tables end. E.g. for the first row first value is 4, so average - 11/11; for the second - 7/13; the last one is 67/14.
How could I using excel formulas do this? Probably OFFSET with nested IF?
This still needs to be entered as an array formula (ctrl-shift-enter) but it isn't volatile:
=AVERAGE(INDEX(($A2:$O2),MATCH(TRUE,$A2:$O2<>0,0)):$O2)
or, depending on location:
=AVERAGE(INDEX(($A2:$O2);MATCH(TRUE;$A2:$O2<>0;0)):$O2)
The sum is the same no matter how many 0's you include, so all you need to worry about is what to divide it by, which you could determine using nested IFs, or take a cue from this: https://superuser.com/questions/671435/excel-formula-to-get-first-non-zero-value-in-row-and-return-column-header
Thank you, Scott Hunter, for good reference.
I solved the problem using a huge formula, and I think it's a bit awkward.
Here it is:
=AVERAGE(INDIRECT(CELL("address";INDEX(A2:O2;MATCH(TRUE;INDEX(A2:O2<>0;;);0)));TRUE):O2)

Finding or arranging all combinations of given numbers [duplicate]

This question already has answers here:
Find all combinations of a given set of numbers
(9 answers)
Closed 8 years ago.
I hope all you are doing great.
I have an interesting question, which has stuck me. Its about generating combinations in a precise order.
For example i have 4 variables(can be vary) and these 4 variables has some limit to increase for example in this case 2. so i want to generate 2d matrix in a order as:
0 0 0 0
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1 1 0 0
1 0 1 0
1 0 0 1
0 1 1 0
0 1 0 1
0 0 1 1
1 1 1 0
0 1 1 1
1 1 1 1
2 0 0 0
0 2 0 0
0 0 2 0
0 0 0 2
2 1 0 0
2 0 1 0
......
......
and so on.
the number of variables ( in this case 4 ) can be varied and also the maximum limit ( in this case 4) can be varied.
Even i have also find all possible combinations but i am not able to arrange them in this sequence.
it would be great if somebody gives an answer.
cheers!
I'm going to assume you've got n variables, each of which is allowed to range from 0 to b-1. What you want is just counting n-digit numbers in base b. For example, if n = 2 and b = 3, then the sequence you want to produce is
00
01
02
10
11
12
20
21
22
To implement this, write a loop something like the following: (warning: untested code)
def inc(v, b):
for i in range(len(v)):
v[i] = v[i] + 1
if v[i] < b:
break
v[i] = 0
def is_zero(v):
for i in range(len(v)):
if v[i] != 0:
return False
return True
v = [0, 0, 0]
b = 3
while True:
print(v)
inc(v, b)
if is_zero(v):
break
If you look carefully at how this works, you should see how to generalize it if your variables have different upper bounds.

Resources