4

I want to assign a value to some segments of an array. I've got indexes of the segments as tuples (start_idx, end_idx). Segments may overlay or be sub-segments of each other.

a = np.zeros(12)
segments = np.array([(0, 3), (1, 2), (6, 8), (8, 10)])
a[segments] = 1

The results is:

a
>> array([1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0])

How can I mask all segments to get this output:

a
>> array([1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0])
5
  • Are you sure the desired output is correct? It seems like the [3] element is wrong?! Shouldn't it be 0? Commented Aug 21, 2017 at 21:20
  • @MSeifert It seems its inclusive of the segment ends. Commented Aug 21, 2017 at 21:21
  • @Divakar But how should 10 be handled then? Normally it would be an IndexError at least for a = np.zeros(10). Commented Aug 21, 2017 at 21:23
  • 1
    @MSeifert Guessing that's a typo : a = np.zeros(12) as the final output seems to have 12 elems. Commented Aug 21, 2017 at 21:24
  • @Divakar Ah, that's a possibility as well. But seems like the answers exclude the end point - at least the accepted one. So I thought the desired output may be wrong (but wrong input would make sense too). Commented Aug 21, 2017 at 21:28

4 Answers 4

2

Here's one vectorized approach with the idea being borrowed from this post -

def segment_arr(segments, L): # L being length of output array
    s = np.zeros(L,dtype=int)
    stop = segments[:,1]+1
    np.add.at(s,segments[:,0],1)
    np.add.at(s,stop[stop<len(s)],-1)
    return (s.cumsum()>0).astype(int)

Sample run -

In [298]: segments = np.array([(0, 3), (1, 2), (6, 8), (8, 10)])

In [299]: segment_arr(segments, L=12)
Out[299]: array([1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0])
Sign up to request clarification or add additional context in comments.

1 Comment

At least one solution that actually produces the "given expected output". :)
1

One option is to simply loop through the segments, and convert ranges to actual index:

a = np.zeros(10)
segments = np.array([(0, 3), (1, 2), (6, 8), (8, 10)])

a[[i for s in segments for i in range(*s)]] = 1    
a
# array([ 1.,  1.,  1.,  0.,  0.,  0.,  1.,  1.,  1.,  1.])

Comments

1

Try this:

a = np.zeros(10)
segments = np.array([(0, 3), (1, 2), (6, 8), (8, 10)])
a[range(3)+range(1,2)+range(6,8)+range(8,10)] = 1
print (a)

3 Comments

How can I do that without assigning them manually? I can create ranges in a list generator, but how to feed them?
Well in that case you will have to Loop through
Note that this throws a TypeError: unsupported operand type(s) for +: 'range' and 'range' on python-3.x
1

Just to mention the trivial solution: Use a for-loop over the segments and assign to the slices:

import numpy as np
a = np.zeros(12)
segments = np.array([(0, 3), (1, 2), (6, 8), (8, 10)])

for seg in segments.tolist():  # the "tolist" is just an optimization here, you *could* omit it.
    a[seg[0]: seg[1]+1] = 1    # or just "seq[1]" if you want to exclude the end point
print(a)
# array([ 1.,  1.,  1.,  1.,  0.,  0.,  1.,  1.,  1.,  1.,  1.,  0.])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.