Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find where in numpy array a zero element is preceded by at least N-1 consecutive zeros?

Given a numpy array (let it be a bit array for simplicity), how can I construct a new array of the same shape where 1 stands exactly at the positions where in the original array there was a zero, preceded by at least N-1 consecutive zeros?

For example, what is the best way to implement function nzeros having two arguments, a numpy array and the minimal required number of consecutive zeros:

import numpy as np
a = np.array([0, 0, 0, 0, 1, 0, 0, 0, 1, 1])
b = nzeros(a, 3)

Function nzeros(a, 3) should return

array([0, 0, 1, 1, 0, 0, 0, 1, 0, 0])
like image 321
Dmitry K. Avatar asked Jan 17 '19 17:01

Dmitry K.


People also ask

How do you find the first occurrence of an element of a NumPy array?

Using ndenumerate() function to find the Index of value It is usually used to find the first occurrence of the element in the given numpy array.

How do you check if there is a 0 in a NumPy array?

In numpy, we can check that whether none of the elements of given array is zero or not with the help of numpy. all() function. In this function pass an array as parameter. If any of one element of the passed array is zero then it returns False otherwise it returns True boolean value.

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

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

How do you find nonzero elements in a NumPy array?

nonzero() function is used to Compute the indices of the elements that are non-zero. It returns a tuple of arrays, one for each dimension of arr, containing the indices of the non-zero elements in that dimension. The corresponding non-zero values in the array can be obtained with arr[nonzero(arr)] .


2 Answers

Approach #1

We can use 1D convolution -

def nzeros(a, n):
    # Define kernel for 1D convolution
    k = np.ones(n,dtype=int)

    # Get sliding summations for zero matches with that kernel
    s = np.convolve(a==0,k)

    # Look for summations that are equal to n value, which will occur for
    # n consecutive 0s. Remember that we are using a "full" version of
    # convolution, so there's one-off offsetting because of the way kernel
    # slides across input data. Also, we need to create 1s at places where
    # n consective 0s end, so we would need to slice out ending elements.
    # Thus, we would end up with the following after int dtype conversion
    return (s==n).astype(int)[:-n+1]

Sample run -

In [46]: a
Out[46]: array([0, 0, 0, 0, 1, 0, 0, 0, 1, 1])

In [47]: nzeros(a,3)
Out[47]: array([0, 0, 1, 1, 0, 0, 0, 1, 0, 0])

In [48]: nzeros(a,2)
Out[48]: array([0, 1, 1, 1, 0, 0, 1, 1, 0, 0])

Approach #2

Another way to solve and this could be considered as a variant of the 1D convolution approach, would be to use erosion, because if you look at the outputs, we can simply erode the mask of 0s from the starts until n-1 places. So, we can use scipy.ndimage.morphology's binary_erosion that also allow us to specify the portion of kernel center with its origin arg, hence we will avoid any slicing. The implementation would look something like this -

from scipy.ndimage.morphology import binary_erosion

out = binary_erosion(a==0,np.ones(n),origin=(n-1)//2).astype(int)
like image 160
Divakar Avatar answered Oct 04 '22 17:10

Divakar


Using for loop:

def nzeros(a, n):
  #Create a numpy array of zeros of length equal to n
  b = np.zeros(n)

  #Create a numpy array of zeros of same length as array a
  c = np.zeros(len(a), dtype=int)

  for i in range(0,len(a) - n):
    if (b == a[i : i+n]).all():  #Check if array b is equal to slice in a
      c[i+n-1] = 1

  return c

Sample Output:

print(nzeros(a, 3))
[0 0 1 1 0 0 0 1 0 0]
like image 31
Animesh Jaipurkar Avatar answered Oct 04 '22 16:10

Animesh Jaipurkar