我能否在指定的索引处查看numpy数组?(使用“花式索引”创建视图)

21
我需要的是一种方法来获取“fancy indexing”(y = x [[0,5,21]])的视图而不是副本。
我有一个数组,但我想能够使用该数组的子集(由索引列表指定),以便在该子集中进行更改也可以正确地放置在大数组中的相应位置。 如果我只想对前10个元素做些什么,我可以使用常规切片y = x [0:10]。那很好用,因为常规切片返回视图。问题是,如果我不想要0:10,而是任意一组索引,是否有一种方法可以做到这一点?
4个回答

16

我认为这是无法避免的。 我的理解是,“高级索引”始终会返回副本。 我能想到的最好的解决方案是操纵 y,然后使用相同的高级索引来更改 x 的值:

ii = [0, 5, 21]
y = x[ii]
<manipulate y>
x[ii] = y

4
你比我先做到了。我要补充的唯一一件事是这个链接:http://projects.scipy.org/numpy/ticket/224。这表明这很可能不会改变。 - Paul
1
哦,如果这种对索引数组的赋值(x[ii] = y)有效,则我想那就是我需要的了。 - Eskil
@Eskil,这是因为x[ii] = y调用了x.__setitem__(ii, y),所以没有涉及到复制,尽管你使用了一个索引数组。的确,x[ii]返回一个副本,但这会调用x.__getitem__(ii),这是另一回事。 - a_guest

2
您可以直接这样操作:
y = x[[0,1,4]]
func(y)
x[[0,1,4]] = y

我认为你不能通过花哨的索引获取视图。也许你不想要这样做,因为我认为花哨的索引速度很慢,复制数据一次应该更快。


2
这里有一种可能的模拟视图(一些语法糖)的方法,通过使用“高级视图上下文”来避免在结尾处使用显式复制语句。您需要注意,在上下文中不要修改索引数组。
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

现在,这段代码片段
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

可以被替换为

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

0
你可以理论上创建一个对象,扮演着“花哨视图”的角色,进入另一个数组中,我可以想到很多用例。问题是,这样的对象将与标准numpy机器不兼容。所有编译的numpy C代码都依赖于数据作为步幅和索引的内积可访问。将此代码推广到基本不同的数据布局格式将是一项巨大的任务。对于一个试图挑战这些方面的项目,请查看continuum的Blaze。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接