admin管理员组

文章数量:1417691

Given an array that looks like this:

values [0,  0,  1,  2,  3,  4,  5,  0,  1,  2,  3,  4,  5,  6,  0,  0,  1,  2,  3]  
index   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18

If I search for index 3, I want to get the indexes of the start and end indexes for that counter, before it is reset again, which is 2 - 6.

And for index 10, I want to get 8 - 13. And for index 16, I want to get 16 - 18.

How can I achieve this in numpy?

Given an array that looks like this:

values [0,  0,  1,  2,  3,  4,  5,  0,  1,  2,  3,  4,  5,  6,  0,  0,  1,  2,  3]  
index   0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18

If I search for index 3, I want to get the indexes of the start and end indexes for that counter, before it is reset again, which is 2 - 6.

And for index 10, I want to get 8 - 13. And for index 16, I want to get 16 - 18.

How can I achieve this in numpy?

Share Improve this question edited Jan 31 at 9:57 mkrieger1 23.6k7 gold badges64 silver badges82 bronze badges asked Jan 31 at 9:40 Andrei M.Andrei M. 4133 silver badges10 bronze badges 2
  • 2 I don't think I follow what the rule here is. Can you explain it in more detail? – alex Commented Jan 31 at 9:53
  • 2 @alex a "counter" starts with a 1 value, and goes until the next 0 value occurs (or the value range ends.) So from the given start index position #3 with value 2, they want to "look back" until they find the value 1 at index position #2, and look forward until they find the last non-zero number 5 at index position #6. – C3roe Commented Jan 31 at 10:02
Add a comment  | 

4 Answers 4

Reset to default 4

For example, if you care about index==10, you can try

grp = np.cumsum(np.append(1,np.diff(values)<0))
np.argwhere(grp ==grp[index==10])[1:].T

which gives

array([[ 8,  9, 10, 11, 12, 13]])

Data

values = np.array([0,  0,  1,  2,  3,  4,  5,  0,  1,  2,  3,  4,  5,  6,  0,  0,  1,  2,  3])
index = np.arange(values.size)

You can get the start/end coordinates of the non-null stretches with something like:

idx = np.nonzero(values == 0)[0]
start = idx+1
end = np.r_[idx[1:]-1, len(values)-1]
m = start<end
indices = np.c_[start, end][m]

indices:

array([[ 2,  6],
       [ 8, 13],
       [16, 18]])

Then get the position with searchsorted (assuming you only pass non-zeros indices, else you need an additional check (e.g. is values[position] != 0) and explanation of what should be the output):

indices[np.searchsorted(indices[:, 1],  2)] # [ 2,  6]
indices[np.searchsorted(indices[:, 1], 10)] # [ 8, 13]
indices[np.searchsorted(indices[:, 1], 16)] # [16, 18]

And you can get multiple targets at once:

target = [2, 6, 10, 16]
indices[np.searchsorted(indices[:, 1], target)]

array([[ 2,  6],
       [ 2,  6],
       [ 8, 13],
       [16, 18]])

And if you have indices of zero-values you could mask them in the output:

target = [1, 2, 6, 7, 10, 16]

out = np.ma.masked_array(indices[np.searchsorted(indices[:, 1], target)],
                         np.broadcast_to(values[target, None]==0, (len(target), 2))
                        )

[[-- --]
 [ 2  6]
 [ 2  6]
 [-- --]
 [ 8 13]
 [16 18]]

Used input:

values = np.array([0,  0,  1,  2,  3,  4,  5,  0,  1,  2,  3,  4,  5,  6,  0,  0,  1,  2,  3])
import numpy as np

arr = np.array([0, 0, 1, 2, 3, 4,5, 0, 1, 2, 3, 4, 5, 6, 0, 0,1, 2, 3])
resets = np.where(arr == 0)[0]
# Create an array of boundaries
boundaries = np.concatenate(([ -1 ], resets, [ len(arr) ]))

def get_run_bounds(arr, boundaries, i):
    if arr[i] == 0:
        return None
    
    pos= np.searchsorted(boundaries, i, side='right')
    start = boundaries[pos- 1] + 1
    end = boundaries[pos] - 1
    
    return (start, end)

print("Index  3→",get_run_bounds(arr, boundaries,  3))  # waiting for(2, 6)
print("Index 10 →", get_run_bounds(arr, boundaries, 10)) # (8, 13)
print("Index 16 →", get_run_bounds(arr, boundaries, 16))# (16, 18)
import numpy as np

values = np.array([0, 1, 2, 3, 4, 5, 0, 7, 8, 9, 10, 11, 12, 0, 0, 15, 16, 17])

m = values == 0 

idx = np.where(m)[0]

aa = np.where(m, np.arange(len(values)), -1)
print(aa)
#[ 0 -1 -1 -1 -1 -1  6 -1 -1 -1 -1 -1 -1 13 14 -1 -1 -1]

startIdx = np.maximum.accumulate(aa, -1) +1
print(startIdx)
'''
[ 1  1  1  1  1  1  7  7  7  7  7  7  7 14 15 15 15 15]
'''

bb = np.where(m[::-1],
        np.arange(len(values))[::-1], len(values)     
              )

print(bb)
'''
[18 18 18 14 13 18 18 18 18 18 18  6 18 18 18 18 18  0]
'''

endIdx = np.minimum.accumulate(bb)[::-1] -1
print(endIdx)
'''
[-1  5  5  5  5  5  5 12 12 12 12 12 12 12 13 17 17 17]
'''

def getRange(idx):
    if values[idx] == 0 : return None
    aa = int(startIdx[idx])
    bb = int(endIdx[idx])
    return (aa,bb)

print(getRange(3))   # Output: (1, 5)
print(getRange(10))  # Output: (7, 12)
print(getRange(16))  # Output: (15, 17)

本文标签: pythonIn an array of counters that resetfind the startend index for counterStack Overflow