Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding the consecutive zeros in a numpy array

I have the following array

a = [1, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 9, 8, 7,0,10,11]

I would like to find the start and the end index of the array where the values are zeros consecutively. For the array above the output would be as follows

[3,8],[12,15],[19]

I want to achieve this as efficiently as possible.

like image 637
Shan Avatar asked Jul 22 '14 10:07

Shan


People also ask

What is the use of zeros () function in NumPy?

Python numpy. zeros() function returns a new array of given shape and type, where the element's value as 0.

Can you use LEN in NumPy array?

You can use the len() method for NumPy arrays, but NumPy also has the built-in typecode . size that you can use to calculate length. Both outputs return 8, the number of elements in the array.

What does [:] do in arrays Python?

basically used in array for slicing , understand bracket accept variable that mean value or key to display, and " : " is used to limit or slice the entire array into packets .


2 Answers

Here's a fairly compact vectorized implementation. I've changed the requirements a bit, so the return value is a bit more "numpythonic": it creates an array with shape (m, 2), where m is the number of "runs" of zeros. The first column is the index of the first 0 in each run, and the second is the index of the first nonzero element after the run. (This indexing pattern matches, for example, how slicing works and how the range function works.)

import numpy as np

def zero_runs(a):
    # Create an array that is 1 where a is 0, and pad each end with an extra 0.
    iszero = np.concatenate(([0], np.equal(a, 0).view(np.int8), [0]))
    absdiff = np.abs(np.diff(iszero))
    # Runs start and end where absdiff is 1.
    ranges = np.where(absdiff == 1)[0].reshape(-1, 2)
    return ranges

For example:

In [236]: a = [1, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 9, 8, 7, 0, 10, 11]

In [237]: runs = zero_runs(a)

In [238]: runs
Out[238]: 
array([[ 3,  9],
       [12, 16],
       [19, 20]])

With this format, it is simple to get the number of zeros in each run:

In [239]: runs[:,1] - runs[:,0]
Out[239]: array([6, 4, 1])

It's always a good idea to check the edge cases:

In [240]: zero_runs([0,1,2])
Out[240]: array([[0, 1]])

In [241]: zero_runs([1,2,0])
Out[241]: array([[2, 3]])

In [242]: zero_runs([1,2,3])
Out[242]: array([], shape=(0, 2), dtype=int64)

In [243]: zero_runs([0,0,0])
Out[243]: array([[0, 3]])
like image 83
Warren Weckesser Avatar answered Oct 12 '22 10:10

Warren Weckesser


You can use itertools to achieve your expected result.

from itertools import groupby
a= [1, 2, 3, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 9, 8, 7,0,10,11]
b = range(len(a))
for group in groupby(iter(b), lambda x: a[x]):
    if group[0]==0:
        lis=list(group[1])
        print [min(lis),max(lis)]
like image 37
rajeshv90 Avatar answered Oct 12 '22 10:10

rajeshv90