Let's say we have a 1d numpy array filled with some int
values. And let's say that some of them are 0
.
Is there any way, using numpy
array's power, to fill all the 0
values with the last non-zero values found?
for example:
arr = np.array([1, 0, 0, 2, 0, 4, 6, 8, 0, 0, 0, 0, 2])
fill_zeros_with_last(arr)
print arr
[1 1 1 2 2 4 6 8 8 8 8 8 2]
A way to do it would be with this function:
def fill_zeros_with_last(arr):
last_val = None # I don't really care about the initial value
for i in range(arr.size):
if arr[i]:
last_val = arr[i]
elif last_val is not None:
arr[i] = last_val
However, this is using a raw python for
loop instead of taking advantage of the numpy
and scipy
power.
If we knew that a reasonably small number of consecutive zeros are possible, we could use something based on numpy.roll
. The problem is that the number of consecutive zeros is potentially large...
Any ideas? or should we go straight to Cython
?
I would say long ago I found a question in stackoverflow asking something like this or very similar. I wasn't able to find it. :-(
Maybe I missed the right search terms, sorry for the duplicate then. Maybe it was just my imagination...
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)] .
The zeros() function is used to get a new array of given shape and type, filled with zeros. Shape of the new array, e.g., (2, 3) or 2. The desired data-type for the array, e.g., numpy. int8.
Explanation. In line 1, we import the numpy package. In line 4, we create an array and specify the number of elements to be 10 , ranging from 1 to 10. In line 7, we use the logical_and() method and specify two conditions to extract the elements, which are greater than or equal to 7 and less than 11.
Python numpy. zeros() function returns a new array of given shape and type, where the element's value as 0.
Here's a solution using np.maximum.accumulate
:
def fill_zeros_with_last(arr):
prev = np.arange(len(arr))
prev[arr == 0] = 0
prev = np.maximum.accumulate(prev)
return arr[prev]
We construct an array prev
which has the same length as arr
, and such that prev[i]
is the index of the last non-zero entry before the i-th entry of arr
. For example, if:
>>> arr = np.array([1, 0, 0, 2, 0, 4, 6, 8, 0, 0, 0, 0, 2])
Then prev
looks like:
array([ 0, 0, 0, 3, 3, 5, 6, 7, 7, 7, 7, 7, 12])
Then we just index into arr
with prev
and we obtain our result. A test:
>>> arr = np.array([1, 0, 0, 2, 0, 4, 6, 8, 0, 0, 0, 0, 2])
>>> fill_zeros_with_last(arr)
array([1, 1, 1, 2, 2, 4, 6, 8, 8, 8, 8, 8, 2])
Note: Be careful to understand what this does when the first entry of your array is zero:
>>> fill_zeros_with_last(np.array([0,0,1,0,0]))
array([0, 0, 1, 1, 1])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With