简体   繁体   中英

find position of last element before specific value in python numpy

I have the foll. python numpy array, arr:

([1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 3L, 3L, 3L, 2L, 2L, 2L,
       2L, 2L, 2L, 1L, 1L, 1L, 1L])

I can find the first occurrence of 1 like this:

np.where(arr.squeeze() == 1)[0]

How do I find the position of the last 1 before either a 0 or 3.

Here's one approach using np.where and np.in1d -

# Get the indices of places with 0s or 3s and this 
# decides the last index where we need to look for 1s later on
last_idx = np.where(np.in1d(arr,[0,3]))[0][-1]

# Get all indices of 1s within the range of last_idx and choose the last one
out = np.where(arr[:last_idx]==1)[0][-1]

Please note that for cases where no indices are found, using something like [0][-1] would complain about having no elements, so error-checking codes are needed to be wrapped around those lines.

Sample run -

In [118]: arr
Out[118]: array([1, 1, 3, 0, 3, 2, 0, 1, 2, 1, 0, 2, 2, 3, 2])

In [119]: last_idx = np.where(np.in1d(arr,[0,3]))[0][-1]

In [120]: np.where(arr[:last_idx]==1)[0][-1]
Out[120]: 9

You can use a rolling window and search that for the values you want:

import numpy as np
arr = np.array([1L, 1L, 1L, 1L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 3L, 3L, 3L, 2L, 2L, 2L,
       2L, 2L, 2L, 1L, 1L, 1L, 1L])

def rolling_window(a, window):
    shape = a.shape[:-1] + (a.shape[-1] - window + 1, window)
    strides = a.strides + (a.strides[-1],)
    return np.lib.stride_tricks.as_strided(a, shape=shape, strides=strides)

match_1_0 = np.all(rolling_window(arr, 2) == [1, 0], axis=1)
match_1_3 = np.all(rolling_window(arr, 2) == [1, 3], axis=1)
all_matches = np.logical_or(match_1_0, match_1_3)
print(np.flatnonzero(all_matches)[-1])

Depending on your arrays, this might be good enough performance-wise. With that said, a less flexible (but simpler) solution might perform better even if it is a loop over indices that you usually want to avoid with numpy...:

for ix in xrange(len(arr) - 2, -1, -1):  # range in python3.x
    if arr[ix] == 1 and (arr[ix + 1] == 0 or arr[ix + 1] == 3):
        return ix

You might even be able to do something like which is probably a bit more flexible than the hard-coded solution above and (I would guess) still probably would out-perform the rolling window solution:

def rfind(haystack, needle):
    len_needle = len(needle)
    for ix in xrange(len(haystack) - len_needle, -1, -1):  # range in python3.x
        if (haystack[ix:ix + len_needle] == needle).all():
            return ix

Here, you'd do something like:

max(rfind(arr, np.array([1, 0])), rfind(arr, np.array([1, 3])))

And of course, with all of these answers, I haven't actually handled the case where the thing you are searching for isn't present since you didn't specify what you would want for that case...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM