22

What i need is a way to get "fancy indexing" (y = x[[0, 5, 21]]) to return a view instead of a copy.

I have an array, but i want to be able to work with a subset of this array (specified by a list of indices) in such a way that the changes in this subset is also put into the right places in the large array. If i just want to do something with the first 10 elements, i can just use regular slicing y = x[0:10]. That works great, because regular slicing returns a view. The problem is if i don't want 0:10, but an arbitrary set of indices.

Is there a way to do this?

4 Answers 4

16

I don't think there is a way around this. My understanding is that 'fancy indexing' will always return a copy. The best solution I can think of is to manipulate y and then use the same fancy indexes to change the values of x afterwards:

ii = [0, 5, 21]
y = x[ii]
<manipulate y>
x[ii] = y
Sign up to request clarification or add additional context in comments.

3 Comments

You beat me to it. The only thing I was going to add was this: projects.scipy.org/numpy/ticket/224 Indicated that this is not likely to change.
Oh if this kind of assignment to indexed array (x[ii] = y) works then that does what i need i guess.
@Eskil That is because x[ii] = y invokes x.__setitem__(ii, y) so there is no copying involved although you used an index array. It is true that x[ii] returns a copy but this invokes x.__getitem__(ii) and is a different story.
2

You can just do:

y = x[[0,1,4]]
func(y)
x[[0,1,4]] = y

I don't think you can get views with fancy indexing. You might not want to, as I think fancy indexing is pretty slow, it should be faster to just copy the data once.

Comments

2

Here is a possible way to simulate having a view (some syntactic sugar), avoiding the explicit copy statements at the end by using a 'fancy view context'. You'll need to take care that your code doesn't modify the index array within the context

import contextlib

@contextlib.contextmanager
def fancy_index_view(arr, inds):
    # create copy from fancy inds
    arr_copy = arr[inds]

    # yield 'view' (copy)
    yield arr_copy

    # after context, save modified data
    arr[inds] = arr_copy

now, the snippet

import numpy as np
foo = np.random.random((22,2))
row_inds = [0,5,21]
barview = foo[row_inds]
barview[::] = 1
foo[row_inds] = barview

could be replaced by

import numpy as np
foo = np.random.random((22,2))
row_inds = [0,5,21]
with fancy_index_view(foo, row_inds) as barview:
    barview[::] = 1

Comments

0

You could theoretically create an object that performs the role of a 'fancy view' into another array, and I can think of plenty of use cases for it. The problem is, that such an object would not be compatible with the standard numpy machinery. All compiled numpy C code relies on data being accessible as an inner product of strides and indices. Generalizing this code to fundamentally different data layout formats would be a gargantuan undertaking. For a project that is trying to take on a challenge along these lines, check out continuum's Blaze.

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.